1 /**
2 * Redistribution and use of this software and associated documentation
3 * ("Software"), with or without modification, are permitted provided
4 * that the following conditions are met:
5 *
6 * 1. Redistributions of source code must retain copyright
7 * statements and notices. Redistributions must also contain a
8 * copy of this document.
9 *
10 * 2. Redistributions in binary form must reproduce the
11 * above copyright notice, this list of conditions and the
12 * following disclaimer in the documentation and/or other
13 * materials provided with the distribution.
14 *
15 * 3. The name "Exolab" must not be used to endorse or promote
16 * products derived from this Software without prior written
17 * permission of Intalio, Inc. For written permission,
18 * please contact info@codehaus.org.
19 *
20 * 4. Products derived from this Software may not be called "Exolab"
21 * nor may "Exolab" appear in their names without prior written
22 * permission of Intalio, Inc. Exolab is a registered
23 * trademark of Intalio, Inc.
24 *
25 * 5. Due credit should be given to the Exolab Project
26 * (http://www.codehaus.org/).
27 *
28 * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS
29 * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
30 * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
31 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
32 * INTALIO, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
33 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
34 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
35 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
37 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
38 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
39 * OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Copyright 1999 (C) Intalio, Inc. All Rights Reserved.
42 *
43 * $Id$
44 */
45 package org.codehaus.modello.plugin.java.javasource;
46
47 /*
48 * Copyright (c) 2004, Codehaus.org
49 *
50 * Permission is hereby granted, free of charge, to any person obtaining a copy of
51 * this software and associated documentation files (the "Software"), to deal in
52 * the Software without restriction, including without limitation the rights to
53 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
54 * of the Software, and to permit persons to whom the Software is furnished to do
55 * so, subject to the following conditions:
56 *
57 * The above copyright notice and this permission notice shall be included in all
58 * copies or substantial portions of the Software.
59 *
60 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
63 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
64 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
65 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
66 * SOFTWARE.
67 */
68
69 /**
70 * A class that represents a Java comment.
71 * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
72 * @version $Revision$ $Date$
73 **/
74 public class JComment {
75
76 /**
77 * The auto style, allows this JComment to automatically
78 * choose a style for this comment
79 **/
80 public static final short AUTO_STYLE = 0;
81
82 /**
83 * The block comment style: \/* *\/
84 **/
85 public static final short BLOCK_STYLE = 1;
86
87 /**
88 * The line comment style: \/\/
89 **/
90 public static final short LINE_STYLE = 2;
91
92 /**
93 * The header style, similiar to block, but with an '*'
94 * at the start of each line.
95 **/
96 public static final short HEADER_STYLE = 3;
97
98 /**
99 * Similiar to HEADER_STYLE, but starts with: \/**
100 **/
101 public static final short JAVADOC_STYLE = 4;
102
103 private static final String START_BLOCK = "/*";
104 private static final String END_BLOCK = " */";
105
106 private static final String START_JAVADOC = "/**";
107 private static final String END_JAVADOC = " */";
108
109 private static final String ASTERIX_PREFIX = " * ";
110 private static final String LINE_COMMENT_PREFIX = "// ";
111 private static final String SPACE_PREFIX = " ";
112
113 /**
114 * The style of this comment
115 **/
116 private short style = AUTO_STYLE;
117
118 /**
119 * The main comment for this JDocComment
120 **/
121 private StringBuilder _comment = null;
122
123 /**
124 * The maximum number of characters per line
125 **/
126 protected static final int MAX_LENGTH = 65;
127
128 /**
129 * Creates a new Java Comment
130 **/
131 public JComment() {
132 super();
133 _comment = new StringBuilder();
134 } // -- JComment
135
136 /**
137 * Creates a new Java comment with the given style
138 *
139 * @param style the comment style
140 **/
141 public JComment(short style) {
142 this();
143 this.style = style;
144 } // -- JComment
145
146 /**
147 * Appends the comment String to this JDocComment
148 * @param comment the comment to append
149 **/
150 public void appendComment(String comment) {
151 _comment.append(comment);
152 } // -- appendComment
153
154 /**
155 * prints this JComment using the given JSourceWriter
156 * @param jsw the JSourceWriter to print to
157 **/
158 public void print(JSourceWriter jsw) {
159
160 if (jsw == null) return; // -- nothing to do
161
162 LineFormatter formatter = null;
163
164 // -- calculate comment length
165 short currentIndent = jsw.getIndentSize();
166 int maxLength = MAX_LENGTH - currentIndent;
167
168 // -- a simple to check to make sure we have some room
169 // -- to print the comment
170 if (maxLength <= 17) maxLength = MAX_LENGTH / 2;
171
172 short resolvedStyle = style;
173
174 if (style == AUTO_STYLE) {
175 // -- estimation of number of lines
176 int nbrLines = _comment.length() / maxLength;
177
178 if (nbrLines > 2) resolvedStyle = BLOCK_STYLE;
179 else resolvedStyle = LINE_STYLE;
180 }
181
182 // -- start comment
183 String prefix = null;
184 String start = null;
185 String end = null;
186
187 switch (resolvedStyle) {
188 case BLOCK_STYLE:
189 start = START_BLOCK;
190 end = END_BLOCK;
191 prefix = SPACE_PREFIX;
192 break;
193 case HEADER_STYLE:
194 start = START_BLOCK;
195 end = END_BLOCK;
196 prefix = ASTERIX_PREFIX;
197 break;
198 case JAVADOC_STYLE:
199 start = START_JAVADOC;
200 end = END_JAVADOC;
201 prefix = ASTERIX_PREFIX;
202 break;
203 default: // -- LINE
204 prefix = LINE_COMMENT_PREFIX;
205 break;
206 }
207 if (start != null) jsw.writeln(start);
208 // -- print main comment
209 formatter = new LineFormatter(_comment.toString(), maxLength, prefix);
210 while (formatter.hasMoreLines()) {
211 jsw.writeln(formatter.nextLine());
212 }
213 if (end != null) jsw.writeln(end);
214 jsw.flush();
215 } // -- print
216
217 /**
218 * Sets the comment String of this JDocComment
219 * @param comment the comment String of this JDocComment
220 **/
221 public void setComment(String comment) {
222 _comment.setLength(0);
223 _comment.append(comment);
224 } // -- setComment
225
226 /**
227 * Sets the style for this JComment
228 * @param style the style to use for this JComment
229 **/
230 public void setStyle(short style) {
231 this.style = style;
232 } // -- setStyle
233
234 /**
235 * Returns the String representation of this Java Doc Comment
236 * @return the String representation of this Java Doc Comment
237 **/
238 public String toString() {
239 return "";
240 } // -- toString
241 } // -- JComment
242
243 /**
244 * Formats a given String for use within a Java comment
245 * @author <a href="mailto:kvisco@intalio.com">Keith Visco</a>
246 **/
247 class LineFormatter {
248
249 String comment = null;
250
251 int maxLength = 65;
252 int offset = 0;
253 int length = 0;
254
255 String prefix = null;
256
257 private StringBuilder sb = null;
258
259 /**
260 * Creates a LineFormatter for the given comment
261 * @param comment the String to format
262 **/
263 LineFormatter(String comment) {
264 this.comment = comment;
265 if (comment != null) this.length = comment.length();
266 sb = new StringBuilder();
267 } // -- LineFormatter
268
269 /**
270 * Creates a new LineFormatter for the given comment
271 * @param comment the String to format
272 * @param maxLength the maximum number of characters per line
273 **/
274 LineFormatter(String comment, int maxLength) {
275 this(comment, maxLength, null);
276 } // -- LineFormatter
277
278 /**
279 * Creates a new LineFormatter for the given comment
280 * @param comment the String to format
281 * @param maxLength the maximum number of characters per line
282 * @param prefix a prefix to append to the beginning of each line
283 **/
284 LineFormatter(String comment, int maxLength, String prefix) {
285 this(comment);
286 this.maxLength = maxLength;
287 this.prefix = prefix;
288 } // -- LineFormatter
289
290 boolean hasMoreLines() {
291 if (comment == null) return false;
292 return (offset < length);
293 } // -- isFinished
294
295 String nextLine() {
296 if (comment == null) return null;
297 if (offset >= length) return null;
298
299 sb.setLength(0);
300 if (prefix != null) sb.append(prefix);
301
302 int max = offset + maxLength;
303 if (max > this.length) max = this.length;
304
305 int index = offset;
306 int breakable = offset;
307 for (; index < max; index++) {
308 char ch = comment.charAt(index);
309 if (isNewLine(ch)) {
310 sb.append(comment.substring(offset, index));
311 offset = index + 1;
312 return sb.toString();
313 }
314 if (isWhitespace(ch)) breakable = index;
315 }
316
317 if (index < length - 1) {
318 // -- if we could not find a breakable character, we must look
319 // -- ahead
320 if (offset == breakable) {
321 while (index < length) {
322 if (isBreakable(comment.charAt(index))) break;
323 ++index;
324 }
325 } else index = breakable;
326 }
327 sb.append(comment.substring(offset, index));
328 offset = index + 1;
329 return sb.toString();
330 } // -- getNextLine
331
332 /**
333 * Sets the prefix that should be appended to the beginning of
334 * each line
335 * @param prefix the prefix for this LineFormatter
336 **/
337 void setPrefix(String prefix) {
338 this.prefix = prefix;
339 } // -- setPrefix
340
341 private boolean isBreakable(char ch) {
342 return (isWhitespace(ch) || isNewLine(ch));
343 }
344
345 private boolean isWhitespace(char ch) {
346 return ((ch == ' ') || (ch == '\t'));
347 } // -- isWhitespace
348
349 private boolean isNewLine(char ch) {
350 return ((ch == '\n') || (ch == '\r'));
351 } // -- isNewLineChar
352 } // -- LineFormatter