View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.maven.doxia.index;
20  
21  import java.util.HashMap;
22  import java.util.Map;
23  import java.util.Stack;
24  import java.util.concurrent.atomic.AtomicInteger;
25  
26  import org.apache.maven.doxia.sink.impl.SinkAdapter;
27  import org.apache.maven.doxia.util.DoxiaUtils;
28  
29  /**
30   * A sink implementation for index.
31   *
32   * @author <a href="mailto:trygvis@inamo.no">Trygve Laugst&oslash;l</a>
33   * @author <a href="mailto:vincent.siveton@gmail.com">Vincent Siveton</a>
34   */
35  public class IndexingSink extends SinkAdapter {
36      /** Section 1. */
37      private static final int TYPE_SECTION_1 = 1;
38  
39      /** Section 2. */
40      private static final int TYPE_SECTION_2 = 2;
41  
42      /** Section 3. */
43      private static final int TYPE_SECTION_3 = 3;
44  
45      /** Section 4. */
46      private static final int TYPE_SECTION_4 = 4;
47  
48      /** Section 5. */
49      private static final int TYPE_SECTION_5 = 5;
50  
51      /** Defined term. */
52      private static final int TYPE_DEFINED_TERM = 6;
53  
54      /** Figure. */
55      private static final int TYPE_FIGURE = 7;
56  
57      /** Table. */
58      private static final int TYPE_TABLE = 8;
59  
60      /** Title. */
61      private static final int TITLE = 9;
62  
63      /** The current type. */
64      private int type;
65  
66      /** The current title. */
67      private String title;
68  
69      /** The stack. */
70      private final Stack<IndexEntry> stack;
71  
72      /** A map containing all used ids of index entries as key and how often they are used as value
73       * (0-based, i.e. 0 means used 1 time). {@link AtomicInteger} is only used here as it implements
74       * a mutable integer (not for its atomicity).
75       */
76      private final Map<String, AtomicInteger> usedIds;
77  
78      /**
79       * Default constructor.
80       *
81       * @param sectionEntry The first index entry.
82       */
83      public IndexingSink(IndexEntry sectionEntry) {
84          stack = new Stack<>();
85          stack.push(sectionEntry);
86          usedIds = new HashMap<>();
87          usedIds.put(sectionEntry.getId(), new AtomicInteger());
88          init();
89      }
90  
91      /**
92       * <p>Getter for the field <code>title</code>.</p>
93       *
94       * @return the title
95       */
96      public String getTitle() {
97          return title;
98      }
99  
100     // ----------------------------------------------------------------------
101     // Sink Overrides
102     // ----------------------------------------------------------------------
103 
104     /**
105      * {@inheritDoc}
106      */
107     public void title() {
108         this.type = TITLE;
109     }
110 
111     /**
112      * {@inheritDoc}
113      */
114     public void section1() {
115         pushNewEntry();
116     }
117 
118     /**
119      * {@inheritDoc}
120      */
121     public void sectionTitle1() {
122         this.type = TYPE_SECTION_1;
123     }
124 
125     /**
126      * {@inheritDoc}
127      */
128     public void title_() {
129         this.type = 0;
130     }
131 
132     /**
133      * <p>sectionTitle1_.</p>
134      */
135     public void sectionTitle1_() {
136         this.type = 0;
137     }
138 
139     /**
140      * {@inheritDoc}
141      */
142     public void section1_() {
143         pop();
144     }
145 
146     /**
147      * {@inheritDoc}
148      */
149     public void section2() {
150         pushNewEntry();
151     }
152 
153     /**
154      * {@inheritDoc}
155      */
156     public void sectionTitle2() {
157         this.type = TYPE_SECTION_2;
158     }
159 
160     /**
161      * <p>sectionTitle2_.</p>
162      */
163     public void sectionTitle2_() {
164         this.type = 0;
165     }
166 
167     /**
168      * {@inheritDoc}
169      */
170     public void section2_() {
171         pop();
172     }
173 
174     /**
175      * {@inheritDoc}
176      */
177     public void section3() {
178         pushNewEntry();
179     }
180 
181     /**
182      * {@inheritDoc}
183      */
184     public void sectionTitle3() {
185         this.type = TYPE_SECTION_3;
186     }
187 
188     /**
189      * <p>sectionTitle3_.</p>
190      */
191     public void sectionTitle3_() {
192         this.type = 0;
193     }
194 
195     /**
196      * {@inheritDoc}
197      */
198     public void section3_() {
199         pop();
200     }
201 
202     /**
203      * {@inheritDoc}
204      */
205     public void section4() {
206         pushNewEntry();
207     }
208 
209     /**
210      * {@inheritDoc}
211      */
212     public void sectionTitle4() {
213         this.type = TYPE_SECTION_4;
214     }
215 
216     /**
217      * <p>sectionTitle4_.</p>
218      */
219     public void sectionTitle4_() {
220         this.type = 0;
221     }
222 
223     /**
224      * {@inheritDoc}
225      */
226     public void section4_() {
227         pop();
228     }
229 
230     /**
231      * {@inheritDoc}
232      */
233     public void section5() {
234         pushNewEntry();
235     }
236 
237     /**
238      * {@inheritDoc}
239      */
240     public void sectionTitle5() {
241         this.type = TYPE_SECTION_5;
242     }
243 
244     /**
245      * <p>sectionTitle5_.</p>
246      */
247     public void sectionTitle5_() {
248         this.type = 0;
249     }
250 
251     /**
252      * {@inheritDoc}
253      */
254     public void section5_() {
255         pop();
256     }
257 
258     // public void definedTerm()
259     // {
260     // type = TYPE_DEFINED_TERM;
261     // }
262     //
263     // public void figureCaption()
264     // {
265     // type = TYPE_FIGURE;
266     // }
267     //
268     // public void tableCaption()
269     // {
270     // type = TYPE_TABLE;
271     // }
272 
273     /** {@inheritDoc} */
274     public void text(String text) {
275         switch (this.type) {
276             case TITLE:
277                 this.title = text;
278                 break;
279             case TYPE_SECTION_1:
280             case TYPE_SECTION_2:
281             case TYPE_SECTION_3:
282             case TYPE_SECTION_4:
283             case TYPE_SECTION_5:
284                 // -----------------------------------------------------------------------
285                 // Sanitize the id. The most important step is to remove any blanks
286                 // -----------------------------------------------------------------------
287 
288                 // append text to current entry
289                 IndexEntry entry = stack.lastElement();
290 
291                 String title = entry.getTitle() + text;
292                 title = title.replaceAll("[\\r\\n]+", "");
293                 entry.setTitle(title);
294 
295                 entry.setId(getUniqueId(DoxiaUtils.encodeId(title)));
296 
297                 break;
298                 // Dunno how to handle these yet
299             case TYPE_DEFINED_TERM:
300             case TYPE_FIGURE:
301             case TYPE_TABLE:
302             default:
303                 break;
304         }
305     }
306 
307     /**
308      * Converts the given id into a unique one by potentially suffixing it with an index value.
309      *
310      * @param id
311      * @return the unique id
312      */
313     String getUniqueId(String id) {
314         final String uniqueId;
315 
316         if (usedIds.containsKey(id)) {
317             uniqueId = id + "_" + usedIds.get(id).incrementAndGet();
318         } else {
319             usedIds.put(id, new AtomicInteger());
320             uniqueId = id;
321         }
322         return uniqueId;
323     }
324 
325     /**
326      * Creates and pushes a new IndexEntry onto the top of this stack.
327      */
328     public void pushNewEntry() {
329         IndexEntry entry = new IndexEntry(peek(), "");
330 
331         entry.setTitle("");
332 
333         stack.push(entry);
334     }
335 
336     /**
337      * Pushes an IndexEntry onto the top of this stack.
338      *
339      * @param entry to put.
340      */
341     public void push(IndexEntry entry) {
342         stack.push(entry);
343     }
344 
345     /**
346      * Removes the IndexEntry at the top of this stack.
347      */
348     public void pop() {
349         stack.pop();
350     }
351 
352     /**
353      * <p>peek.</p>
354      *
355      * @return Looks at the IndexEntry at the top of this stack.
356      */
357     public IndexEntry peek() {
358         return stack.peek();
359     }
360 
361     /**
362      * {@inheritDoc}
363      */
364     public void close() {
365         super.close();
366 
367         init();
368     }
369 
370     /**
371      * {@inheritDoc}
372      */
373     protected void init() {
374         this.type = 0;
375         this.title = null;
376     }
377 }