001: // Copyright 2006, 2007 The Apache Software Foundation
002: //
003: // Licensed under the Apache License, Version 2.0 (the "License");
004: // you may not use this file except in compliance with the License.
005: // You may obtain a copy of the License at
006: //
007: // http://www.apache.org/licenses/LICENSE-2.0
008: //
009: // Unless required by applicable law or agreed to in writing, software
010: // distributed under the License is distributed on an "AS IS" BASIS,
011: // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
012: // See the License for the specific language governing permissions and
013: // limitations under the License.
014:
015: package org.apache.tapestry.ioc.util;
016:
017: import java.util.Formatter;
018:
019: /**
020: * Utility class for assembling the <em>body</em> used with Javassist when defining a method or
021: * constructor. Basically, assists with formatting and with indentation. This makes the code that
022: * assembles a method body much simpler ... and it makes the result neater, which will be easier to
023: * debug (debugging dynamically generated code is hard enough that it should be easy to read the
024: * input code before worrying about why it doesn't compile or execute properly).
025: * <p>
026: * This class is not threadsafe.
027: */
028: public final class BodyBuilder {
029: /**
030: * Feels right for the size of a typical body.
031: */
032: private static final int DEFAULT_LENGTH = 200;
033:
034: private final StringBuilder _buffer = new StringBuilder(
035: DEFAULT_LENGTH);
036:
037: private final Formatter _formatter = new Formatter(_buffer);
038:
039: // Per level of nesting depth (two spaces).
040:
041: private static final String INDENT = " ";
042:
043: private int _nestingDepth = 0;
044:
045: private boolean _atNewLine = true;
046:
047: /**
048: * Clears the builder, returning it to its initial, empty state.
049: */
050: public void clear() {
051: _nestingDepth = 0;
052: _atNewLine = true;
053: _buffer.setLength(0);
054: }
055:
056: /**
057: * Adds text to the current line, without ending the line.
058: *
059: * @param a
060: * string format, as per {@link java.util.Formatter}
061: * @param args
062: * arguments referenced by format specifiers
063: */
064: public void add(String format, Object... args) {
065: add(format, args, false);
066: }
067:
068: /**
069: * Adds text to the current line and ends the line.
070: *
071: * @param a
072: * string format, as per {@link java.util.Formatter}
073: * @param args
074: * arguments referenced by format specifiers
075: */
076: public void addln(String format, Object... args) {
077: add(format, args, true);
078: }
079:
080: private void add(String format, Object[] args, boolean newLine) {
081: indent();
082:
083: // Format output, send to buffer
084:
085: _formatter.format(format, args);
086:
087: if (newLine)
088: newline();
089: }
090:
091: private void newline() {
092: _buffer.append("\n");
093: _atNewLine = true;
094: }
095:
096: /**
097: * Begins a new block. Emits a "{", properly indented, on a new line.
098: */
099: public void begin() {
100: if (!_atNewLine)
101: newline();
102:
103: indent();
104: _buffer.append("{");
105: newline();
106:
107: _nestingDepth++;
108: }
109:
110: /**
111: * Ends the current block. Emits a "}", propertly indented, on a new line.
112: */
113: public void end() {
114: if (!_atNewLine)
115: newline();
116:
117: // TODO: Could check here if nesting depth goes below zero.
118:
119: _nestingDepth--;
120:
121: indent();
122: _buffer.append("}");
123:
124: newline();
125: }
126:
127: private void indent() {
128: if (_atNewLine) {
129: for (int i = 0; i < _nestingDepth; i++)
130: _buffer.append(INDENT);
131:
132: _atNewLine = false;
133: }
134: }
135:
136: /**
137: * Returns the current contents of the buffer. This value is often passed to methods such as
138: * {@link org.apache.tapestry.ioc.services.ClassFab#addConstructor(Class[], Class[], String)} or
139: * {@link org.apache.tapestry.ioc.services.ClassFab#addMethod(int, MethodSignature, String)}.
140: * <p>
141: * A BodyBuilder can be used again after invoking toString(), typically by invoking
142: * {@link #clear()}.
143: */
144: @Override
145: public String toString() {
146: return _buffer.toString();
147: }
148: }
|