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@exolab.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.exolab.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-2001 (C) Intalio, Inc. All Rights Reserved.
42 */
43 package org.exolab.javasource;
44
45 import java.text.MessageFormat;
46 import java.util.StringTokenizer;
47 import java.util.Vector;
48
49 /**
50 * A class for holding in-memory Java source code.
51 *
52 * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
53 * @version $Revision$ $Date: 2005-03-05 06:42:06 -0700 (Sat, 05 Mar 2005) $
54 */
55 public final class JSourceCode {
56 //--------------------------------------------------------------------------
57
58 /** Default indentation size. */
59 public static final int DEFAULT_INDENT_SIZE = 4;
60
61 //--------------------------------------------------------------------------
62
63 /** A list of JCodeStatements. */
64 private Vector<JCodeStatement> _source = null;
65
66 /** The indent size. */
67 private short _indentSize = DEFAULT_INDENT_SIZE;
68
69 /** The current indent size. */
70 private short _currentIndent = _indentSize;
71
72 //--------------------------------------------------------------------------
73
74 /**
75 * Creates an empty JSourceCode.
76 */
77 public JSourceCode() {
78 super();
79
80 _source = new Vector<JCodeStatement>();
81 }
82
83 /**
84 * Creates a JSourceCode and adds the given String to its contents.
85 *
86 * @param sourceCode the source to add
87 */
88 public JSourceCode(final String sourceCode) {
89 this();
90
91 _source.addElement(new JCodeStatement(sourceCode, _currentIndent));
92 }
93
94 //--------------------------------------------------------------------------
95
96 /**
97 * Adds statement generated by replacing parameters of given pattern with given argument to
98 * this JSourceCode. The statement will be added on a new line.
99 *
100 * @param pattern Pattern for the statement.
101 * @param argument Argument to replace first parameter in pattern.
102 */
103 public void add(final String pattern, final Object argument) {
104 add(pattern, new Object[] {argument});
105 }
106
107 /**
108 * Adds statement generated by replacing parameters of given pattern with given arguments to
109 * this JSourceCode. The statement will be added on a new line.
110 *
111 * @param pattern Pattern for the statement.
112 * @param argument1 Argument to replace first parameter in pattern.
113 * @param argument2 Argument to replace second parameter in pattern.
114 */
115 public void add(final String pattern, final Object argument1, final Object argument2) {
116 add(pattern, new Object[] {argument1, argument2});
117 }
118
119 /**
120 * Adds statements generated by replacing parameters of given pattern with given arguments to
121 * this JSourceCode. Multiple statements can be separated by '\n' characters. Each statement
122 * will be added on a new line. If that statement starts with whitespace characters it will
123 * be indented.
124 *
125 * @param pattern Pattern for the statement.
126 * @param arguments Arguments to replace parameters in pattern.
127 */
128 public void add(final String pattern, final Object[] arguments) {
129 StringTokenizer tokenizer = new StringTokenizer(pattern, "\n");
130 while (tokenizer.hasMoreTokens()) { addWithIndent(tokenizer.nextToken(), arguments); }
131 }
132
133 /**
134 * Adds statement generated by replacing parameters of given pattern with given arguments to
135 * this JSourceCode. The statement will be added on a new line. If the statement starts with
136 * whitespace characters the statement will be indented.
137 *
138 * @param pattern Pattern for the statement.
139 * @param arguments Arguments to replace parameters in pattern.
140 */
141 private void addWithIndent(final String pattern, final Object[] arguments) {
142 if (pattern.startsWith(" ")) {
143 indent();
144 addWithIndent(pattern.substring(1), arguments);
145 unindent();
146 } else if ((pattern.indexOf('{') + 2) == pattern.indexOf('}')) {
147 add(MessageFormat.format(pattern, arguments));
148 } else {
149 add(pattern);
150 }
151 }
152
153 /**
154 * Adds the given statement to this JSourceCode. The statement will be added
155 * on a new line.
156 *
157 * @param statement The statement to add.
158 */
159 public void add(final String statement) {
160 _source.addElement(new JCodeStatement(statement, _currentIndent));
161 }
162
163 /**
164 * Adds the given statement to this JSourceCode. The statement will be added
165 * on a new line and added with increased indent. This is a convenience
166 * method for the sequence:
167 * <code>
168 * indent();
169 * add(statement);
170 * unindent();
171 * </code>
172 * @param statement The statement to add.
173 */
174 public void addIndented(final String statement) {
175 indent();
176 _source.addElement(new JCodeStatement(statement, _currentIndent));
177 unindent();
178 }
179
180 /**
181 * Appends the given String to the last line in this JSourceCode.
182 *
183 * @param segment The String to append.
184 */
185 public void append(final String segment) {
186 if (_source.isEmpty()) {
187 add(segment);
188 } else {
189 JCodeStatement jcs = _source.lastElement();
190 jcs.append(segment);
191 }
192 }
193
194 /**
195 * Clears all the code statements from this JSourceCode.
196 */
197 public void clear() {
198 _source.removeAllElements();
199 }
200
201 /**
202 * Copies the contents of this JSourceCode into the given JSourceCode.
203 *
204 * @param jsc The JSourceCode to copy this JSourceCode into.
205 */
206 public void copyInto(final JSourceCode jsc) {
207 for (int i = 0; i < _source.size(); i++) {
208 jsc.addCodeStatement(_source.elementAt(i));
209 }
210 }
211
212 /**
213 * Increases the current indent level by 1.
214 */
215 public void indent() {
216 _currentIndent += _indentSize;
217 }
218
219 /**
220 * Returns true if this JSourceCode is empty (ie. no source).
221 *
222 * @return True if this JSourceCode is empty.
223 */
224 public boolean isEmpty() {
225 return _source.isEmpty();
226 }
227
228 /**
229 * Prints this JSourceCode to the given JSourceWriter.
230 *
231 * @param jsw The JSourceWriter to print to.
232 */
233 public void print(final JSourceWriter jsw) {
234 for (int i = 0; i < _source.size(); i++) {
235 jsw.writeln(_source.elementAt(i).toString());
236 }
237 }
238
239 /**
240 * Decreases the indent level by 1.
241 */
242 public void unindent() {
243 _currentIndent -= _indentSize;
244 }
245
246 /**
247 * Returns the number of source code lines (aka JCodeStatements) set so far.
248 *
249 * @return The number of source code lines set so far.
250 */
251 public int size() {
252 return _source.size();
253 }
254
255 /**
256 * Adds the given JCodeStatement to this JSourceCode.
257 *
258 * @param jcs The JCodeStatement to add.
259 */
260 private void addCodeStatement(final JCodeStatement jcs) {
261 short indent = (short) (jcs.getIndent() + _currentIndent - DEFAULT_INDENT_SIZE);
262 _source.addElement(new JCodeStatement(jcs.getStatement(), indent));
263 }
264
265 /**
266 * Returns a vector of source lines.
267 *
268 * @return A vector of source lines.
269 */
270 public Vector<JCodeStatement> getSource() {
271 return _source;
272 }
273
274 //--------------------------------------------------------------------------
275
276 /**
277 * {@inheritDoc}
278 */
279 public String toString() {
280 StringBuilder sb = new StringBuilder(100);
281 String lineSeparator = System.getProperty("line.separator");
282 for (int i = 0; i < _source.size(); i++) {
283 sb.append(_source.elementAt(i).toString());
284 sb.append(lineSeparator);
285 }
286 return sb.toString();
287 }
288
289 //--------------------------------------------------------------------------
290 }