View Javadoc

1   /*
2    * Copyright 2007-2013 smartics, Kronseder & Reiner GmbH
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package de.smartics.exceptions.report.utils;
17  
18  import static de.smartics.exceptions.report.utils.StringFunction.indexOfFirstWhiteSpace;
19  
20  import java.util.ArrayList;
21  import java.util.Iterator;
22  import java.util.List;
23  
24  import org.apache.commons.lang.StringUtils;
25  
26  import com.thoughtworks.qdox.model.DocletTag;
27  import com.thoughtworks.qdox.model.JavaAnnotatedElement;
28  import com.thoughtworks.qdox.model.impl.DefaultDocletTag;
29  
30  import de.smartics.util.lang.Arg;
31  
32  /**
33   * Parses the Javadoc body and returns the tags and text fragments as an
34   * iterator.
35   */
36  public final class InlineJavadocTags implements Iterable<DocletTag>
37  {
38    // ********************************* Fields *********************************
39  
40    // --- constants ------------------------------------------------------------
41  
42    /**
43     * The identifier of doclets that only contain text.
44     */
45    public static final String TEXT_DOCLET_NAME = "{text}";
46  
47    // --- members --------------------------------------------------------------
48  
49    /**
50     * The annotated element whose Javadoc comment is to be parsed.
51     */
52    private final JavaAnnotatedElement element;
53  
54    // ****************************** Initializer *******************************
55  
56    // ****************************** Constructors ******************************
57  
58    /**
59     * Default constructor.
60     *
61     * @param element the annotated element whose Javadoc comment is to be parsed.
62     * @throws NullPointerException if {@code element} is <code>null</code>.
63     */
64    public InlineJavadocTags(final JavaAnnotatedElement element)
65      throws NullPointerException
66    {
67      this.element = Arg.checkNotNull("element", element);
68    }
69  
70    // ****************************** Inner Classes *****************************
71  
72    // ********************************* Methods ********************************
73  
74    // --- init -----------------------------------------------------------------
75  
76    // --- get&set --------------------------------------------------------------
77  
78    // --- business -------------------------------------------------------------
79  
80    // CHECKSTYLE:OFF
81    /**
82     * Parses the Javadoc body and returns the tags and text fragments as an
83     * iterator.
84     *
85     * @return the iterator over doclet tags and javadoc text.
86     */
87    @Override
88    public Iterator<DocletTag> iterator()
89    {
90      final List<DocletTag> tags = new ArrayList<DocletTag>();
91  
92      final String comment = element.getComment();
93      if (StringUtils.isBlank(comment))
94      {
95        return tags.iterator();
96      }
97  
98      final int length = comment.length();
99      final char[] commentArray = comment.toCharArray();
100     final StringBuilder buffer = new StringBuilder(512);
101     boolean inText = true;
102     int lineNumber = 0;
103     for (int i = 0; i < length; i++)
104     {
105       final char c = commentArray[i];
106 
107       if (inText)
108       {
109         if (c == '{')
110         {
111           if (commentArray[i + 1] == '@')
112           {
113             if (buffer.length() > 0)
114             {
115               final DocletTag textTag =
116                   createTextTag(inText, buffer, lineNumber);
117               tags.add(textTag);
118               buffer.setLength(0);
119             }
120             i++;
121             inText = false;
122           }
123           else
124           {
125             buffer.append(c);
126           }
127         }
128         else
129         {
130           buffer.append(c);
131         }
132       }
133       else
134       {
135         if (c == '}')
136         {
137           final DocletTag tag = createTag(buffer, lineNumber);
138           tags.add(tag);
139           buffer.setLength(0);
140           inText = true;
141         }
142         else
143         {
144           buffer.append(c);
145         }
146       }
147 
148       if (c == '\n')
149       {
150         lineNumber++;
151       }
152     }
153 
154     if (buffer.length() > 0)
155     {
156       final DocletTag textTag = createTextTag(inText, buffer, lineNumber);
157       tags.add(textTag);
158     }
159 
160     return tags.iterator();
161   }
162   // CHECKSTYLE:ON
163 
164   private DocletTag createTextTag(final boolean inText,
165       final StringBuilder buffer, final int lineNumber)
166   {
167     final String string = buffer.toString();
168     final String value = inText ? string : "{@" + string;
169 
170     final DefaultDocletTag tag =
171         new DefaultDocletTag(TEXT_DOCLET_NAME, value, element, lineNumber);
172     return tag;
173   }
174 
175   private DocletTag createTag(final StringBuilder buffer, final int lineNumber)
176   {
177     final int firstBlank = indexOfFirstWhiteSpace(buffer);
178     final String name =
179         firstBlank == -1 ? buffer.toString() : buffer
180             .subSequence(0, firstBlank).toString();
181     final String value =
182         firstBlank != -1 && firstBlank + 1 < buffer.length() ? buffer
183             .substring(firstBlank + 1).trim() : StringUtils.EMPTY;
184     final DefaultDocletTag tag =
185         new DefaultDocletTag(name, value, element, lineNumber);
186     return tag;
187   }
188 
189   /**
190    * Checks if the given tag is a simple text element.
191    *
192    * @param tag the tag to test.
193    * @return <code>true</code> if the tag is only a text, <code>false</code> if
194    *         it is a doclet tag.
195    * @throws NullPointerException if {@code tag} is <code>null</code>.
196    */
197   public static boolean isText(final DocletTag tag) throws NullPointerException
198   {
199     return TEXT_DOCLET_NAME.equals(tag.getName());
200   }
201 
202   // --- object basics --------------------------------------------------------
203 
204 }