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 @Override 135 public void parse( Reader source, Sink sink ) 136 throws ParseException 137 { 138 parse( source, sink, "" ); 139 } 140 141 @Override 142 public final synchronized void parse( final Reader source, final Sink sink, String reference ) 143 throws ParseException 144 { 145 init(); 146 147 List<Block> blocks; 148 final ByLineSource src = new ByLineReaderSource( source, reference ); 149 150 try 151 { 152 blocks = parse( src ); 153 } 154 catch ( final Exception e ) 155 { 156 // TODO handle column number 157 throw new ParseException( e, src.getName(), src.getLineNumber(), -1 ); 158 } 159 160 sink.head(); 161 162 final String title = getTitle( blocks, src ); 163 if ( title != null ) 164 { 165 sink.title(); 166 sink.text( title ); 167 sink.title_(); 168 } 169 170 sink.head_(); 171 sink.body(); 172 for ( Block block : blocks ) 173 { 174 block.traverse( sink ); 175 } 176 sink.body_(); 177 sink.flush(); 178 sink.close(); 179 180 setSecondParsing( false ); 181 init(); 182 } 183 184 /** 185 * Guess a title for the page. It uses the first section that it finds. 186 * If it doesn't find any section tries to get it from 187 * {@link ByLineReaderSource#getName()} 188 * 189 * @param blocks blocks to parse 190 * @param source source to parse 191 * @return a title for a page 192 * @since 1.1 193 */ 194 public final String getTitle( final List<Block> blocks, final ByLineSource source ) 195 { 196 String title = null; 197 198 for ( Block block : blocks ) 199 { 200 if ( block instanceof SectionBlock ) 201 { 202 final SectionBlock sectionBlock = (SectionBlock) block; 203 title = sectionBlock.getTitle(); 204 break; 205 } 206 } 207 208 if ( title == null ) 209 { 210 String name = source.getName(); 211 if ( name != null ) 212 { 213 name = name.trim(); 214 215 if ( name.length() != 0 ) 216 { 217 if ( name.endsWith( ".twiki" ) ) 218 { 219 title = name.substring( 0, name.length() - EXTENSION_LENGTH ); 220 } 221 else 222 { 223 title = name; 224 } 225 } 226 } 227 } 228 229 return title; 230 } 231 232 /** {@inheritDoc} */ 233 protected void init() 234 { 235 super.init(); 236 237 paraParser.setSectionParser( sectionParser ); 238 paraParser.setListParser( listParser ); 239 paraParser.setTextParser( formatTextParser ); 240 paraParser.setHrulerParser( hrulerParser ); 241 paraParser.setTableBlockParser( tableParser ); 242 paraParser.setVerbatimParser( verbatimParser ); 243 sectionParser.setParaParser( paraParser ); 244 sectionParser.setHrulerParser( hrulerParser ); 245 sectionParser.setVerbatimBlockParser( verbatimParser ); 246 listParser.setTextParser( formatTextParser ); 247 formatTextParser.setTextParser( textParser ); 248 tableParser.setTextParser( formatTextParser ); 249 250 this.parsers = new BlockParser[] { sectionParser, hrulerParser, verbatimParser, paraParser }; 251 } 252}