001 // Copyright 2006, 2007, 2008, 2011 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.tapestry5.ioc.util;
016
017 import java.util.Formatter;
018
019 import org.apache.tapestry5.ioc.services.MethodSignature;
020
021 /**
022 * Utility class for assembling the <em>body</em> used with Javassist when defining a method or constructor. Basically,
023 * assists with formatting and with indentation. This makes the code that assembles a method body much simpler ... and
024 * it makes the result neater, which will be easier to debug (debugging dynamically generated code is hard enough that
025 * it should be easy to read the input code before worrying about why it doesn't compile or execute properly).
026 * <p/>
027 * This class is not threadsafe.
028 * <p/>
029 * Most of the methods return the BodyBuilder, to form a fluent interface.
030 *
031 * @deprecated In 5.3/0, to be removed in a later release
032 */
033 public final class BodyBuilder
034 {
035 /**
036 * Feels right for the size of a typical body.
037 */
038 private static final int DEFAULT_LENGTH = 200;
039
040 private static final String INDENT = " ";
041
042 private final StringBuilder buffer = new StringBuilder(DEFAULT_LENGTH);
043
044 private final Formatter formatter = new Formatter(buffer);
045
046 // Per level of nesting depth (two spaces).
047
048 private int nestingDepth = 0;
049
050 private boolean atNewLine = true;
051
052 /**
053 * Clears the builder, returning it to its initial, empty state.
054 */
055 public BodyBuilder clear()
056 {
057 nestingDepth = 0;
058 atNewLine = true;
059 buffer.setLength(0);
060
061 return this;
062 }
063
064 /**
065 * Adds text to the current line, without ending the line.
066 *
067 * @param format
068 * string format, as per {@link java.util.Formatter}
069 * @param args
070 * arguments referenced by format specifiers
071 */
072 public BodyBuilder add(String format, Object... args)
073 {
074 add(format, args, false);
075
076 return this;
077 }
078
079 /**
080 * Adds text to the current line and ends the line.
081 *
082 * @param format
083 * string format, as per {@link java.util.Formatter}
084 * @param args
085 * arguments referenced by format specifiers
086 */
087 public BodyBuilder addln(String format, Object... args)
088 {
089 add(format, args, true);
090
091 return this;
092 }
093
094 private BodyBuilder add(String format, Object[] args, boolean newLine)
095 {
096 indent();
097
098 // Format output, send to buffer
099
100 formatter.format(format, args);
101
102 if (newLine)
103 newline();
104
105 return this;
106 }
107
108 private void newline()
109 {
110 buffer.append("\n");
111 atNewLine = true;
112 }
113
114 /**
115 * Begins a new block. Emits a "{", properly indented, on a new line.
116 */
117 public BodyBuilder begin()
118 {
119 if (!atNewLine)
120 newline();
121
122 indent();
123 buffer.append("{");
124 newline();
125
126 nestingDepth++;
127
128 return this;
129 }
130
131 /**
132 * Ends the current block. Emits a "}", propertly indented, on a new line.
133 */
134 public BodyBuilder end()
135 {
136 if (!atNewLine)
137 newline();
138
139 // TODO: Could check here if nesting depth goes below zero.
140
141 nestingDepth--;
142
143 indent();
144 buffer.append("}");
145
146 newline();
147
148 return this;
149 }
150
151 private void indent()
152 {
153 if (atNewLine)
154 {
155 for (int i = 0; i < nestingDepth; i++)
156 buffer.append(INDENT);
157
158 atNewLine = false;
159 }
160 }
161
162 /**
163 * Returns the current contents of the buffer. This value is often passed to methods such as
164 * {@link org.apache.tapestry5.ioc.services.ClassFab#addConstructor(Class[], Class[], String)} or
165 * {@link org.apache.tapestry5.ioc.services.ClassFab#addMethod(int, MethodSignature, String)}.
166 * <p/>
167 * A BodyBuilder can be used again after invoking toString(), typically by invoking {@link #clear()}.
168 */
169 @Override
170 public String toString()
171 {
172 return buffer.toString();
173 }
174 }