1 9 package javolution.xml; 10 11 import j2me.lang.CharSequence; 12 import j2me.nio.ByteBuffer; 13 14 import java.io.IOException; 15 import java.io.OutputStream; 16 import java.io.Writer; 17 18 import org.xml.sax.SAXException; 19 20 import javolution.io.Utf8ByteBufferWriter; 21 import javolution.io.Utf8StreamWriter; 22 import javolution.lang.PersistentReference; 23 import javolution.lang.Reusable; 24 import javolution.lang.Text; 25 import javolution.lang.TextBuilder; 26 import javolution.realtime.ObjectFactory; 27 import javolution.util.FastComparator; 28 import javolution.util.FastList; 29 import javolution.util.FastMap; 30 import javolution.util.FastTable; 31 import javolution.xml.sax.ContentHandler; 32 import javolution.xml.sax.WriterHandler; 33 34 72 public class ObjectWriter implements Reusable { 73 74 77 private static final PersistentReference CDATA_SIZE = new PersistentReference( 78 "javolution.xml.ObjectWriter#CDATA_SIZE", new Integer(256)); 79 80 83 private static final Text J = Text.valueOf("j").intern(); 84 85 88 private static final Text XMLNS_J = Text.valueOf("xmlns:j").intern(); 89 90 93 private static final Text XMLNS = Text.valueOf("xmlns").intern(); 94 95 98 private static final Text XMLNS_URI = Text.valueOf( 99 "http://www.w3.org/2000/xmlns/").intern(); 100 101 104 public static final Text JAVOLUTION_URI = Text.valueOf( 105 "http://javolution.org").intern(); 106 107 110 private static final Text JAVA_ = Text.valueOf("java:").intern(); 111 112 115 private static final Text CLASS = Text.valueOf("class").intern(); 116 117 120 private static final Text J_CLASS = Text.valueOf("j:class").intern(); 121 122 128 public static int OUTPUT_JCLASS = 0x01; 129 130 135 public static int OUTPUT_XMLNS = 0x02; 136 137 141 public static int NO_IDENTIFIER = 0x04; 142 143 150 public static int EXPAND_REFERENCES = 0x08; 151 152 155 public static int DEFAULT_FEATURES = 0; 156 157 160 private FastList _namespaces = new FastList(); 161 162 165 private int _features = DEFAULT_FEATURES; 166 167 170 private CharSequence _rootName; 171 172 175 private String _defaultPkg = ""; 176 177 180 private final FastMap _classInfo = new FastMap(); 181 182 185 private final FastTable _stack = new FastTable(); 186 187 190 private final Utf8StreamWriter _utf8StreamWriter = new Utf8StreamWriter(); 191 192 195 private final Utf8ByteBufferWriter _utf8ByteBufferWriter = new Utf8ByteBufferWriter(); 196 197 200 private final WriterHandler _writerHandler = new WriterHandler(); 201 202 205 private char[] _cdata = (char[]) new char[((Integer) CDATA_SIZE.get()) 206 .intValue()]; 207 208 211 private final FastMap _objectToId = new FastMap() 212 .setKeyComparator(FastComparator.IDENTITY); 213 214 217 private int _idCount; 218 219 222 public ObjectWriter() { 223 _stack.addLast(new XmlElement()); 224 } 225 226 242 public void setNamespace(String prefix, String packageName) { 243 if (prefix.equals("j")) 244 throw new IllegalArgumentException("Prefix: \"j\" is reserved."); 245 if (prefix.length() == 0) { _defaultPkg = packageName; 247 } 248 _namespaces.addLast(prefix); 249 _namespaces.addLast(packageName); 250 } 251 252 257 public void setFeature(int features) { 258 _features = features; 259 } 260 261 267 public void setRootName(CharSequence rootName) { 268 _rootName = rootName; 269 } 270 271 281 public void write(Objectobj, Writer writer) throws IOException { 282 try { 283 _writerHandler.setWriter(writer); 284 write(obj, _writerHandler); 285 } catch (SAXException e) { 286 if (e.getException() instanceof IOException) { 287 throw (IOException) e.getException(); 288 } 289 } finally { 290 _writerHandler.reset(); 291 } 292 } 293 294 305 public void write(Objectobj, OutputStream out) throws IOException { 306 try { 307 _utf8StreamWriter.setOutputStream(out); 308 _writerHandler.setWriter(_utf8StreamWriter); 309 write(obj, _writerHandler); 310 } catch (SAXException e) { 311 if (e.getException() instanceof IOException) { 312 throw (IOException) e.getException(); 313 } 314 } finally { 315 _utf8StreamWriter.reset(); 316 _writerHandler.reset(); 317 } 318 } 319 320 328 public void write(Objectobj, ByteBuffer byteBuffer) 329 throws IOException { 330 try { 331 _utf8ByteBufferWriter.setByteBuffer(byteBuffer); 332 _writerHandler.setWriter(_utf8ByteBufferWriter); 333 write(obj, _writerHandler); 334 } catch (SAXException e) { 335 if (e.getException() instanceof IOException) { 336 throw (IOException) e.getException(); 337 } 338 } finally { 339 _utf8ByteBufferWriter.reset(); 340 _writerHandler.reset(); 341 } 342 } 343 344 351 public void write(Objectobj, ContentHandler handler) 352 throws SAXException { 353 handler.startDocument(); 354 try { 355 handler.startPrefixMapping(J, JAVOLUTION_URI); 356 for (FastList.Node n = _namespaces.headNode(), end = _namespaces 357 .tailNode(); (n = n.getNextNode()) != end;) { 358 Object prefix = n.getValue(); 359 String pkg = (String) (n = n.getNextNode()).getValue(); 360 Text uri = JAVA_.concat(Text.valueOf(pkg)); 361 handler.startPrefixMapping(toCharSeq(prefix), uri); 362 } 363 writeElement(obj, handler, 0, _rootName); 364 } finally { 365 handler.endPrefixMapping(J); 366 for (FastList.Node n = _namespaces.headNode(), end = _namespaces 367 .tailNode(); (n = n.getNextNode()) != end;) { 368 Object prefix = n.getValue(); 369 n = n.getNextNode(); handler.endPrefixMapping(toCharSeq(prefix)); 371 } 372 handler.endDocument(); 373 } 374 } 375 376 private void writeElement(Object obj, ContentHandler handler, int level, 377 CharSequence tagName) throws SAXException { 378 379 if (obj == null) { 381 writeElement(XmlFormat.NULL, handler, level, null); 382 return; 383 } 384 385 if (obj instanceof CharacterData) { 387 CharacterData charData = (CharacterData) obj; 388 final int length = charData.length(); 389 if (length > _cdata.length) { char[] tmp = new char[_cdata.length * 2]; 391 System.arraycopy(_cdata, 0, tmp, 0, _cdata.length); 392 _cdata = tmp; 393 CDATA_SIZE.set(new Integer(_cdata.length)); 394 } 395 charData.getChars(0, length, _cdata, 0); 396 handler.characters(_cdata, 0, length); 397 return; 398 } 399 400 Class clazz = obj.getClass(); 402 ClassInfo ci = (ClassInfo) _classInfo.get(clazz); 403 if (ci == null) { ci = (ClassInfo) ClassInfo.FACTORY.newObject(); 405 _classInfo.put(clazz, ci); 406 } 407 if (ci.format == null) { 408 ci.className = clazz.getName(); 409 ci.alias = XmlFormat.nameFor(clazz); 410 ci.format = XmlFormat.getInstance(clazz); 411 412 String prefix = null; 414 String pkg = ""; 415 for (FastList.Node n = _namespaces.headNode(), end = _namespaces 416 .tailNode(); (n = n.getNextNode()) != end;) { 417 String pkgStr = (String) (n = n.getNextNode()).getValue(); 418 if (ci.alias.startsWith(pkgStr) 419 && (pkgStr.length() > pkg.length())) { 420 prefix = (String) n.getPreviousNode().getValue(); 421 pkg = pkgStr; 422 } 423 } 424 425 if (prefix == null) { if (_defaultPkg.length() == 0) { prefix = ""; 432 } else { 433 prefix = "j"; 434 ci.uri.append(JAVOLUTION_URI); 435 } 436 } else { 437 ci.uri.append(JAVA_).append(pkg); 438 } 439 440 if (pkg.length() == 0) { 442 ci.localName.append(ci.alias); 443 } else { ci.localName.append(ci.alias, pkg.length() + 1, ci.alias 445 .length()); 446 } 447 448 if (prefix.length() == 0) { ci.qName.append(ci.localName); 451 } else { 452 ci.qName.append(prefix).append(":").append(ci.localName); 453 } 454 } 455 456 if (level >= _stack.size()) { 458 XmlElement tmp = (XmlElement) XmlElement.FACTORY.newObject(); 459 tmp._parent = (XmlElement) _stack.get(level - 1); 460 _stack.addLast(tmp); 461 } 462 XmlElement xml = (XmlElement) _stack.get(level); 463 xml._object = obj; 464 xml._objectClass = clazz; 465 xml._format = ci.format; 466 467 if ((ci.format._idName != null) && ((_features & NO_IDENTIFIER) == 0)) { 468 CharSequence idValue = (CharSequence) _objectToId.get(obj); 470 if (idValue != null) { if (((_features & EXPAND_REFERENCES) != 0) && !xml.isRecursion()) { 472 xml._format.format(obj, xml); 474 } else { xml.setAttribute(ci.format._idRef.toString(), idValue); 476 } 477 } else { xml._format.format(obj, xml); 479 480 idValue = xml.getAttribute(ci.format._idName.toString()); 482 if (idValue == null) { idValue = newTextBuilder().append(++_idCount); 484 xml.setAttribute(ci.format._idName.toString(), idValue); 485 } 486 _objectToId.put(obj, idValue); 487 } 488 } else { xml._format.format(obj, xml); 490 } 491 492 if (((_features & OUTPUT_JCLASS) != 0) || 493 ((tagName != null) && (xml.classFor(tagName) == null))) { 494 xml._attributes.addAttribute(JAVOLUTION_URI, CLASS, J, J_CLASS, 496 "CDATA", toCharSeq(ci.className)); 497 } 498 499 if ((_features & OUTPUT_XMLNS) != 0) { 500 xml._attributes.addAttribute(XMLNS_URI, J, XMLNS, XMLNS_J, 501 "CDATA", JAVOLUTION_URI); 502 } 504 505 if (tagName != null) { handler.startElement(Text.EMPTY, tagName, tagName, xml._attributes); 508 } else { 509 handler.startElement(ci.uri, ci.localName, ci.qName, 510 xml._attributes); 511 } 512 513 for (FastMap.Entry e = xml._nameToChild.headEntry(), end = xml._nameToChild 515 .tailEntry(); (e = e.getNextEntry()) != end;) { 516 writeElement(e.getValue(), handler, level + 1, 517 toCharSeq(e.getKey())); 518 } 519 for (FastList.Node n = xml._content.headNode(), end = xml._content 521 .tailNode(); (n = n.getNextNode()) != end;) { 522 writeElement(n.getValue(), handler, level + 1, null); 523 } 524 525 if (tagName != null) { 527 handler.endElement(Text.EMPTY, tagName, tagName); 528 } else { 529 handler.endElement(ci.uri, ci.localName, ci.qName); 530 } 531 532 xml.reset(); 533 } 534 535 540 public void reset() { 541 for (FastMap.Entry e = _classInfo.headEntry(), end = _classInfo 542 .tailEntry(); (e = e.getNextEntry()) != end;) { 543 ((ClassInfo) e.getValue()).reset(); } 545 _textBuilderPool.addAll(_objectToId.values()); 546 _objectToId.clear(); 547 _namespaces.clear(); 548 _defaultPkg = ""; 549 _idCount = 0; 550 _features = DEFAULT_FEATURES; 551 _rootName = null; 552 } 553 554 557 private static final class ClassInfo { 558 private static ObjectFactory FACTORY = new ObjectFactory() { 559 protected Object create() { 560 return new ClassInfo(); 561 } 562 }; 563 564 String className; 566 String alias; 568 XmlFormat format; 569 570 TextBuilder uri = new TextBuilder(); 572 TextBuilder qName = new TextBuilder(); 574 TextBuilder localName = new TextBuilder(); 576 void reset() { 577 format = null; 578 uri.reset(); 579 qName.reset(); 580 localName.reset(); 581 } 582 } 583 584 589 private TextBuilder newTextBuilder() { 590 if (_textBuilderPool.isEmpty()) 591 return (TextBuilder) TextBuilder.newInstance().moveHeap(); 592 TextBuilder tb = (TextBuilder) _textBuilderPool.removeLast(); 593 tb.reset(); 594 return tb; 595 } 596 597 private FastList _textBuilderPool = new FastList(); 598 599 605 private static CharSequence toCharSeq(Object str) { 606 return (str instanceof CharSequence) ? (CharSequence) str : Text 607 .valueOf((String) str); 608 } 609 } | Popular Tags |