1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package Torello.Java.Additional;

import Torello.JavaDoc.JDHeaderBackgroundImg;

import java.io.IOException;

/**
 * An implementation of the standard Java <CODE>'Appendable'</CODE> interface that keeps an
 * internal log of all text-data that 'passes through' the <CODE>Appendable</CODE>.
 * 
 * <EMBED CLASS='external-html' DATA-FILE-ID=APPENDABLE_TAP>
 */
@JDHeaderBackgroundImg(EmbedTagFileID={"APPENDABLE_EXTENSION", "APPENDABLE_TAP_JDHBI"})
public class AppendableTap implements Appendable
{
    private Appendable outputAppendable;

    private StringBuffer sb = new StringBuffer();

    /**
     * Builds an instance of this class.  The provided instance of {@code Appendable}
     * will receive all {@code append()} invocations that are sent to {@code 'this'}
     * instance of {@code AppendTap}.  It is important to note that only the 
     * {@code append()} calls sent to <B>this</B> class first will be 'tapped' (logged
     * and kept in an internal {@code StringBuffer} instance).  Any invocations that are
     * made independently on the provided {@code Appendable} <I>will not be saved by this
     * class.</I>
     *
     * @param appendable This may be any java {@code Appendable}.  Any messages sent to this
     * class will be sent to this input {@code Appendable} as well.
     */
    public AppendableTap(Appendable appendable)
    { this.outputAppendable = appendable; }

    /**
     * Logs input-parameter character {@code 'c'} to an internal {@code StringBuffer}, and then
     * subsequently sends {@code 'c'} to the user-provided {@code Appendable}.
     *
     * @param c Any character data.
     *
     * @return {@code 'this'} instance of {@code AppendableTap} shall be returned, for convenience.
     */
    public synchronized Appendable append(char c) throws IOException
    {
        sb.append(c); 
        return outputAppendable.append(c);
    }

    /**
     * Logs input-parameter {@code CharSequence 's'} to an internal {@code StringBuffer}, and
     * then subsequently sends {@code 's'} to the user-provided {@code Appendable}.
     *
     * @param s Any {@code String} data.
     *
     * @return {@code 'this'} instance of {@code AppendableTap} shall be returned, for convenience.
     */
    public synchronized Appendable append(CharSequence s) throws IOException
    {
        sb.append(s);
        return outputAppendable.append(s);
    }

    /**
     * Logs a substring of input-parameter {@code CharSequence 's'} defined by the {@code int}
     * parameters {@code 'start'} and {@code 'end'}.
     * 
     * This operation would be equivalent to calling the {@code String} method
     * {@code String.substring(start, end)} on the input {@code CharSequence} prior to logging
     * this character data, and sending it to the user-provided {@code Appendable}.
     *
     * @param s This may be any Java {@code CharSequence}
     *
     * @param start The first character (inclusive) in the sub-string / sub-sequence of the input 
     * {@code CharSequence} to log, and pass-on.
     *
     * @param end The last character (exclusive) of the input sub-string / sub-sequence of the
     * {@code CharSequence} to log, and pass-on.
     *
     * @return {@code 'this'} instance of {@code AppendableTap} shall be returned, for convenience.
     */
    public synchronized Appendable append(CharSequence s, int start, int end) throws IOException
    { 
        sb.append(s, start, end); 
        return outputAppendable.append(s, start, end);
    }

    /**
     * Retrieves the text-data that has been sent to this {@code AppendableTap}
     * 
     * <BR /><BR /><B>NOTE:</B> Invoking this method has no effect on the underlying
     * output (user-provided - at construction time) {@code Appendable}.
     *
     * @return Any character or text data that has been received by {@code 'this'} instance
     * of {@code AppendableTap} through any of its {@code append(...)} methods.
     */
    public synchronized String getString()
    {
        String s = sb.toString();
        sb.setLength(0);
        sb.append(s);
        return s;
    }

    /**
     * Resets or 'clears' the contents of the internal {@code StringBuffer} 'tap', and returns
     * the contents that were saved.
     * @return Returns the contents of the internal storage, and clears the contents.
     */
    public synchronized String poll()
    {
        String s = sb.toString();
        sb.setLength(0);
        return s;
    }

    /** Clears the 'tap' of all contents */
    public synchronized void clear() { sb.setLength(0); }
}