View Javadoc
1   package org.apache.maven.doxia.module.twiki;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import org.apache.maven.doxia.module.twiki.parser.Block;
23  import org.apache.maven.doxia.module.twiki.parser.BlockParser;
24  import org.apache.maven.doxia.module.twiki.parser.FormatedTextParser;
25  import org.apache.maven.doxia.module.twiki.parser.GenericListBlockParser;
26  import org.apache.maven.doxia.module.twiki.parser.HRuleBlockParser;
27  import org.apache.maven.doxia.module.twiki.parser.ParagraphBlockParser;
28  import org.apache.maven.doxia.module.twiki.parser.SectionBlock;
29  import org.apache.maven.doxia.module.twiki.parser.SectionBlockParser;
30  import org.apache.maven.doxia.module.twiki.parser.TableBlockParser;
31  import org.apache.maven.doxia.module.twiki.parser.TextParser;
32  import org.apache.maven.doxia.module.twiki.parser.VerbatimBlockParser;
33  import org.apache.maven.doxia.module.twiki.parser.XHTMLWikiWordLinkResolver;
34  import org.apache.maven.doxia.parser.AbstractTextParser;
35  import org.apache.maven.doxia.parser.ParseException;
36  import org.apache.maven.doxia.parser.Parser;
37  import org.apache.maven.doxia.sink.Sink;
38  import org.apache.maven.doxia.util.ByLineReaderSource;
39  import org.apache.maven.doxia.util.ByLineSource;
40  import org.codehaus.plexus.component.annotations.Component;
41  
42  import java.io.Reader;
43  import java.util.ArrayList;
44  import java.util.List;
45  
46  /**
47   * Parse the <a href="http://twiki.org/cgi-bin/view/TWiki/TextFormattingRules">
48   * twiki file format</a>
49   *
50   * @author Juan F. Codagnone
51   * @since 1.0
52   */
53  @Component( role = Parser.class, hint = "twiki" )
54  public class TWikiParser
55      extends AbstractTextParser
56  {
57      private static final int EXTENSION_LENGTH = 6;
58  
59      /** paragraph parser. */
60      private final ParagraphBlockParser paraParser = new ParagraphBlockParser();
61  
62      /** section parser. */
63      private final SectionBlockParser sectionParser = new SectionBlockParser();
64  
65      /** enumeration parser. */
66      private final GenericListBlockParser listParser = new GenericListBlockParser();
67  
68      /** Text parser. */
69      private final FormatedTextParser formatTextParser = new FormatedTextParser();
70  
71      /**
72       * text parser.
73       * This only works for xhtml output, but there is no way
74       * of transforming a wikiWord in another context.
75       */
76      private final TextParser textParser = new TextParser( new XHTMLWikiWordLinkResolver() );
77  
78      /** hruler parser. */
79      private final HRuleBlockParser hrulerParser = new HRuleBlockParser();
80  
81      /** table parser. */
82      private final TableBlockParser tableParser = new TableBlockParser();
83  
84      /** verbatim parser. */
85      private final VerbatimBlockParser verbatimParser = new VerbatimBlockParser();
86  
87      /** list of parsers to try to apply to the toplevel */
88      private BlockParser[] parsers;
89  
90      /**
91       * Creates the TWikiParser.
92       */
93      public TWikiParser()
94      {
95          init();
96      }
97  
98      /**
99       * <p>parse.</p>
100      *
101      * @param source source to parse.
102      * @return the blocks that represent source.
103      * @throws org.apache.maven.doxia.parser.ParseException on error.
104      */
105     public final List<Block> parse( final ByLineSource source )
106         throws ParseException
107     {
108         final List<Block> ret = new ArrayList<>();
109 
110         String line;
111         while ( ( line = source.getNextLine() ) != null )
112         {
113             boolean accepted = false;
114 
115             for ( BlockParser parser : parsers )
116             {
117                 if ( parser.accept( line ) )
118                 {
119                     accepted = true;
120                     ret.add( parser.visit( line, source ) );
121                     break;
122                 }
123             }
124             if ( !accepted )
125             {
126                 throw new ParseException( "Line number not handle : " + source.getLineNumber() + ": " + line );
127             }
128         }
129 
130         return ret;
131     }
132 
133     /** {@inheritDoc} */
134     @Override
135     public void parse( Reader source, Sink sink )
136         throws ParseException
137     {
138         parse( source, sink, "" );
139     }
140     
141     /** {@inheritDoc} */
142     @Override
143     public final synchronized void parse( final Reader source, final Sink sink, String reference )
144         throws ParseException
145     {
146         init();
147 
148         List<Block> blocks;
149         final ByLineSource src = new ByLineReaderSource( source, reference );
150 
151         try
152         {
153             blocks = parse( src );
154         }
155         catch ( final Exception e )
156         {
157             // TODO handle column number
158             throw new ParseException( e, src.getName(), src.getLineNumber(), -1 );
159         }
160 
161         sink.head();
162 
163         final String title = getTitle( blocks, src );
164         if ( title != null )
165         {
166             sink.title();
167             sink.text( title );
168             sink.title_();
169         }
170 
171         sink.head_();
172         sink.body();
173         for ( Block block : blocks )
174         {
175             block.traverse( sink );
176         }
177         sink.body_();
178         sink.flush();
179         sink.close();
180 
181         setSecondParsing( false );
182         init();
183     }
184 
185     /**
186      * Guess a title for the page. It uses the first section that it finds.
187      * If it doesn't find any section tries to get it from
188      * {@link ByLineReaderSource#getName()}
189      *
190      * @param blocks blocks to parse
191      * @param source source to parse
192      * @return a title for a page
193      * @since 1.1
194      */
195     public final String getTitle( final List<Block> blocks, final ByLineSource source )
196     {
197         String title = null;
198 
199         for ( Block block : blocks )
200         {
201             if ( block instanceof SectionBlock )
202             {
203                 final SectionBlock sectionBlock = (SectionBlock) block;
204                 title = sectionBlock.getTitle();
205                 break;
206             }
207         }
208 
209         if ( title == null )
210         {
211             String name = source.getName();
212             if ( name != null )
213             {
214                 name = name.trim();
215 
216                 if ( name.length() != 0 )
217                 {
218                     if ( name.endsWith( ".twiki" ) )
219                     {
220                         title = name.substring( 0, name.length() - EXTENSION_LENGTH );
221                     }
222                     else
223                     {
224                         title = name;
225                     }
226                 }
227             }
228         }
229 
230         return title;
231     }
232 
233     /**
234      * {@inheritDoc}
235      */
236     protected void init()
237     {
238         super.init();
239 
240         paraParser.setSectionParser( sectionParser );
241         paraParser.setListParser( listParser );
242         paraParser.setTextParser( formatTextParser );
243         paraParser.setHrulerParser( hrulerParser );
244         paraParser.setTableBlockParser( tableParser );
245         paraParser.setVerbatimParser( verbatimParser );
246         sectionParser.setParaParser( paraParser );
247         sectionParser.setHrulerParser( hrulerParser );
248         sectionParser.setVerbatimBlockParser( verbatimParser );
249         listParser.setTextParser( formatTextParser );
250         formatTextParser.setTextParser( textParser );
251         tableParser.setTextParser( formatTextParser );
252 
253         this.parsers = new BlockParser[] { sectionParser, hrulerParser, verbatimParser, paraParser };
254     }
255 }