1 16 package org.apache.cocoon.components.serializers; 17 18 import java.io.IOException ; 19 import java.io.OutputStream ; 20 import java.io.OutputStreamWriter ; 21 import java.io.UnsupportedEncodingException ; 22 import java.util.Arrays ; 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 ; 35 import org.xml.sax.Locator ; 36 import org.xml.sax.SAXException ; 37 38 44 public abstract class EncodingSerializer implements Serializer, Locator , Recyclable, Configurable { 45 46 47 private static final char S_EOL[] = SystemUtils.LINE_SEPARATOR.toCharArray(); 48 49 50 51 52 public static final int ATTRIBUTE_NSURI = 0; 53 54 55 public static final int ATTRIBUTE_LOCAL = 1; 56 57 58 public static final int ATTRIBUTE_QNAME = 2; 59 60 61 public static final int ATTRIBUTE_VALUE = 3; 62 63 64 public static final int ATTRIBUTE_LENGTH = 4; 65 66 67 68 69 private Encoder encoder = null; 70 71 72 private Locator locator = null; 73 74 75 private OutputStreamWriter out = null; 76 77 78 private boolean prolog = true; 79 80 81 private boolean processing = false; 82 83 84 private int level = 0; 85 86 87 private char[] indentBuffer = null; 88 89 90 91 92 protected Charset charset = null; 93 94 95 protected Namespaces namespaces = new Namespaces(); 96 97 98 protected int indentPerLevel = 0; 99 100 101 104 protected EncodingSerializer(Encoder encoder) { 105 super(); 106 this.encoder = encoder; 107 this.recycle(); 108 } 109 110 111 112 115 public boolean shouldSetContentLength() { 116 return(false); 117 } 118 119 122 public void recycle() { 123 if (processing) throw new IllegalStateException (); 124 this.namespaces = new Namespaces(); 125 this.locator = null; 126 this.out = null; 127 this.prolog = true; 128 } 129 130 136 public void setOutputStream(OutputStream out) 137 throws IOException { 138 if (out == null) throw new NullPointerException ("Null output"); 139 140 this.out = new OutputStreamWriter (out, this.charset.getName()); 141 } 142 143 146 public void configure(Configuration conf) 147 throws ConfigurationException { 148 String encoding = conf.getChild("encoding").getValue(null); 149 try { 150 this.charset = CharsetFactory.newInstance().getCharset(encoding); 151 } catch (UnsupportedEncodingException 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 175 protected void encode(String data) 176 throws SAXException { 177 char array[] = data.toCharArray(); 178 this.encode(array, 0, array.length); 179 } 180 181 184 protected void encode(char data[]) 185 throws SAXException { 186 this.encode(data, 0, data.length); 187 } 188 189 192 protected void encode(char data[], int start, int length) 193 throws SAXException { 194 int end = start + length; 195 196 if (data == null) throw new NullPointerException ("Null data"); 197 if ((start < 0) || (start > data.length) || (length < 0) || 198 (end > data.length) || (end < 0)) 199 throw new IndexOutOfBoundsException ("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 222 public final void setDocumentLocator(Locator locator) { 223 this.locator = locator; 224 } 225 226 232 public String getPublicId() { 233 return(this.locator == null? null: this.locator.getPublicId()); 234 } 235 236 242 public String getSystemId() { 243 return(this.locator == null? null: this.locator.getSystemId()); 244 } 245 246 251 public int getLineNumber() { 252 return(this.locator == null? -1: this.locator.getLineNumber()); 253 } 254 255 260 public int getColumnNumber() { 261 return(this.locator == null? -1: this.locator.getColumnNumber()); 262 } 263 264 267 protected String getLocation() { 268 if (this.locator == null) return(""); 269 StringBuffer buf = new StringBuffer (" ("); 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 285 protected void flush() 286 throws SAXException { 287 try { 288 this.out.flush(); 289 } catch (IOException e) { 290 throw new SAXException ("I/O error flushing: " + e.getMessage(), e); 291 } 292 } 293 294 297 protected void write(char data[]) 298 throws SAXException { 299 try { 300 this.out.write(data, 0, data.length); 301 } catch (IOException e) { 302 throw new SAXException ("I/O error writing: " + e.getMessage(), e); 303 } 304 } 305 306 309 protected void write(char data[], int start, int length) 310 throws SAXException { 311 try { 312 this.out.write(data, start, length); 313 } catch (IOException e) { 314 throw new SAXException ("I/O error writing: " + e.getMessage(), e); 315 } 316 } 317 318 321 protected void write(int c) 322 throws SAXException { 323 try { 324 this.out.write(c); 325 } catch (IOException e) { 326 throw new SAXException ("I/O error writing: " + e.getMessage(), e); 327 } 328 } 329 330 333 protected void write(String data) 334 throws SAXException { 335 try { 336 this.out.write(data); 337 } catch (IOException e) { 338 throw new SAXException ("I/O error writing: " + e.getMessage(), e); 339 } 340 } 341 342 345 protected void write(String data, int start, int length) 346 throws SAXException { 347 try { 348 this.out.write(data, start, length); 349 } catch (IOException e) { 350 throw new SAXException ("I/O error writing: " + e.getMessage(), e); 351 } 352 } 353 354 357 protected void writeln() 358 throws SAXException { 359 try { 360 this.out.write(S_EOL); 361 } catch (IOException e) { 362 throw new SAXException ("I/O error writing: " + e.getMessage(), e); 363 } 364 } 365 366 369 protected void writeln(String data) 370 throws SAXException { 371 try { 372 this.out.write(data); 373 this.out.write(S_EOL); 374 } catch (IOException e) { 375 throw new SAXException ("I/O error writing: " + e.getMessage(), e); 376 } 377 } 378 379 385 protected void writeIndent(int indent) throws SAXException { 386 this.charactersImpl("\n".toCharArray(),0,1); 387 if (indent > 0) { 388 this.charactersImpl(assureIndentBuffer(indent),0,indent); 389 } 390 } 391 392 393 394 397 public void startDocument() 398 throws SAXException { 399 this.processing = true; 400 this.level = 0; 401 } 402 403 406 public void endDocument() 407 throws SAXException { 408 this.processing = false; 409 this.flush(); 410 } 411 412 415 public void startPrefixMapping(String prefix, String uri) 416 throws SAXException { 417 this.namespaces.push(prefix, uri); 418 } 419 420 423 public void endPrefixMapping(String prefix) 424 throws SAXException { 425 this.namespaces.pop(prefix); 426 } 427 428 431 public void startElement(String nsuri, String local, String qual, 432 Attributes attributes) 433 throws SAXException { 434 if (indentPerLevel > 0) { 435 this.writeIndent(indentPerLevel*level); 436 level++; 437 } 438 439 String 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 ns[][] = this.namespaces.commit(); 447 448 String at[][] = new String [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 { 464 if (indentPerLevel > 0) { 465 this.writeIndent(indentPerLevel*level + 1); 466 } 467 this.charactersImpl(ch, start, length); 468 } 469 470 473 public void endElement(String nsuri, String local, String qual) 474 throws SAXException { 475 if (indentPerLevel > 0) { 476 level--; 477 this.writeIndent(indentPerLevel*level); 478 } 479 480 String name = this.namespaces.qualify(nsuri, local, qual); 481 this.endElementImpl(nsuri, local, name); 482 } 483 484 491 public abstract void body(String uri, String local, String qual) 492 throws SAXException ; 493 494 505 public abstract void startElementImpl(String uri, String local, String qual, 506 String namespaces[][], String attributes[][]) 507 throws SAXException ; 508 509 516 public abstract void charactersImpl (char ch[], int start, int length) 517 throws SAXException ; 518 519 526 public abstract void endElementImpl(String uri, String local, String qual) 527 throws SAXException ; 528 } 529 | Popular Tags |