KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > sun > org > apache > xml > internal > serializer > SerializerTraceWriter


1 /*
2  * Copyright 2003-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: SerializerTraceWriter.java,v 1.2 2004/02/17 04:18:18 minchau Exp $
18  */

19 package com.sun.org.apache.xml.internal.serializer;
20
21 import java.io.IOException JavaDoc;
22 import java.io.Writer JavaDoc;
23
24 /**
25  * This class wraps the real writer, it only purpose is to send
26  * CHARACTERTOSTREAM events to the trace listener.
27  * Each method immediately sends the call to the wrapped writer unchanged, but
28  * in addition it collects characters to be issued to a trace listener.
29  *
30  * In this way the trace
31  * listener knows what characters have been written to the output Writer.
32  *
33  * There may still be differences in what the trace events say is going to the
34  * output writer and what is really going there. These differences will be due
35  * to the fact that this class is UTF-8 encoding before emiting the trace event
36  * and the underlying writer may not be UTF-8 encoding. There may also be
37  * encoding differences. So the main pupose of this class is to provide a
38  * resonable facsimile of the true output.
39  *
40  */

41 public class SerializerTraceWriter extends Writer JavaDoc
42 {
43
44     /** The real writer to immediately write to.
45      * This reference may be null, in which case nothing is written out, but
46      * only the trace events are fired for output.
47      */

48     private final java.io.Writer JavaDoc m_writer;
49
50     /** The tracer to send events to */
51     private final SerializerTrace m_tracer;
52
53     /** The size of the internal buffer, just to keep too many
54      * events from being sent to the tracer
55      */

56     private int buf_length;
57
58     /**
59      * Internal buffer to collect the characters to go to the trace listener.
60      *
61      */

62     private byte buf[];
63
64     /**
65      * How many bytes have been collected and still need to go to trace
66      * listener.
67      */

68     private int count;
69
70     /**
71      * Creates or replaces the internal buffer, and makes sure it has a few
72      * extra bytes slight overflow of the last UTF8 encoded character.
73      * @param size
74      */

75     private void setBufferSize(int size)
76     {
77         buf = new byte[size + 3];
78         buf_length = size;
79         count = 0;
80     }
81
82     /**
83      * Constructor.
84      * If the writer passed in is null, then this SerializerTraceWriter will
85      * only signal trace events of what would have been written to that writer.
86      * If the writer passed in is not null then the trace events will mirror
87      * what is going to that writer. In this way tools, such as a debugger, can
88      * gather information on what is being written out.
89      *
90      * @param out the Writer to write to (possibly null)
91      * @param tracer the tracer to inform that characters are being written
92      */

93     public SerializerTraceWriter(Writer JavaDoc out, SerializerTrace tracer)
94     {
95         m_writer = out;
96         m_tracer = tracer;
97         setBufferSize(1024);
98     }
99
100     /**
101      * Flush out the collected characters by sending them to the trace
102      * listener. These characters are never written to the real writer
103      * (m_writer) because that has already happened with every method
104      * call. This method simple informs the listener of what has already
105      * happened.
106      * @throws IOException
107      */

108     private void flushBuffer() throws IOException JavaDoc
109     {
110
111         // Just for tracing purposes
112
if (count > 0)
113         {
114             char[] chars = new char[count];
115             for(int i=0; i<count; i++)
116                 chars[i] = (char) buf[i];
117
118             if (m_tracer != null)
119                 m_tracer.fireGenerateEvent(
120                     SerializerTrace.EVENTTYPE_OUTPUT_CHARACTERS,
121                     chars,
122                     0,
123                     chars.length);
124
125             count = 0;
126         }
127     }
128
129     /**
130      * Flush the internal buffer and flush the Writer
131      * @see java.io.Writer#flush()
132      */

133     public void flush() throws java.io.IOException JavaDoc
134     {
135         // send to the real writer
136
if (m_writer != null)
137             m_writer.flush();
138
139         // from here on just for tracing purposes
140
flushBuffer();
141     }
142
143     /**
144      * Flush the internal buffer and close the Writer
145      * @see java.io.Writer#close()
146      */

147     public void close() throws java.io.IOException JavaDoc
148     {
149         // send to the real writer
150
if (m_writer != null)
151             m_writer.close();
152
153         // from here on just for tracing purposes
154
flushBuffer();
155     }
156
157
158     /**
159      * Write a single character. The character to be written is contained in
160      * the 16 low-order bits of the given integer value; the 16 high-order bits
161      * are ignored.
162      *
163      * <p> Subclasses that intend to support efficient single-character output
164      * should override this method.
165      *
166      * @param c int specifying a character to be written.
167      * @exception IOException If an I/O error occurs
168      */

169     public void write(final int c) throws IOException JavaDoc
170     {
171         // send to the real writer
172
if (m_writer != null)
173             m_writer.write(c);
174
175         // ---------- from here on just collect for tracing purposes
176

177         /* If we are close to the end of the buffer then flush it.
178          * Remember the buffer can hold a few more characters than buf_length
179          */

180         if (count >= buf_length)
181             flushBuffer();
182
183         if (c < 0x80)
184         {
185             buf[count++] = (byte) (c);
186         }
187         else if (c < 0x800)
188         {
189             buf[count++] = (byte) (0xc0 + (c >> 6));
190             buf[count++] = (byte) (0x80 + (c & 0x3f));
191         }
192         else
193         {
194             buf[count++] = (byte) (0xe0 + (c >> 12));
195             buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
196             buf[count++] = (byte) (0x80 + (c & 0x3f));
197         }
198     }
199
200     /**
201      * Write a portion of an array of characters.
202      *
203      * @param chars Array of characters
204      * @param start Offset from which to start writing characters
205      * @param length Number of characters to write
206      *
207      * @exception IOException If an I/O error occurs
208      *
209      * @throws java.io.IOException
210      */

211     public void write(final char chars[], final int start, final int length)
212         throws java.io.IOException JavaDoc
213     {
214         // send to the real writer
215
if (m_writer != null)
216             m_writer.write(chars, start, length);
217
218         // from here on just collect for tracing purposes
219
int lengthx3 = (length << 1) + length;
220
221         if (lengthx3 >= buf_length)
222         {
223
224             /* If the request length exceeds the size of the output buffer,
225               * flush the output buffer and make the buffer bigger to handle.
226               */

227
228             flushBuffer();
229             setBufferSize(2 * lengthx3);
230
231         }
232
233         if (lengthx3 > buf_length - count)
234         {
235             flushBuffer();
236         }
237
238         final int n = length + start;
239         for (int i = start; i < n; i++)
240         {
241             final char c = chars[i];
242
243             if (c < 0x80)
244                 buf[count++] = (byte) (c);
245             else if (c < 0x800)
246             {
247                 buf[count++] = (byte) (0xc0 + (c >> 6));
248                 buf[count++] = (byte) (0x80 + (c & 0x3f));
249             }
250             else
251             {
252                 buf[count++] = (byte) (0xe0 + (c >> 12));
253                 buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
254                 buf[count++] = (byte) (0x80 + (c & 0x3f));
255             }
256         }
257
258     }
259
260     /**
261      * Write a string.
262      *
263      * @param s String to be written
264      *
265      * @exception IOException If an I/O error occurs
266      */

267     public void write(final String JavaDoc s) throws IOException JavaDoc
268     {
269         // send to the real writer
270
if (m_writer != null)
271             m_writer.write(s);
272
273         // from here on just collect for tracing purposes
274
final int length = s.length();
275
276         // We multiply the length by three since this is the maximum length
277
// of the characters that we can put into the buffer. It is possible
278
// for each Unicode character to expand to three bytes.
279

280         int lengthx3 = (length << 1) + length;
281
282         if (lengthx3 >= buf_length)
283         {
284
285             /* If the request length exceeds the size of the output buffer,
286               * flush the output buffer and make the buffer bigger to handle.
287               */

288
289             flushBuffer();
290             setBufferSize(2 * lengthx3);
291         }
292
293         if (lengthx3 > buf_length - count)
294         {
295             flushBuffer();
296         }
297
298         for (int i = 0; i < length; i++)
299         {
300             final char c = s.charAt(i);
301
302             if (c < 0x80)
303                 buf[count++] = (byte) (c);
304             else if (c < 0x800)
305             {
306                 buf[count++] = (byte) (0xc0 + (c >> 6));
307                 buf[count++] = (byte) (0x80 + (c & 0x3f));
308             }
309             else
310             {
311                 buf[count++] = (byte) (0xe0 + (c >> 12));
312                 buf[count++] = (byte) (0x80 + ((c >> 6) & 0x3f));
313                 buf[count++] = (byte) (0x80 + (c & 0x3f));
314             }
315         }
316     }
317
318 }
319
Popular Tags