| 1 16 package org.apache.commons.betwixt.io; 17 18 import java.beans.IntrospectionException ; 19 import java.io.IOException ; 20 import java.util.ArrayList ; 21 import java.util.Collection ; 22 import java.util.HashMap ; 23 import java.util.Iterator ; 24 25 import org.apache.commons.betwixt.AttributeDescriptor; 26 import org.apache.commons.betwixt.BindingConfiguration; 27 import org.apache.commons.betwixt.Descriptor; 28 import org.apache.commons.betwixt.ElementDescriptor; 29 import org.apache.commons.betwixt.XMLBeanInfo; 30 import org.apache.commons.betwixt.XMLIntrospector; 31 import org.apache.commons.betwixt.digester.XMLIntrospectorHelper; 32 import org.apache.commons.betwixt.expression.Context; 33 import org.apache.commons.betwixt.expression.Expression; 34 import org.apache.commons.betwixt.io.id.SequentialIDGenerator; 35 import org.apache.commons.collections.ArrayStack; 36 import org.apache.commons.logging.Log; 37 import org.apache.commons.logging.LogFactory; 38 import org.xml.sax.Attributes ; 39 import org.xml.sax.SAXException ; 40 import org.xml.sax.helpers.AttributesImpl ; 41 42 45 50 88 public abstract class AbstractBeanWriter { 89 90 91 private XMLIntrospector introspector = new XMLIntrospector(); 92 93 94 private Log log = LogFactory.getLog( AbstractBeanWriter.class ); 95 96 private HashMap idMap = new HashMap (); 97 98 private ArrayStack beanStack = new ArrayStack(); 99 100 private IDGenerator idGenerator = new SequentialIDGenerator(); 101 102 private boolean writeEmptyElements = true; 103 104 private BindingConfiguration bindingConfiguration = new BindingConfiguration(); 105 106 private WriteContextImpl writeContext = new WriteContextImpl(); 107 108 private Collection namespacesDeclared = new ArrayList (); 109 110 117 public void start() throws IOException , SAXException { 118 } 119 120 127 128 public void end() throws IOException , SAXException { 129 } 130 131 146 public void write(Object bean) throws 147 IOException , 148 SAXException , 149 IntrospectionException { 150 if (log.isDebugEnabled()) { 151 log.debug( "Writing bean graph..." ); 152 log.debug( bean ); 153 } 154 start(); 155 writeBean( null, null, null, bean, makeContext( bean ) ); 156 end(); 157 if (log.isDebugEnabled()) { 158 log.debug( "Finished writing bean graph." ); 159 } 160 } 161 162 177 public void write( 178 String qualifiedName, 179 Object bean) 180 throws 181 IOException , 182 SAXException , 183 IntrospectionException { 184 start(); 185 writeBean( "", qualifiedName, qualifiedName, bean, makeContext( bean ) ); 186 end(); 187 } 188 189 207 private void writeBean ( 208 String namespaceUri, 209 String localName, 210 String qualifiedName, 211 Object bean, 212 Context context) 213 throws 214 IOException , 215 SAXException , 216 IntrospectionException { 217 218 if ( log.isTraceEnabled() ) { 219 log.trace( "Writing bean graph (qualified name '" + qualifiedName + "'" ); 220 } 221 222 XMLBeanInfo beanInfo = introspector.introspect( bean ); 224 if ( beanInfo != null ) { 225 ElementDescriptor elementDescriptor = beanInfo.getElementDescriptor(); 226 if ( elementDescriptor != null ) { 227 context = context.newContext( bean ); 228 if ( qualifiedName == null ) { 229 qualifiedName = elementDescriptor.getQualifiedName(); 230 } 231 if ( namespaceUri == null ) { 232 namespaceUri = elementDescriptor.getURI(); 233 } 234 if ( localName == null ) { 235 localName = elementDescriptor.getLocalName(); 236 } 237 238 String ref = null; 239 String id = null; 240 241 if ( elementDescriptor.isSimple() ) { 243 writeElement( 245 namespaceUri, 246 localName, 247 qualifiedName, 248 elementDescriptor, 249 context ); 250 251 } else { 252 pushBean ( context.getBean() ); 253 if ( getBindingConfiguration().getMapIDs() ) { 254 ref = (String ) idMap.get( context.getBean() ); 255 } 256 if ( ref == null ) { 257 AttributeDescriptor idAttribute = beanInfo.getIDAttribute(); 259 if (idAttribute == null) { 260 id = idGenerator.nextId(); 262 idMap.put( bean, id ); 263 264 if ( getBindingConfiguration().getMapIDs() ) { 265 writeElement( 267 namespaceUri, 268 localName, 269 qualifiedName, 270 elementDescriptor, 271 context , 272 beanInfo.getIDAttributeName(), 273 id); 274 275 } else { 276 writeElement( 278 namespaceUri, 279 localName, 280 qualifiedName, 281 elementDescriptor, 282 context ); 283 } 284 285 } else { 286 Object exp = idAttribute.getTextExpression().evaluate( context ); 290 if (exp == null) { 291 log.debug("Using random id"); 293 id = idGenerator.nextId(); 294 295 } else { 296 id = exp.toString(); 298 } 299 idMap.put( bean, id); 300 301 writeElement( 303 namespaceUri, 304 localName, 305 qualifiedName, 306 elementDescriptor, 307 context ); 308 } 309 } else { 310 311 if ( !ignoreElement( elementDescriptor, context )) { 312 writeIDREFElement( 314 elementDescriptor, 315 namespaceUri, 316 localName, 317 qualifiedName, 318 beanInfo.getIDREFAttributeName(), 319 ref); 320 } 321 } 322 popBean(); 323 } 324 } 325 } 326 327 log.trace( "Finished writing bean graph." ); 328 } 329 330 336 public IDGenerator getIdGenerator() { 337 return idGenerator; 338 } 339 340 347 public void setIdGenerator(IDGenerator idGenerator) { 348 this.idGenerator = idGenerator; 349 } 350 351 352 353 358 public BindingConfiguration getBindingConfiguration() { 359 return bindingConfiguration; 360 } 361 362 367 public void setBindingConfiguration(BindingConfiguration bindingConfiguration) { 368 this.bindingConfiguration = bindingConfiguration; 369 } 370 371 380 public boolean getWriteIDs() { 381 return getBindingConfiguration().getMapIDs(); 382 } 383 384 392 public void setWriteIDs(boolean writeIDs) { 393 getBindingConfiguration().setMapIDs( writeIDs ); 394 } 395 396 407 public boolean getWriteEmptyElements() { 408 return writeEmptyElements; 409 } 410 411 422 public void setWriteEmptyElements(boolean writeEmptyElements) { 423 this.writeEmptyElements = writeEmptyElements; 424 } 425 426 436 public XMLIntrospector getXMLIntrospector() { 437 return introspector; 438 } 439 440 441 451 public void setXMLIntrospector(XMLIntrospector introspector) { 452 this.introspector = introspector; 453 } 454 455 460 public final Log getAbstractBeanWriterLog() { 461 return log; 462 } 463 464 469 public final void setAbstractBeanWriterLog(Log log) { 470 this.log = log; 471 } 472 473 476 488 protected void startElement( 489 WriteContext context, 490 String uri, 491 String localName, 492 String qName, 493 Attributes attr) 494 throws 495 IOException , 496 SAXException { 497 startElement(uri, localName, qName, attr); 499 } 500 501 512 protected void endElement( 513 WriteContext context, 514 String uri, 515 String localName, 516 String qName) 517 throws 518 IOException , 519 SAXException { 520 endElement(uri, localName, qName); 522 } 523 524 533 protected void bodyText(WriteContext context, String text) 534 throws IOException , SAXException { 535 bodyText(text); 537 } 538 539 542 554 protected void startElement( 555 String uri, 556 String localName, 557 String qName, 558 Attributes attr) 559 throws 560 IOException , 561 SAXException {} 562 563 574 protected void endElement( 575 String uri, 576 String localName, 577 String qName) 578 throws 579 IOException , 580 SAXException {} 581 582 591 protected void bodyText(String text) throws IOException , SAXException {} 592 593 596 608 private void writeElement( 609 String namespaceUri, 610 String localName, 611 String qualifiedName, 612 ElementDescriptor elementDescriptor, 613 Context context ) 614 throws 615 IOException , 616 SAXException , 617 IntrospectionException { 618 if( log.isTraceEnabled() ) { 619 log.trace( "Writing: " + qualifiedName + " element: " + elementDescriptor ); 620 } 621 622 if ( !ignoreElement( elementDescriptor, context )) { 623 if ( log.isTraceEnabled() ) { 624 log.trace( "Element " + elementDescriptor + " is empty." ); 625 } 626 627 Attributes attributes = addNamespaceDeclarations( 628 new ElementAttributes( elementDescriptor, context ), namespaceUri); 629 writeContext.setCurrentDescriptor(elementDescriptor); 630 startElement( 631 writeContext, 632 namespaceUri, 633 localName, 634 qualifiedName, 635 attributes); 636 637 writeElementContent( elementDescriptor, context ) ; 638 writeContext.setCurrentDescriptor(elementDescriptor); 639 endElement( writeContext, namespaceUri, localName, qualifiedName ); 640 641 } 642 } 643 644 650 private Attributes addNamespaceDeclarations(Attributes attributes, String elementNamespaceUri) { 651 Attributes result = attributes; 652 AttributesImpl withDeclarations = null; 653 for (int i=-1, size=attributes.getLength(); i<size ; i++) { 654 String uri = null; 655 if (i == -1) { 656 uri = elementNamespaceUri; 657 } else { 658 uri = attributes.getURI(i); 659 } 660 if (uri != null && !"".equals(uri) && !namespacesDeclared.contains(uri)) { 661 if (withDeclarations == null) { 662 withDeclarations = new AttributesImpl (attributes); 663 } 664 withDeclarations.addAttribute("", "", "xmlns:" 665 + getXMLIntrospector().getConfiguration().getPrefixMapper().getPrefix(uri), "NOTATION", uri); 666 namespacesDeclared.add(uri); 667 } 668 } 669 670 if (withDeclarations != null) { 671 result = withDeclarations; 672 } 673 return result; 674 } 675 676 677 691 private void writeElement( 692 String namespaceUri, 693 String localName, 694 String qualifiedName, 695 ElementDescriptor elementDescriptor, 696 Context context, 697 String idAttribute, 698 String idValue ) 699 throws 700 IOException , 701 SAXException , 702 IntrospectionException { 703 704 if ( !ignoreElement( elementDescriptor, context ) ) { 705 writeContext.setCurrentDescriptor(elementDescriptor); 706 Attributes attributes = new IDElementAttributes( 707 elementDescriptor, 708 context, 709 idAttribute, 710 idValue ); 711 startElement( 712 writeContext, 713 namespaceUri, 714 localName, 715 qualifiedName, 716 addNamespaceDeclarations(attributes, namespaceUri)); 717 718 writeElementContent( elementDescriptor, context ) ; 719 writeContext.setCurrentDescriptor(elementDescriptor); 720 endElement( writeContext, namespaceUri, localName, qualifiedName ); 721 722 } else if ( log.isTraceEnabled() ) { 723 log.trace( "Element " + qualifiedName + " is empty." ); 724 } 725 } 726 727 728 |