001package org.apache.maven.doxia.module.twiki; 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 org.apache.maven.doxia.module.twiki.parser.Block; 023import org.apache.maven.doxia.module.twiki.parser.BlockParser; 024import org.apache.maven.doxia.module.twiki.parser.FormatedTextParser; 025import org.apache.maven.doxia.module.twiki.parser.GenericListBlockParser; 026import org.apache.maven.doxia.module.twiki.parser.HRuleBlockParser; 027import org.apache.maven.doxia.module.twiki.parser.ParagraphBlockParser; 028import org.apache.maven.doxia.module.twiki.parser.SectionBlock; 029import org.apache.maven.doxia.module.twiki.parser.SectionBlockParser; 030import org.apache.maven.doxia.module.twiki.parser.TableBlockParser; 031import org.apache.maven.doxia.module.twiki.parser.TextParser; 032import org.apache.maven.doxia.module.twiki.parser.VerbatimBlockParser; 033import org.apache.maven.doxia.module.twiki.parser.XHTMLWikiWordLinkResolver; 034import org.apache.maven.doxia.parser.AbstractTextParser; 035import org.apache.maven.doxia.parser.ParseException; 036import org.apache.maven.doxia.parser.Parser; 037import org.apache.maven.doxia.sink.Sink; 038import org.apache.maven.doxia.util.ByLineReaderSource; 039import org.apache.maven.doxia.util.ByLineSource; 040import org.codehaus.plexus.component.annotations.Component; 041 042import java.io.Reader; 043import java.util.ArrayList; 044import java.util.List; 045 046/** 047 * Parse the <a href="http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules"> 048 * twiki file format</a> 049 * 050 * @author Juan F. Codagnone 051 * @version $Id$ 052 * @since 1.0 053 */ 054@Component( role = Parser.class, hint = "twiki" ) 055public class TWikiParser 056 extends AbstractTextParser 057{ 058 private static final int EXTENSION_LENGTH = 6; 059 060 /** paragraph parser. */ 061 private final ParagraphBlockParser paraParser = new ParagraphBlockParser(); 062 063 /** section parser. */ 064 private final SectionBlockParser sectionParser = new SectionBlockParser(); 065 066 /** enumeration parser. */ 067 private final GenericListBlockParser listParser = new GenericListBlockParser(); 068 069 /** Text parser. */ 070 private final FormatedTextParser formatTextParser = new FormatedTextParser(); 071 072 /** 073 * text parser. 074 * This only works for xhtml output, but there is no way 075 * of transforming a wikiWord in another context. 076 */ 077 private final TextParser textParser = new TextParser( new XHTMLWikiWordLinkResolver() ); 078 079 /** hruler parser. */ 080 private final HRuleBlockParser hrulerParser = new HRuleBlockParser(); 081 082 /** table parser. */ 083 private final TableBlockParser tableParser = new TableBlockParser(); 084 085 /** verbatim parser. */ 086 private final VerbatimBlockParser verbatimParser = new VerbatimBlockParser(); 087 088 /** list of parsers to try to apply to the toplevel */ 089 private BlockParser[] parsers; 090 091 /** 092 * Creates the TWikiParser. 093 */ 094 public TWikiParser() 095 { 096 init(); 097 } 098 099 /** 100 * <p>parse.</p> 101 * 102 * @param source source to parse. 103 * @return the blocks that represent source. 104 * @throws org.apache.maven.doxia.parser.ParseException on error. 105 */ 106 public final List<Block> parse( final ByLineSource source ) 107 throws ParseException 108 { 109 final List<Block> ret = new ArrayList<Block>(); 110 111 String line; 112 while ( ( line = source.getNextLine() ) != null ) 113 { 114 boolean accepted = false; 115 116 for ( BlockParser parser : parsers ) 117 { 118 if ( parser.accept( line ) ) 119 { 120 accepted = true; 121 ret.add( parser.visit( line, source ) ); 122 break; 123 } 124 } 125 if ( !accepted ) 126 { 127 throw new ParseException( "Line number not handle : " + source.getLineNumber() + ": " + line ); 128 } 129 } 130 131 return ret; 132 } 133 134 /** {@inheritDoc} */ 135 public final synchronized void parse( final Reader source, final Sink sink ) 136 throws ParseException 137 { 138 init(); 139 140 List<Block> blocks; 141 final ByLineSource src = new ByLineReaderSource( source ); 142 143 try 144 { 145 blocks = parse( src ); 146 } 147 catch ( final Exception e ) 148 { 149 // TODO handle column number 150 throw new ParseException( e, src.getName(), src.getLineNumber(), -1 ); 151 } 152 153 sink.head(); 154 155 final String title = getTitle( blocks, src ); 156 if ( title != null ) 157 { 158 sink.title(); 159 sink.text( title ); 160 sink.title_(); 161 } 162 163 sink.head_(); 164 sink.body(); 165 for ( Block block : blocks ) 166 { 167 block.traverse( sink ); 168 } 169 sink.body_(); 170 sink.flush(); 171 sink.close(); 172 173 setSecondParsing( false ); 174 init(); 175 } 176 177 /** 178 * Guess a title for the page. It uses the first section that it finds. 179 * If it doesn't find any section tries to get it from 180 * {@link ByLineReaderSource#getName()} 181 * 182 * @param blocks blocks to parse 183 * @param source source to parse 184 * @return a title for a page 185 * @since 1.1 186 */ 187 public final String getTitle( final List<Block> blocks, final ByLineSource source ) 188 { 189 String title = null; 190 191 for ( Block block : blocks ) 192 { 193 if ( block instanceof SectionBlock ) 194 { 195 final SectionBlock sectionBlock = (SectionBlock) block; 196 title = sectionBlock.getTitle(); 197 break; 198 } 199 } 200 201 if ( title == null ) 202 { 203 String name = source.getName(); 204 if ( name != null ) 205 { 206 name = name.trim(); 207 208 if ( name.length() != 0 ) 209 { 210 if ( name.endsWith( ".twiki" ) ) 211 { 212 title = name.substring( 0, name.length() - EXTENSION_LENGTH ); 213 } 214 else 215 { 216 title = name; 217 } 218 } 219 } 220 } 221 222 return title; 223 } 224 225 /** {@inheritDoc} */ 226 protected void init() 227 { 228 super.init(); 229 230 paraParser.setSectionParser( sectionParser ); 231 paraParser.setListParser( listParser ); 232 paraParser.setTextParser( formatTextParser ); 233 paraParser.setHrulerParser( hrulerParser ); 234 paraParser.setTableBlockParser( tableParser ); 235 paraParser.setVerbatimParser( verbatimParser ); 236 sectionParser.setParaParser( paraParser ); 237 sectionParser.setHrulerParser( hrulerParser ); 238 sectionParser.setVerbatimBlockParser( verbatimParser ); 239 listParser.setTextParser( formatTextParser ); 240 formatTextParser.setTextParser( textParser ); 241 tableParser.setTextParser( formatTextParser ); 242 243 this.parsers = new BlockParser[] { sectionParser, hrulerParser, verbatimParser, paraParser }; 244 } 245}