View Javadoc
1   /**
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 1999-2001 (C) Intalio, Inc. All Rights Reserved.
32   */
33  package org.exolab.javasource;
34  
35  import java.text.MessageFormat;
36  import java.util.StringTokenizer;
37  import java.util.Vector;
38  
39  /**
40   * A class for holding in-memory Java source code.
41   *
42   * @author <a href="mailto:keith AT kvisco DOT com">Keith Visco</a>
43   * @version $Revision$ $Date: 2005-03-05 06:42:06 -0700 (Sat, 05 Mar 2005) $
44   */
45  public final class JSourceCode {
46    // --------------------------------------------------------------------------
47  
48    /** Default indentation size. */
49    public static final int DEFAULT_INDENT_SIZE = 4;
50  
51    // --------------------------------------------------------------------------
52  
53    /** A list of JCodeStatements. */
54    private final Vector<JCodeStatement> _source = new Vector<>();
55  
56    /** The indent size. */
57    private short _indentSize = DEFAULT_INDENT_SIZE;
58  
59    /** The current indent size. */
60    private short _currentIndent = _indentSize;
61  
62    // --------------------------------------------------------------------------
63  
64    /**
65     * Creates an empty JSourceCode.
66     */
67    public JSourceCode() {
68      super();
69    }
70  
71    /**
72     * Creates a JSourceCode and adds the given String to its contents.
73     *
74     * @param sourceCode the source to add
75     */
76    public JSourceCode(final String sourceCode) {
77      this();
78  
79      _source.add(new JCodeStatement(sourceCode, _currentIndent));
80    }
81  
82    // --------------------------------------------------------------------------
83  
84    /**
85     * Adds statement generated by replacing parameters of given pattern with given argument to this
86     * JSourceCode. The statement will be added on a new line.
87     *
88     * @param pattern Pattern for the statement.
89     * @param argument Argument to replace first parameter in pattern.
90     */
91    public void add(final String pattern, final Object argument) {
92      add(pattern, new Object[] {argument});
93    }
94  
95    /**
96     * Adds statement generated by replacing parameters of given pattern with given arguments to this
97     * JSourceCode. The statement will be added on a new line.
98     *
99     * @param pattern Pattern for the statement.
100    * @param argument1 Argument to replace first parameter in pattern.
101    * @param argument2 Argument to replace second parameter in pattern.
102    */
103   public void add(final String pattern, final Object argument1, final Object argument2) {
104     add(pattern, new Object[] {argument1, argument2});
105   }
106 
107   /**
108    * Adds statements generated by replacing parameters of given pattern with given arguments to this
109    * JSourceCode. Multiple statements can be separated by '\n' characters. Each statement will be
110    * added on a new line. If that statement starts with whitespace characters it will be indented.
111    *
112    * @param pattern Pattern for the statement.
113    * @param arguments Arguments to replace parameters in pattern.
114    */
115   public void add(final String pattern, final Object[] arguments) {
116     StringTokenizer tokenizer = new StringTokenizer(pattern, "\n");
117     while (tokenizer.hasMoreTokens()) {
118       addWithIndent(tokenizer.nextToken(), arguments);
119     }
120   }
121 
122   /**
123    * Adds statement generated by replacing parameters of given pattern with given arguments to this
124    * JSourceCode. The statement will be added on a new line. If the statement starts with whitespace
125    * characters the statement will be indented.
126    *
127    * @param pattern Pattern for the statement.
128    * @param arguments Arguments to replace parameters in pattern.
129    */
130   private void addWithIndent(final String pattern, final Object[] arguments) {
131     if (pattern.startsWith(" ")) {
132       indent();
133       addWithIndent(pattern.substring(1), arguments);
134       unindent();
135     } else if ((pattern.indexOf('{') + 2) == pattern.indexOf('}')) {
136       add(MessageFormat.format(pattern, arguments));
137     } else {
138       add(pattern);
139     }
140   }
141 
142   /**
143    * Adds the given statement to this JSourceCode. The statement will be added on a new line.
144    *
145    * @param statement The statement to add.
146    */
147   public void add(final String statement) {
148     _source.add(new JCodeStatement(statement, _currentIndent));
149   }
150 
151   /**
152    * Adds the given statement to this JSourceCode. The statement will be added on a new line and
153    * added with increased indent. This is a convenience method for the sequence: <code>
154    * indent();
155    * add(statement);
156    * unindent();
157    * </code>
158    * 
159    * @param statement The statement to add.
160    */
161   public void addIndented(final String statement) {
162     indent();
163     _source.add(new JCodeStatement(statement, _currentIndent));
164     unindent();
165   }
166 
167   /**
168    * Appends the given String to the last line in this JSourceCode.
169    *
170    * @param segment The String to append.
171    */
172   public void append(final String segment) {
173     if (_source.isEmpty()) {
174       add(segment);
175     } else {
176       JCodeStatement jcs = _source.lastElement();
177       jcs.append(segment);
178     }
179   }
180 
181   /**
182    * Clears all the code statements from this JSourceCode.
183    */
184   public void clear() {
185     _source.removeAllElements();
186   }
187 
188   /**
189    * Copies the contents of this JSourceCode into the given JSourceCode.
190    *
191    * @param jsc The JSourceCode to copy this JSourceCode into.
192    */
193   public void copyInto(final JSourceCode jsc) {
194     for (JCodeStatement jcs : _source) {
195       jsc.addCodeStatement(jcs);
196     }
197   }
198 
199   /**
200    * Increases the current indent level by 1.
201    */
202   public void indent() {
203     _currentIndent += _indentSize;
204   }
205 
206   /**
207    * Returns true if this JSourceCode is empty (ie. no source).
208    *
209    * @return True if this JSourceCode is empty.
210    */
211   public boolean isEmpty() {
212     return _source.isEmpty();
213   }
214 
215   /**
216    * Prints this JSourceCode to the given JSourceWriter.
217    *
218    * @param jsw The JSourceWriter to print to.
219    */
220   public void print(final JSourceWriter jsw) {
221     for (JCodeStatement jcs : _source) {
222       jsw.writeln(jcs.toString());
223     }
224   }
225 
226   /**
227    * Decreases the indent level by 1.
228    */
229   public void unindent() {
230     _currentIndent -= _indentSize;
231   }
232 
233   /**
234    * Returns the number of source code lines (aka JCodeStatements) set so far.
235    * 
236    * @return The number of source code lines set so far.
237    */
238   public int size() {
239     return _source.size();
240   }
241 
242   /**
243    * Adds the given JCodeStatement to this JSourceCode.
244    *
245    * @param jcs The JCodeStatement to add.
246    */
247   private void addCodeStatement(final JCodeStatement jcs) {
248     short indent = (short) (jcs.getIndent() + _currentIndent - DEFAULT_INDENT_SIZE);
249     _source.add(new JCodeStatement(jcs.getStatement(), indent));
250   }
251 
252   /**
253    * Returns a vector of source lines.
254    * 
255    * @return A vector of source lines.
256    */
257   public Vector<JCodeStatement> getSource() {
258     return _source;
259   }
260 
261   // --------------------------------------------------------------------------
262 
263   /**
264    * {@inheritDoc}
265    */
266   public String toString() {
267     StringBuilder sb = new StringBuilder(100);
268     String lineSeparator = System.getProperty("line.separator");
269     for (JCodeStatement jcs : _source) {
270       sb.append(jcs).append(lineSeparator);
271     }
272     return sb.toString();
273   }
274 
275   // --------------------------------------------------------------------------
276 }