KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cocoon > components > serializers > EncodingSerializer


1 /*
2  * Copyright 1999-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 package org.apache.cocoon.components.serializers;
17
18 import java.io.IOException JavaDoc;
19 import java.io.OutputStream JavaDoc;
20 import java.io.OutputStreamWriter JavaDoc;
21 import java.io.UnsupportedEncodingException JavaDoc;
22 import java.util.Arrays JavaDoc;
23
24 import org.apache.avalon.excalibur.pool.Recyclable;
25 import org.apache.avalon.framework.configuration.Configurable;
26 import org.apache.avalon.framework.configuration.Configuration;
27 import org.apache.avalon.framework.configuration.ConfigurationException;
28 import org.apache.cocoon.components.serializers.encoding.Charset;
29 import org.apache.cocoon.components.serializers.encoding.CharsetFactory;
30 import org.apache.cocoon.components.serializers.encoding.Encoder;
31 import org.apache.cocoon.components.serializers.util.Namespaces;
32 import org.apache.cocoon.serialization.Serializer;
33 import org.apache.commons.lang.SystemUtils;
34 import org.xml.sax.Attributes JavaDoc;
35 import org.xml.sax.Locator JavaDoc;
36 import org.xml.sax.SAXException JavaDoc;
37
38 /**
39  *
40  *
41  * @author <a HREF="mailto:pier@apache.org">Pier Fumagalli</a>, February 2003
42  * @version CVS $Id: EncodingSerializer.java 54845 2004-10-15 10:52:09Z cziegeler $
43  */

