    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    }