1 package org.apache.torque.generator.outlet.java;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.HashSet;
23 import java.util.Set;
24 import java.util.StringTokenizer;
25
26 import org.apache.commons.lang.StringUtils;
27 import org.apache.torque.generator.GeneratorException;
28 import org.apache.torque.generator.control.ControllerState;
29 import org.apache.torque.generator.outlet.OutletImpl;
30 import org.apache.torque.generator.outlet.OutletResult;
31 import org.apache.torque.generator.qname.QualifiedName;
32
33
34
35
36
37
38 public class JavadocOutlet extends OutletImpl
39 {
40
41 public static final String BODY_MERGEPOINT_NAME = "body";
42
43
44 public static final String ATTRIBUTES_MERGEPOINT_NAME = "attributes";
45
46
47 private static final String START_LINE = "/**";
48
49
50 private static final String MID_LINE_START = " * ";
51
52
53 private static final String END_LINE = " */";
54
55
56 private static final String JAVADOC_ATTRIBUTE_START = "@";
57
58
59 private static final int DEFAULT_MAX_LINEWIDTH = 80;
60
61
62 private String lineBreak = "\n";
63
64
65 private int maxLineLength = DEFAULT_MAX_LINEWIDTH;
66
67
68 private String indent = " ";
69
70
71
72
73
74 private String removableWrapCharacters = " ";
75
76
77
78
79
80 private String wrapAfterCharacters = ".;,-";
81
82
83
84
85
86
87 public JavadocOutlet(QualifiedName qualifiedName)
88 {
89 super(qualifiedName);
90 }
91
92 @Override
93 public OutletResult execute(ControllerState controllerState)
94 throws GeneratorException
95 {
96 StringBuilder result = new StringBuilder();
97 result.append(indent).append(START_LINE).append(lineBreak);
98 String body = mergepoint(BODY_MERGEPOINT_NAME, controllerState);
99 result.append(wrapLinesAndIndent(body));
100 {
101 String attributes = mergepoint(
102 ATTRIBUTES_MERGEPOINT_NAME,
103 controllerState);
104 if (!StringUtils.isEmpty(attributes)
105 && !StringUtils.isEmpty(body))
106 {
107 result.append(indent).append(" *").append(lineBreak);
108 }
109 if (!StringUtils.isEmpty(attributes))
110 {
111 result.append(wrapLinesAndIndent(attributes));
112 }
113 }
114
115 result.append(indent).append(END_LINE).append(lineBreak);
116 return new OutletResult(result.toString());
117 }
118
119
120
121
122
123
124
125
126
127
128 String wrapLinesAndIndent(String content)
129 {
130 if (StringUtils.isBlank(content))
131 {
132 return "";
133 }
134 StringTokenizer tokenizer
135 = new StringTokenizer(
136 content.trim(),
137 removableWrapCharacters
138 + wrapAfterCharacters
139 + "\r\n"
140 + JAVADOC_ATTRIBUTE_START,
141 true);
142 StringBuilder result = new StringBuilder();
143 result.append(indent).append(MID_LINE_START);
144 int currentLineLength = indent.length() + MID_LINE_START.length();
145 boolean lineBreakPossible = false;
146
147 boolean lastCharRemovable = true;
148 String token = null;
149 String currentIndent = indent + MID_LINE_START;
150 String lastJavadocAttribute = null;
151 while (tokenizer.hasMoreTokens() || token != null)
152 {
153 if (token == null)
154 {
155
156 token = tokenizer.nextToken();
157 }
158 if ("\r".equals(token))
159 {
160
161
162 token = null;
163 }
164 else if ("\n".equals(token))
165 {
166
167 result.append(lineBreak);
168 lineBreakPossible = false;
169
170
171 lastCharRemovable = true;
172 if (tokenizer.hasMoreTokens())
173 {
174 result.append(currentIndent);
175 currentLineLength = currentIndent.length();
176 }
177 token = null;
178 }
179 else if (JAVADOC_ATTRIBUTE_START.equals(token))
180 {
181 if (tokenizer.hasMoreTokens())
182 {
183
184 token = tokenizer.nextToken();
185
186 currentIndent = StringUtils.rightPad(
187 indent + MID_LINE_START,
188 indent.length() + MID_LINE_START.length()
189 + 2 + token.length());
190 if (result.length()
191 > indent.length() + MID_LINE_START.length())
192 {
193
194
195 removeEnd(result, " \r\n");
196 boolean alreadyIndented = false;
197 if (result.toString().endsWith(indent + " *"))
198 {
199 alreadyIndented = true;
200 }
201 boolean doubleLineBreak = false;
202 if (!token.equals(lastJavadocAttribute))
203 {
204 doubleLineBreak = true;
205 }
206 if (!alreadyIndented)
207 {
208 result.append(lineBreak).append(indent).append(" *");
209 }
210 if (doubleLineBreak)
211 {
212 result.append(lineBreak).append(indent).append(" *");
213 }
214 result.append(" ");
215 }
216
217 currentLineLength
218 = indent.length() + MID_LINE_START.length();
219 lastJavadocAttribute = token;
220 }
221 result.append(JAVADOC_ATTRIBUTE_START);
222 ++currentLineLength;
223 lineBreakPossible = false;
224 lastCharRemovable = false;
225 }
226 else if (maxLineLength == -1)
227 {
228 result.append(token);
229 token = null;
230 }
231 else if (removableWrapCharacters.indexOf(token) != -1)
232 {
233 if (currentLineLength + 1 > maxLineLength)
234 {
235 result.append(lineBreak);
236 if (tokenizer.hasMoreTokens())
237 {
238 result.append(currentIndent);
239 currentLineLength = currentIndent.length();
240 }
241 lineBreakPossible = false;
242 lastCharRemovable = false;
243 }
244 else
245 {
246 result.append(token);
247 currentLineLength++;
248 lineBreakPossible = true;
249 lastCharRemovable = true;
250 }
251 token = null;
252 }
253 else if (lineBreakPossible)
254 {
255
256 String nextToken = null;
257 if (tokenizer.hasMoreTokens())
258 {
259 nextToken = tokenizer.nextToken();
260 }
261 int unbreakableChunkSize;
262 if (nextToken == null
263 || "\r".equals(nextToken)
264 || "\n".equals(nextToken)
265 || wrapAfterCharacters.contains(token)
266 || JAVADOC_ATTRIBUTE_START.equals(nextToken)
267 || removableWrapCharacters.contains(nextToken))
268 {
269 unbreakableChunkSize = token.length();
270 }
271 else
272 {
273 unbreakableChunkSize = token.length() + nextToken.length();
274 }
275 if (currentLineLength + unbreakableChunkSize > maxLineLength)
276 {
277
278 if (lastCharRemovable)
279 {
280 result.replace(
281 result.length() - 1,
282 result.length(),
283 "");
284 }
285 result.append(lineBreak)
286 .append(currentIndent)
287 .append(token);
288 currentLineLength
289 = currentIndent.length() + token.length();
290 }
291 else
292 {
293
294 result.append(token);
295 currentLineLength += token.length();
296 }
297 lastCharRemovable = false;
298 lineBreakPossible = wrapAfterCharacters.contains(token);
299 token = nextToken;
300 }
301 else
302 {
303 result.append(token);
304 currentLineLength += token.length();
305 lastCharRemovable = false;
306 lineBreakPossible = wrapAfterCharacters.contains(token);
307 token = null;
308 }
309 }
310 if (!result.toString().endsWith(lineBreak))
311 {
312 result.append(lineBreak);
313 }
314 return result.toString();
315 }
316
317 public String getLineBreak()
318 {
319 return lineBreak;
320 }
321
322 public void setLineBreak(String lineBreak)
323 {
324 if (!("\r".equals(lineBreak)) && !("\r\n".equals(lineBreak)))
325 {
326 throw new IllegalArgumentException(
327 "lineBreak must be either \\r or \\r\\n");
328 }
329 this.lineBreak = lineBreak;
330 }
331
332 public int getMaxLineLength()
333 {
334 return maxLineLength;
335 }
336
337 public void setMaxLineLength(int maxLineLength)
338 {
339 this.maxLineLength = maxLineLength;
340 }
341
342 public String getIndent()
343 {
344 return indent;
345 }
346
347 public void setIndent(String indent)
348 {
349 this.indent = indent;
350 }
351
352 public String getRemovableWrapCharacters()
353 {
354 return removableWrapCharacters;
355 }
356
357 public void setRemovableWrapCharacters(String removableWrapCharacters)
358 {
359 this.removableWrapCharacters = removableWrapCharacters;
360 }
361
362 public String getWrapAfterCharacters()
363 {
364 return wrapAfterCharacters;
365 }
366
367 public void setWrapAfterCharacters(String wrapAfterCharacters)
368 {
369 this.wrapAfterCharacters = wrapAfterCharacters;
370 }
371
372
373
374
375
376
377
378
379
380 static void removeEnd(StringBuilder stringBuilder, String removeChars)
381 {
382 Set<Character> removeCharSet = new HashSet<Character>();
383 for (char character : removeChars.toCharArray())
384 {
385 removeCharSet.add(character);
386 }
387 int index = stringBuilder.length();
388 while (index > 0)
389 {
390 if (!removeCharSet.contains(stringBuilder.charAt(index - 1)))
391 {
392 break;
393 }
394 index--;
395 }
396
397
398 stringBuilder.replace(index, stringBuilder.length(), "");
399 }
400 }