44 public abstract class EncodingSerializer implements Serializer, Locator JavaDoc, Recyclable, Configurable {
45
46     /** The line separator string */
47     private static final char S_EOL[] = SystemUtils.LINE_SEPARATOR.toCharArray();
48
49     /* ====================================================================== */
50
51     /** The position of the namespace URI in the attributes array. */
52     public static final int ATTRIBUTE_NSURI = 0;
53
54     /** The position of the local name in the attributes array. */
55     public static final int ATTRIBUTE_LOCAL = 1;
56
57     /** The position of the qualified name in the attributes array. */
58     public static final int ATTRIBUTE_QNAME = 2;
59
60     /** The position of the value in the attributes array. */
61     public static final int ATTRIBUTE_VALUE = 3;
62
63     /** The length of the array of strings representing an attribute. */
64     public static final int ATTRIBUTE_LENGTH = 4;
65
66     /* ====================================================================== */
67
68     /** Our <code>Encoder</code> instance. */
69     private Encoder encoder = null;
70     
71     /** Our <code>Locator</code> instance. */
72     private Locator JavaDoc locator = null;
73
74     /** Our <code>Writer</code> instance. */
75     private OutputStreamWriter JavaDoc out = null;
76
77     /** Flag indicating if the document prolog is being processed. */
78     private boolean prolog = true;
79
80     /** Flag indicating if the document is being processed. */
81     private boolean processing = false;
82
83     /** Current nesting level */
84     private int level = 0;
85
86     /** Whitespace buffer for indentation */
87     private char[] indentBuffer = null;
88
89     /* ====================================================================== */
90
91     /** The <code>Charset</code> associated with the character encoding. */
92     protected Charset charset = null;
93
94     /** The <code>Namespace</code> associated with this instance. */
95     protected Namespaces namespaces = new Namespaces();
96
97     /** Per level indent spaces */
98     protected int indentPerLevel = 0;
99     /* ====================================================================== */
100
101     /**
102      * Create a new instance of this <code>EncodingSerializer</code>
103      */

104     protected EncodingSerializer(Encoder encoder) {
105         super();
106         this.encoder = encoder;
107         this.recycle();
108     }
109     
110     /* ====================================================================== */
111
112     /**
113      * Test if the component wants to set the content length.
114      */

115     public boolean shouldSetContentLength() {
116         return(false);
117     }
118
119     /**
120      * Reset this <code>EncodingSerializer</code>.
121      */

122     public void recycle() {
123         if (processing) throw new IllegalStateException JavaDoc();
124         this.namespaces = new Namespaces();
125         this.locator = null;
126         this.out = null;
127         this.prolog = true;
128     }
129
130     /**
131      * Set the <code>OutputStream</code> where this serializer will
132      * write data to.
133      *
134      * @param out The <code>OutputStream</code> used for output.
135      */

136     public void setOutputStream(OutputStream JavaDoc out)
137     throws IOException JavaDoc {
138         if (out == null) throw new NullPointerException JavaDoc("Null output");
139         
140         this.out = new OutputStreamWriter JavaDoc(out, this.charset.getName());
141     }
142
143     /**
144      * Set the configurations for this serializer.
145      */

146     public void configure(Configuration conf)
147     throws ConfigurationException {
148         String JavaDoc encoding = conf.getChild("encoding").getValue(null);
149         try {
150             this.charset = CharsetFactory.newInstance().getCharset(encoding);
151         } catch (UnsupportedEncodingException JavaDoc exception) {
152             throw new ConfigurationException("Encoding not supported: "
153                                              + encoding, exception);
154         }
155
156         indentPerLevel = conf.getChild("indent").getValueAsInteger(0);
157         if (indentPerLevel > 0) {
158             assureIndentBuffer(indentPerLevel * 6);
159         }
160     }
161
162     /* ====================================================================== */
163     
164     private char[] assureIndentBuffer( int size ) {
165         if (indentBuffer == null || indentBuffer.length < size) {
166             indentBuffer = new char[size];
167             Arrays.fill(indentBuffer,' ');
168         }
169         return indentBuffer;
170     }
171
172     /**
173      * Encode and write a <code>String</code>
174      */

175     protected void encode(String JavaDoc data)
176     throws SAXException JavaDoc {
177         char array[] = data.toCharArray();
178         this.encode(array, 0, array.length);
179     }
180     
181     /**
182      * Encode and write an array of characters.
183      */

184     protected void encode(char data[])
185     throws SAXException JavaDoc {
186         this.encode(data, 0, data.length);
187     }
188     
189     /**
190      * Encode and write a specific part of an array of characters.
191      */

192     protected void encode(char data[], int start, int length)
193     throws SAXException JavaDoc {
194         int end = start + length;
195         
196         if (data == null) throw new NullPointerException JavaDoc("Null data");
197         if ((start < 0) || (start > data.length) || (length < 0) ||
198             (end > data.length) || (end < 0))
199             throw new IndexOutOfBoundsException JavaDoc("Invalid data");
200         if (length == 0) return;
201         
202         for (int x = start; x < end; x++) {
203             char c = data[x];
204             
205             if (this.charset.allows(c) && this.encoder.allows(c)) {
206                 continue;
207             }
208             
209             if (start != x) this.write(data, start, x - start );
210             this.write(this.encoder.encode(c));
211             start = x + 1;
212             continue;
213         }
214         if (start != end) this.write(data, start, end - start );
215     }
216
217     /* ====================================================================== */
218
219     /**
220      * Receive an object for locating the origin of SAX document events.
221      */

222     public final void setDocumentLocator(Locator JavaDoc locator) {
223         this.locator = locator;
224     }
225
226     /**
227      * Return the public identifier for the current document event.
228      *
229      * @return A <code>String</code> containing the public identifier,
230      * or <b>null</b> if none is available.
231      */

232     public String JavaDoc getPublicId() {
233         return(this.locator == null? null: this.locator.getPublicId());
234     }
235
236     /**
237      * Return the system identifier for the current document event.
238      *
239      * @return A <code>String</code> containing the system identifier,
240      * or <b>null</b> if none is available.
241      */

242     public String JavaDoc getSystemId() {
243         return(this.locator == null? null: this.locator.getSystemId());
244     }
245     
246     /**
247      * Return the line number where the current document event ends.
248      *
249      * @return The line number, or -1 if none is available.
250      */

251     public int getLineNumber() {
252         return(this.locator == null? -1: this.locator.getLineNumber());
253     }
254
255     /**
256      * Return the column number where the current document event ends.
257      *
258      * @return The column number, or -1 if none is available.
259      */

260     public int getColumnNumber() {
261         return(this.locator == null? -1: this.locator.getColumnNumber());
262     }
263
264     /**
265      * Return a <code>String</code> describing the current location.
266      */

267     protected String JavaDoc getLocation() {
268         if (this.locator == null) return("");
269         StringBuffer JavaDoc buf = new StringBuffer JavaDoc(" (");
270         if (this.getSystemId() != null) {
271             buf.append(this.getSystemId());
272             buf.append(' ');
273         }
274         buf.append("line " + this.getLineNumber());
275         buf.append(" col " + this.getColumnNumber());
276         buf.append(')');
277         return(buf.toString());
278     }
279
280     /* ====================================================================== */
281
282     /**
283      * Flush the stream.
284      */

285     protected void flush()
286     throws SAXException JavaDoc {
287         try {
288             this.out.flush();
289         } catch (IOException JavaDoc e) {
290             throw new SAXException JavaDoc("I/O error flushing: " + e.getMessage(), e);
291         }
292     }
293
294     /**
295      * Write an array of characters.
296      */

297     protected void write(char data[])
298     throws SAXException JavaDoc {
299         try {
300             this.out.write(data, 0, data.length);
301         } catch (IOException JavaDoc e) {
302             throw new SAXException JavaDoc("I/O error writing: " + e.getMessage(), e);
303         }
304     }
305
306     /**
307      * Write a portion of an array of characters.
308      */

309     protected void write(char data[], int start, int length)
310     throws SAXException JavaDoc {
311         try {
312             this.out.write(data, start, length);
313         } catch (IOException JavaDoc e) {
314             throw new SAXException JavaDoc("I/O error writing: " + e.getMessage(), e);
315         }
316     }
317
318     /**
319      * Write a single character.
320      */

321     protected void write(int c)
322     throws SAXException JavaDoc {
323         try {
324             this.out.write(c);
325         } catch (IOException JavaDoc e) {
326             throw new SAXException JavaDoc("I/O error writing: " + e.getMessage(), e);
327         }
328     }
329
330     /**
331      * Write a string.
332      */

333     protected void write(String JavaDoc data)
334     throws SAXException JavaDoc {
335         try {
336             this.out.write(data);
337         } catch (IOException JavaDoc e) {
338             throw new SAXException JavaDoc("I/O error writing: " + e.getMessage(), e);
339         }
340     }
341
342     /**
343      * Write a portion of a string.
344      */

345     protected void write(String JavaDoc data, int start, int length)
346     throws SAXException JavaDoc {
347         try {
348             this.out.write(data, start, length);
349         } catch (IOException JavaDoc e) {
350             throw new SAXException JavaDoc("I/O error writing: " + e.getMessage(), e);
351         }
352     }
353
354     /**
355      * Write a end-of-line character.
356      */

357     protected void writeln()
358     throws SAXException JavaDoc {
359         try {
360             this.out.write(S_EOL);
361         } catch (IOException JavaDoc e) {
362             throw new SAXException JavaDoc("I/O error writing: " + e.getMessage(), e);
363         }
364     }
365
366     /**
367      * Write a string and a end-of-line character.
368      */

369     protected void writeln(String JavaDoc data)
370     throws SAXException JavaDoc {
371         try {
372             this.out.write(data);
373             this.out.write(S_EOL);
374         } catch (IOException JavaDoc e) {
375             throw new SAXException JavaDoc("I/O error writing: " + e.getMessage(), e);
376         }
377     }
378
379     /**
380      * Write out character to indent the output according
381      * to the level of nesting
382      * @param indent
383      * @throws SAXException
384      */

385     protected void writeIndent(int indent) throws SAXException JavaDoc {
386         this.charactersImpl("\n".toCharArray(),0,1);
387         if (indent > 0) {
388             this.charactersImpl(assureIndentBuffer(indent),0,indent);
389         }
390     }
391
392     /* ====================================================================== */
393
394     /**
395      * Receive notification of the beginning of a document.
396      */

397     public void startDocument()
398     throws SAXException JavaDoc {
399         this.processing = true;
400         this.level = 0;
401     }
402
403     /**
404      * Receive notification of the end of a document.
405      */

406     public void endDocument()
407     throws SAXException JavaDoc {
408         this.processing = false;
409         this.flush();
410     }
411
412     /**
413      * Begin the scope of a prefix-URI Namespace mapping.
414      */

415     public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
416     throws SAXException JavaDoc {
417         this.namespaces.push(prefix, uri);
418     }
419
420     /**
421      * End the scope of a prefix-URI mapping.
422      */

423     public void endPrefixMapping(String JavaDoc prefix)
424     throws SAXException JavaDoc {
425         this.namespaces.pop(prefix);
426     }
427
428     /**
429      * Receive notification of the beginning of an element.
430      */

431     public void startElement(String JavaDoc nsuri, String JavaDoc local, String JavaDoc qual,
432                                    Attributes JavaDoc attributes)
433     throws SAXException JavaDoc {
434         if (indentPerLevel > 0) {
435             this.writeIndent(indentPerLevel*level);
436             level++;
437         }
438
439         String JavaDoc name = this.namespaces.qualify(nsuri, local, qual);
440
441         if (this.prolog) {
442             this.body(nsuri, local, name);
443             this.prolog = false;
444         }
445
446         String JavaDoc ns[][] = this.namespaces.commit();
447
448         String JavaDoc at[][] = new String JavaDoc [attributes.getLength()][4];
449         for (int x = 0; x < at.length; x++) {
450             at[x][ATTRIBUTE_NSURI] = attributes.getURI(x);
451             at[x][ATTRIBUTE_LOCAL] = attributes.getLocalName(x);
452             at[x][ATTRIBUTE_QNAME] = namespaces.qualify(
453                             attributes.getURI(x),
454                             attributes.getLocalName(x),
455                             attributes.getQName(x));
456             at[x][ATTRIBUTE_VALUE] = attributes.getValue(x);
457         }
458
459         this.startElementImpl(nsuri, local, name, ns, at);
460     }
461
462     public void characters (char ch[], int start, int length)
463     throws SAXException JavaDoc {
464         if (indentPerLevel > 0) {
465             this.writeIndent(indentPerLevel*level + 1);
466         }
467         this.charactersImpl(ch, start, length);
468     }
469
470     /**
471      * Receive notification of the end of an element.
472      */

473     public void endElement(String JavaDoc nsuri, String JavaDoc local, String JavaDoc qual)
474     throws SAXException JavaDoc {
475         if (indentPerLevel > 0) {
476             level--;
477             this.writeIndent(indentPerLevel*level);
478         }
479
480         String JavaDoc name = this.namespaces.qualify(nsuri, local, qual);
481         this.endElementImpl(nsuri, local, name);
482     }
483
484     /**
485      * Receive notification of the beginning of the document body.
486      *
487      * @param uri The namespace URI of the root element.
488      * @param local The local name of the root element.
489      * @param qual The fully-qualified name of the root element.
490      */

491     public abstract void body(String JavaDoc uri, String JavaDoc local, String JavaDoc qual)
492     throws SAXException JavaDoc;
493
494     /**
495      * Receive notification of the beginning of an element.
496      *
497      * @param uri The namespace URI of the root element.
498      * @param local The local name of the root element.
499      * @param qual The fully-qualified name of the root element.
500      * @param namespaces An array of <code>String</code> objects containing
501      * the namespaces to be declared by this element.
502      * @param attributes An array of <code>String</code> objects containing
503      * all attributes of this element.
504      */

505     public abstract void startElementImpl(String JavaDoc uri, String JavaDoc local, String JavaDoc qual,
506                                   String JavaDoc namespaces[][], String JavaDoc attributes[][])
507     throws SAXException JavaDoc;
508
509     /**
510      * Receive character notifications
511      * @param ch
512      * @param start
513      * @param length
514      * @throws SAXException
515      */

516     public abstract void charactersImpl (char ch[], int start, int length)
517     throws SAXException JavaDoc;
518
519     /**
520      * Receive notification of the end of an element.
521      *
522      * @param uri The namespace URI of the root element.
523      * @param local The local name of the root element.
524      * @param qual The fully-qualified name of the root element.
525      */

526     public abstract void endElementImpl(String JavaDoc uri, String JavaDoc local, String JavaDoc qual)
527     throws SAXException JavaDoc;
528 }
529
Popular Tags