View Javadoc

1   package org.apache.maven.doxia.module.confluence.parser;
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 java.util.ArrayList;
23  import java.util.List;
24  
25  import org.codehaus.plexus.util.StringUtils;
26  
27  /**
28   * Re-usable builder that can be used to generate paragraph and list item text from a string containing all the content
29   * and wiki formatting. This class is intentionally stateful, but cheap to create, so create one as needed and keep it
30   * on the stack to preserve stateless behaviour in the caller.
31   *
32   * @author Dave Syer
33   * @version $Id: ChildBlocksBuilder.java 1090706 2011-04-09 23:15:28Z hboutemy $
34   * @since 1.1
35   */
36  public class ChildBlocksBuilder
37  {
38      private boolean insideBold = false;
39  
40      private boolean insideItalic = false;
41  
42      private boolean insideLink = false;
43  
44      private List<Block> blocks = new ArrayList<Block>();
45  
46      private StringBuffer text = new StringBuffer();
47  
48      private String input;
49  
50      private boolean insideMonospaced;
51  
52      /**
53       * <p>Constructor for ChildBlocksBuilder.</p>
54       *
55       * @param input the input.
56       */
57      public ChildBlocksBuilder( String input )
58      {
59          this.input = input;
60      }
61  
62      /**
63       * Utility method to convert marked up content into blocks for rendering.
64       *
65       * @return a list of Blocks that can be used to render it
66       */
67      public List<Block> getBlocks()
68      {
69          List<Block> specialBlocks = new ArrayList<Block>();
70  
71          for ( int i = 0; i < input.length(); i++ )
72          {
73              char c = input.charAt( i );
74  
75              switch ( c )
76              {
77                  case '*':
78                      if ( insideBold )
79                      {
80                          insideBold = false;
81                          specialBlocks = getList( new BoldBlock( getChildren( text, specialBlocks ) ), specialBlocks );
82                          text = new StringBuffer();
83                      }
84                      else
85                      {
86                          text = addTextBlockIfNecessary( blocks, specialBlocks, text );
87                          insideBold = true;
88                      }
89  
90                      break;
91                  case '_':
92                      if ( insideItalic )
93                      {
94                          insideItalic = false;
95                          specialBlocks = getList( new ItalicBlock( getChildren( text, specialBlocks ) ), specialBlocks );
96                          text = new StringBuffer();
97                      }
98                      else
99                      {
100                         text = addTextBlockIfNecessary( blocks, specialBlocks, text );
101                         insideItalic = true;
102                     }
103 
104                     break;
105                 case '[':
106                     insideLink = true;
107                     text = addTextBlockIfNecessary( blocks, specialBlocks, text );
108                     break;
109                 case ']':
110                     if ( insideLink )
111                     {
112                         boolean addHTMLSuffix = false;
113                         String link = text.toString();
114 
115                         if ( !link.endsWith( ".html" ) )
116                         {
117                             if ( link.indexOf( "http" ) < 0 )
118                             {
119                                 addHTMLSuffix = true;
120                             }
121                         }
122                         if ( link.indexOf( "|" ) > 0 )
123                         {
124                             String[] pieces = StringUtils.split( text.toString(), "|" );
125 
126                             if ( addHTMLSuffix )
127                             {
128                                 if ( pieces[1].indexOf( "#" ) < 0 )
129                                 {
130                                     pieces[1] = pieces[1].concat( ".html" );
131                                 }
132                                 else
133                                 {
134                                     if ( !pieces[1].startsWith( "#" ) )
135                                     {
136                                         String[] temp = pieces[1].split( "#" );
137                                         pieces[1] = temp[0] + ".html#" + temp[1];
138                                     }
139                                 }
140                             }
141 
142                             blocks.add( new LinkBlock( pieces[1], pieces[0] ) );
143                         }
144                         else
145                         {
146                             String value = link;
147 
148                             if ( link.startsWith( "#" ) )
149                             {
150                                 value = link.substring( 1 );
151                             }
152 
153                             if ( addHTMLSuffix )
154                             {
155                                 if ( link.indexOf( "#" ) < 0 )
156                                 {
157                                     link = link.concat( ".html" );
158                                 }
159                                 else
160                                 {
161                                     if ( !link.startsWith( "#" ) )
162                                     {
163                                         String[] temp = link.split( "#" );
164                                         link = temp[0] + ".html#" + temp[1];
165                                     }
166                                 }
167                             }
168 
169                             blocks.add( new LinkBlock( link, value ) );
170                         }
171 
172                         text = new StringBuffer();
173                         insideLink = false;
174                     }
175 
176                     break;
177                 case '{':
178 
179                     text = addTextBlockIfNecessary( blocks, specialBlocks, text );
180 
181                     if ( charAt( input, i ) == '{' ) // it's monospaced
182                     {
183                         i++;
184                         insideMonospaced = true;
185                     }
186                     // else it's a confluence macro...
187 
188                     break;
189                 case '}':
190 
191                     // System.out.println( "line = " + line );
192 
193                     if ( charAt( input, i ) == '}' )
194                     {
195                         i++;
196                         insideMonospaced = false;
197                         specialBlocks = getList( new MonospaceBlock( getChildren( text, specialBlocks ) ),
198                                                  specialBlocks );
199                         text = new StringBuffer();
200                     }
201                     else
202                     {
203                         String name = text.toString();
204                         if ( name.startsWith( "anchor:" ) )
205                         {
206                             blocks.add( new AnchorBlock( name.substring( "anchor:".length() ) ) );
207                         }
208                         else
209                         {
210                             blocks.add( new TextBlock( "{" + name + "}" ) );
211                         }
212                         text = new StringBuffer();
213                     }
214 
215                     break;
216                 case '\\':
217 
218                     // System.out.println( "line = " + line );
219 
220                     if ( charAt( input, i ) == '\\' )
221                     {
222                         i++;
223                         text = addTextBlockIfNecessary( blocks, specialBlocks, text );
224                         blocks.add( new LinebreakBlock() );
225                     }
226                     else
227                     {
228                         i++;
229                         text.append( input.charAt( i ) );
230                     }
231 
232                     break;
233                 default:
234                     text.append( c );
235             }
236 
237             if ( !specialBlocks.isEmpty() )
238             {
239                 if ( !insideItalic && !insideBold && !insideMonospaced )
240                 {
241                     blocks.addAll( specialBlocks );
242                     specialBlocks.clear();
243                 }
244             }
245 
246         }
247 
248         if ( text.length() > 0 )
249         {
250             blocks.add( new TextBlock( text.toString() ) );
251         }
252 
253         return blocks;
254     }
255 
256     private List<Block> getList( Block block, List<Block> currentBlocks )
257     {
258         List<Block> list = new ArrayList<Block>();
259 
260         if ( insideBold || insideItalic || insideMonospaced )
261         {
262             list.addAll( currentBlocks );
263         }
264 
265         list.add( block );
266 
267         return list;
268     }
269 
270     private List<Block> getChildren( StringBuffer buffer, List<Block> currentBlocks )
271     {
272         String txt = buffer.toString().trim();
273 
274         if ( currentBlocks.isEmpty() && StringUtils.isEmpty( txt ) )
275         {
276             return new ArrayList<Block>();
277         }
278 
279         ArrayList<Block> list = new ArrayList<Block>();
280 
281         if ( !insideBold && !insideItalic && !insideMonospaced )
282         {
283             list.addAll( currentBlocks );
284         }
285 
286         if ( StringUtils.isEmpty( txt ) )
287         {
288             return list;
289         }
290 
291         list.add( new TextBlock( txt ) );
292 
293         return list;
294     }
295 
296     private static char charAt( String input, int i )
297     {
298         return input.length() > i + 1 ? input.charAt( i + 1 ) : '\0';
299     }
300 
301     private StringBuffer addTextBlockIfNecessary( List<Block> blcks, List<Block> specialBlocks, StringBuffer txt )
302     {
303         if ( txt.length() == 0 )
304         {
305             return txt;
306         }
307 
308         TextBlock textBlock = new TextBlock( txt.toString() );
309 
310         if ( !insideBold && !insideItalic && !insideMonospaced )
311         {
312             blcks.add( textBlock );
313         }
314         else
315         {
316             specialBlocks.add( textBlock );
317         }
318 
319         return new StringBuffer();
320     }
321 
322 }