1 22 package org.jboss.xb.binding; 23 24 import java.io.IOException ; 25 import java.io.Reader ; 26 import java.io.Writer ; 27 import java.lang.reflect.Array ; 28 import java.lang.reflect.Method ; 29 import java.util.AbstractList ; 30 import java.util.ArrayList ; 31 import java.util.Arrays ; 32 import java.util.Collection ; 33 import java.util.Iterator ; 34 import java.util.List ; 35 import javax.xml.namespace.QName ; 36 import javax.xml.parsers.ParserConfigurationException ; 37 import org.apache.xerces.xs.StringList; 38 import org.apache.xerces.xs.XSAttributeDeclaration; 39 import org.apache.xerces.xs.XSAttributeUse; 40 import org.apache.xerces.xs.XSComplexTypeDefinition; 41 import org.apache.xerces.xs.XSConstants; 42 import org.apache.xerces.xs.XSElementDeclaration; 43 import org.apache.xerces.xs.XSModel; 44 import org.apache.xerces.xs.XSModelGroup; 45 import org.apache.xerces.xs.XSNamedMap; 46 import org.apache.xerces.xs.XSObject; 47 import org.apache.xerces.xs.XSObjectList; 48 import org.apache.xerces.xs.XSParticle; 49 import org.apache.xerces.xs.XSSimpleTypeDefinition; 50 import org.apache.xerces.xs.XSTerm; 51 import org.apache.xerces.xs.XSTypeDefinition; 52 import org.apache.xerces.xs.XSWildcard; 53 import org.jboss.xb.binding.sunday.unmarshalling.SchemaBindingResolver; 54 import org.xml.sax.ContentHandler ; 55 import org.xml.sax.SAXException ; 56 57 61 public class XercesXsMarshaller 62 extends AbstractMarshaller 63 { 64 private Stack stack = new StackImpl(); 65 66 69 private GenericObjectModelProvider provider; 70 71 private Object root; 72 73 76 private boolean supportNil = true; 77 78 private QName rootTypeQName; 79 80 private SchemaBindingResolver schemaResolver; 81 82 private XSModel model; 83 84 private boolean ignoreUnresolvedWildcard; 85 86 private XSAttributeUse currentAttribute; 87 private XSTypeDefinition currentElementType; 88 89 private String simpleContentProperty = "value"; 90 91 private MarshallingContext ctx = new MarshallingContext() 92 { 93 private ContentHandler ch; 94 95 public boolean isAttributeRequired() 96 { 97 if(currentAttribute == null) 98 { 99 throw new JBossXBRuntimeException("There is no current attribute!"); 100 } 101 return currentAttribute.getRequired(); 102 } 103 104 public boolean isTypeComplex() 105 { 106 if(currentElementType == null) 107 { 108 throw new JBossXBRuntimeException("There is no current element!"); 109 } 110 return currentElementType.getTypeCategory() == XSTypeDefinition.COMPLEX_TYPE; 111 } 112 113 public String getSimpleContentProperty() 114 { 115 return simpleContentProperty; 116 } 117 118 public ContentHandler getContentHandler() 119 { 120 if(ch == null) 121 { 122 ch = new ContentHandlerAdaptor(); 123 } 124 return ch; 125 } 126 127 public NamespaceRegistry getNamespaceContext() 128 { 129 return nsRegistry; 130 } 131 }; 132 133 public String getSimpleContentProperty() 134 { 135 return simpleContentProperty; 136 } 137 138 public void setSimpleContentProperty(String simpleContentProperty) 139 { 140 this.simpleContentProperty = simpleContentProperty; 141 } 142 143 public boolean isIgnoreUnresolvedWildcard() 144 { 145 return ignoreUnresolvedWildcard; 146 } 147 148 public void setIgnoreUnresolvedWildcard(boolean ignoreUnresolvedWildcard) 149 { 150 this.ignoreUnresolvedWildcard = ignoreUnresolvedWildcard; 151 } 152 153 public SchemaBindingResolver getSchemaResolver() 154 { 155 return schemaResolver; 156 } 157 158 public void setSchemaResolver(SchemaBindingResolver schemaResolver) 159 { 160 this.schemaResolver = schemaResolver; 161 } 162 163 public QName getRootTypeQName() 164 { 165 return rootTypeQName; 166 } 167 168 public void setRootTypeQName(QName rootTypeQName) 169 { 170 this.rootTypeQName = rootTypeQName; 171 } 172 173 public boolean isSupportNil() 174 { 175 return supportNil; 176 } 177 178 public void setSupportNil(boolean supportNil) 179 { 180 this.supportNil = supportNil; 181 } 182 183 193 public void addAttribute(String prefix, String localName, String type, String value) 194 { 195 } 197 198 200 public void marshal(Reader xsdReader, ObjectModelProvider provider, Object root, Writer writer) 201 throws IOException , SAXException , ParserConfigurationException 202 { 203 XSModel model = Util.loadSchema(xsdReader, null, schemaResolver); 204 marshallInternal(provider, root, model, writer); 205 } 206 207 public void marshal(String xsdURL, ObjectModelProvider provider, Object root, Writer writer) throws IOException , 208 SAXException 209 { 210 XSModel model = Util.loadSchema(xsdURL, schemaResolver); 211 marshallInternal(provider, root, model, writer); 212 } 213 214 public void marshal(XSModel model, ObjectModelProvider provider, Object root, Writer writer) throws IOException , 215 SAXException 216 { 217 marshallInternal(provider, root, model, writer); 218 } 219 220 private void marshallInternal(ObjectModelProvider provider, Object root, XSModel model, Writer writer) 221 throws IOException , SAXException 222 { 223 if(model == null) 224 { 225 throw new JBossXBRuntimeException("XSModel is not available!"); 226 } 227 228 this.model = model; 229 this.provider = provider instanceof GenericObjectModelProvider ? 230 (GenericObjectModelProvider)provider : new DelegatingObjectModelProvider(provider); 231 232 this.root = root; 233 234 content.startDocument(); 235 236 if(rootTypeQName != null) 237 { 238 if(rootQNames.isEmpty()) 239 { 240 throw new JBossXBRuntimeException("If type name (" + 241 rootTypeQName + 242 ") for the root element is specified then the name for the root element is required!" 243 ); 244 } 245 QName rootQName = (QName )rootQNames.get(0); 246 247 XSTypeDefinition type = model.getTypeDefinition(rootTypeQName.getLocalPart(), 248 rootTypeQName.getNamespaceURI() 249 ); 250 if(type == null) 251 { 252 throw new JBossXBRuntimeException("Global type definition is not found: " + rootTypeQName); 253 } 254 255 if(isArrayWrapper(type)) 256 { 257 Object o = provider.getRoot(root, null, rootQName.getNamespaceURI(), rootQName.getLocalPart()); 258 stack.push(o); 259 marshalComplexType(rootQName.getNamespaceURI(), 260 rootQName.getLocalPart(), 261 (XSComplexTypeDefinition)type, 262 true, 263 false 264 ); 265 stack.pop(); 266 } 267 else 268 { 269 Object o = provider.getRoot(root, null, rootQName.getNamespaceURI(), rootQName.getLocalPart()); 270 marshalElementOccurence(rootQName.getNamespaceURI(), 271 rootQName.getLocalPart(), 272 type, 273 o, 274 false, 275 false, 276 true 277 ); 278 } 279 } 280 else if(rootQNames.isEmpty()) 281 { 282 XSNamedMap components = model.getComponents(XSConstants.ELEMENT_DECLARATION); 283 if(components.getLength() == 0) 284 { 285 throw new JBossXBRuntimeException("The schema doesn't contain global element declarations."); 286 } 287 288 for(int i = 0; i < components.getLength(); ++i) 289 { 290 XSElementDeclaration element = (XSElementDeclaration)components.item(i); 291 Object o = provider.getRoot(root, null, element.getNamespace(), element.getName()); 292 marshalElementOccurence(element.getNamespace(), 293 element.getName(), 294 element.getTypeDefinition(), 295 o, 296 element.getNillable(), 297 false, 298 true 299 ); 300 } 301 } 302 else 303 { 304 for(int i = 0; i < rootQNames.size(); ++i) 305 { 306 QName qName = (QName )rootQNames.get(i); 307 XSElementDeclaration element = model.getElementDeclaration(qName.getLocalPart(), qName.getNamespaceURI()); 308 if(element == null) 309 { 310 XSNamedMap components = model.getComponents(XSConstants.ELEMENT_DECLARATION); 311 String roots = ""; 312 for(int j = 0; j < components.getLength(); ++j) 313 { 314 XSObject xsObject = components.item(j); 315 if(j > 0) 316 { 317 roots += ", "; 318 } 319 roots += "{" + xsObject.getNamespace() + "}" + xsObject.getName(); 320 } 321 throw new IllegalStateException ("Root element not found: " + qName + " among " + roots); 322 } 323 324 Object o = provider.getRoot(root, null, element.getNamespace(), element.getName()); 325 marshalElementOccurence(element.getNamespace(), 326 element.getName(), 327 element.getTypeDefinition(), 328 o, 329 element.getNillable(), 330 false, 331 true 332 ); 333 } 334 } 335 336 content.endDocument(); 337 338 writeXmlVersion(writer); 340 341 ContentWriter contentWriter = new ContentWriter(writer, 342 propertyIsTrueOrNotSet(Marshaller.PROP_OUTPUT_INDENTATION) 343 ); 344 content.handleContent(contentWriter); 345 346 if(log.isTraceEnabled()) 347 { 348 java.io.StringWriter traceWriter = new java.io.StringWriter (); 349 contentWriter = new ContentWriter(traceWriter, 350 propertyIsTrueOrNotSet(Marshaller.PROP_OUTPUT_INDENTATION) 351 ); 352 content.handleContent(contentWriter); 353 log.trace("marshalled:\n" + traceWriter.getBuffer().toString()); 354 } 355 } 356 357 private boolean marshalElement(String elementNs, String elementLocal, 358 XSTypeDefinition type, 359 boolean optional, 360 boolean nillable, 361 boolean declareNs, 362 boolean declareXsiType) 363 { 364 Object value = stack.peek(); 365 boolean result = value != null || value == null && (optional || nillable); 366 boolean trace = log.isTraceEnabled() && result; 367 if(trace) 368 { 369 String prefix = getPrefix(elementNs); 370 log.trace("started element ns=" + elementNs + ", local=" + elementLocal + ", prefix=" + prefix); 371 } 372 373 if(value != null) 374 { 375 marshalElementType(elementNs, elementLocal, type, declareNs, nillable, declareXsiType); 376 } 377 else if(nillable) 378 { 379 writeNillable(elementNs, elementLocal, nillable); 380 } 381 382 if(trace) 383 { 384 log.trace("finished element ns=" + elementNs + ", local=" + elementLocal); 385 } 386 387 return result; 388 } 389 390 private void marshalElementType(String elementNs, 391 String elementLocal, 392 XSTypeDefinition type, 393 boolean declareNs, 394 boolean nillable, 395 boolean declareXsiType) 396 { 397 switch(type.getTypeCategory()) 398 { 399 case XSTypeDefinition.SIMPLE_TYPE: 400 marshalSimpleType(elementNs, 401 elementLocal, 402 (XSSimpleTypeDefinition)type, 403 declareNs, 404 nillable, 405 declareXsiType 406 ); 407 break; 408 case XSTypeDefinition.COMPLEX_TYPE: 409 marshalComplexType(elementNs, elementLocal, (XSComplexTypeDefinition)type, declareNs, declareXsiType); 410 break; 411 default: 412 throw new IllegalStateException ("Unexpected type category: " + type.getTypeCategory()); 413 } 414 } 415 416 private void marshalSimpleType(String elementUri, 417 String elementLocal, 418 XSSimpleTypeDefinition type, 419 boolean declareNs, 420 boolean nillable, 421 boolean declareXsiType) 422 { 423 Object value = stack.peek(); 424 if(value != null) 425 { 426 String prefix = getPrefix(elementUri); 427 boolean genPrefix = prefix == null && elementUri != null && elementUri.length() > 0; 428 if(genPrefix) 429 { 430 prefix = "ns_" + elementLocal; 431 } 432 433 AttributesImpl attrs = null; 434 String typeName = type.getName(); 435 if(SimpleTypeBindings.XS_QNAME_NAME.equals(typeName) || 436 SimpleTypeBindings.XS_NOTATION_NAME.equals(typeName) || 437 type.getItemType() != null && 438 (SimpleTypeBindings.XS_QNAME_NAME.equals(type.getItemType().getName()) || 439 SimpleTypeBindings.XS_NOTATION_NAME.equals(type.getItemType().getName()) 440 ) 441 ) 442 { 443 attrs = new AttributesImpl(5); 444 } 445 446 String marshalled = marshalCharacters(elementUri, prefix, type, value, attrs); 447 448 if((declareNs || declareXsiType) && nsRegistry.size() > 0) 449 { 450 if(attrs == null) 451 { 452 attrs = new AttributesImpl(nsRegistry.size() + 1); 453 } 454 declareNs(attrs); 455 } 456 457 if(declareXsiType) 458 { 459 declareXsiType(type, attrs); 460 } 461 462 if(genPrefix) 463 { 464 if(attrs == null) 465 { 466 attrs = new AttributesImpl(1); 467 } 468 attrs.add(null, prefix, "xmlns:" + prefix, null, (String )elementUri); 469 } 470 471 String qName = prefixLocalName(prefix, elementLocal); 472 473 content.startElement(elementUri, elementLocal, qName, attrs); 474 content.characters(marshalled.toCharArray(), 0, marshalled.length()); 475 content.endElement(elementUri, elementLocal, qName); 476 } 477 else 478 { 479 writeNillable(elementUri, elementLocal, nillable); 480 } 481 } 482 483 private void marshalComplexType(String elementNsUri, 484 String elementLocalName, 485 XSComplexTypeDefinition type, 486 boolean declareNs, 487 boolean declareXsiType) 488 { 489 Object o = stack.peek(); 490 XSParticle particle = type.getParticle(); 491 492 XSObjectList attributeUses = type.getAttributeUses(); 493 int attrsTotal = declareNs || declareXsiType ? 494 nsRegistry.size() + attributeUses.getLength() + 1 : 495 attributeUses.getLength(); 496 AttributesImpl attrs = attrsTotal > 0 ? new AttributesImpl(attrsTotal) : null; 497 498 if(declareNs && nsRegistry.size() > 0) 499 { 500 declareNs(attrs); 501 } 502 503 String generatedPrefix = null; 504 if(declareXsiType) 505 { 506 generatedPrefix = declareXsiType(type, attrs); 507 if(generatedPrefix != null) 508 { 509 String typeNsWithGeneratedPrefix = type.getNamespace(); 510 declareNs(attrs, generatedPrefix, typeNsWithGeneratedPrefix); 511 declareNamespace(generatedPrefix, typeNsWithGeneratedPrefix); 512 } 513 } 514 515 String prefix = getPrefix(elementNsUri); 516 boolean genPrefix = prefix == null && elementNsUri != null && elementNsUri.length() > 0; 517 if(genPrefix) 518 { 519 prefix = "ns_" + elementLocalName; 521 declareNamespace(prefix, elementNsUri); 522 if(attrs == null) 523 { 524 attrs = new AttributesImpl(1); 525 } 526 attrs.add(null, prefix, "xmlns:" + prefix, null, elementNsUri); 527 } 528 529 for(int i = 0; i < attributeUses.getLength(); ++i) 530 { 531 currentAttribute = (XSAttributeUse)attributeUses.item(i); 532 XSAttributeDeclaration attrDec = currentAttribute.getAttrDeclaration(); 533 String attrNs = attrDec.getNamespace(); 534 String attrLocal = attrDec.getName(); 535 Object attrValue = provider.getAttributeValue(o, ctx, attrNs, attrLocal); 536 537 if(attrValue != null) 538 { 539 if(attrs == null) 540 { 541 attrs = new AttributesImpl(5); 542 } 543 544 String attrPrefix = null; 545 if(attrNs != null) 546 { 547 attrPrefix = getPrefix(attrNs); 548 if(attrPrefix == null && attrNs != null && attrNs.length() > 0) 549 { 550 attrPrefix = "ns_" + attrLocal; 551 attrs.add(null, attrPrefix, "xmlns:" + attrPrefix, null, attrNs); 552 } 553 } 554 555 String qName = attrPrefix == null || attrPrefix.length() == 0 ? attrLocal : attrPrefix + ":" + attrLocal; 556 557 XSSimpleTypeDefinition attrType = attrDec.getTypeDefinition(); 559 if(attrType.getItemType() != null) 560 { 561 XSSimpleTypeDefinition itemType = attrType.getItemType(); 562 if(Constants.NS_XML_SCHEMA.equals(itemType.getNamespace())) 563 { 564 List list; 565 if(attrValue instanceof List ) 566 { 567 list = (List )attrValue; 568 } 569 else if(attrValue.getClass().isArray()) 570 { 571 list = Arrays.asList((Object [])attrValue); 572 } 573 else 574 { 575 throw new JBossXBRuntimeException("Expected value for list type is an array or " + 576 List .class.getName() + 577 " but got: " + 578 attrValue 579 ); 580 } 581 582 if(Constants.QNAME_QNAME.getLocalPart().equals(itemType.getName())) 583 { 584 for(int listInd = 0; listInd < list.size(); ++listInd) 585 { 586 QName item = (QName )list.get(listInd); 587 String itemNs = item.getNamespaceURI(); 588 if(itemNs != null && itemNs.length() > 0) 589 { 590 String itemPrefix; 591 if(itemNs.equals(elementNsUri)) 592 { 593 itemPrefix = prefix; 594 } 595 else 596 { 597 itemPrefix = getPrefix(itemNs); 598 if(itemPrefix == null) 599 { 600 itemPrefix = attrLocal + listInd; 601 declareNs(attrs, itemPrefix, itemNs); 602 } 603 } 604 item = new QName (item.getNamespaceURI(), item.getLocalPart(), itemPrefix); 605 list.set(listInd, item); 606 } 607 } 608 } 609 610 attrValue = SimpleTypeBindings.marshalList(itemType.getName(), list, null); 611 } 612 else 613 { 614 throw new JBossXBRuntimeException("Marshalling of list types with item types not from " + 615 Constants.NS_XML_SCHEMA + " is not supported." 616 ); 617 } 618 } 619 else if(attrType.getLexicalPattern().item(0) != null 620 && 621 attrType.derivedFrom(Constants.NS_XML_SCHEMA, 622 Constants.QNAME_BOOLEAN.getLocalPart(), 623 XSConstants.DERIVATION_RESTRICTION 624 )) 625 { 626 String item = attrType.getLexicalPattern().item(0); 627 if(item.indexOf('0') != -1 && item.indexOf('1') != -1) 628 { 629 attrValue = ((Boolean )attrValue).booleanValue() ? "1" : "0"; 630 } 631 else 632 { 633 attrValue = ((Boolean )attrValue).booleanValue() ? "true" : "false"; 634 } 635 } 636 else if(Constants.QNAME_QNAME.getNamespaceURI().equals(attrType.getNamespace()) && 637 Constants.QNAME_QNAME.getLocalPart().equals(attrType.getName())) 638 { 639 QName qNameValue = (QName )attrValue; 640 641 String qNamePrefix = null; 642 boolean declarePrefix = false; 643 String ns = qNameValue.getNamespaceURI(); 644 if(ns != null && ns.length() > 0) 645 { 646 qNamePrefix = getPrefix(ns); 647 if(qNamePrefix == null) 648 { 649 qNamePrefix = qNameValue.getPrefix(); 650 if(qNamePrefix == null || qNamePrefix.length() == 0) 651 { 652 qNamePrefix = "ns_" + qNameValue.getLocalPart(); 653 } 654 declareNs(attrs, qNamePrefix, ns); 655 nsRegistry.addPrefixMapping(qNamePrefix, ns); 656 declarePrefix = true; 657 } 658 } 659 660 attrValue = SimpleTypeBindings.marshalQName(qNameValue, nsRegistry); 661 662 if(declarePrefix) 663 { 664 nsRegistry.removePrefixMapping(qNamePrefix); 665 } 666 } 667 else 668 { 669 attrValue = attrValue.toString(); 670 } 671 672 attrs.add(attrNs, 673 attrLocal, 674 qName, 675 attrDec.getTypeDefinition().getName(), 676 attrValue.toString() 677 ); 678 } 679 } 680 currentAttribute = null; 681 682 String characters = null; 683 if(type.getSimpleType() != null) 684 { 685 Object value = getSimpleContentValue(elementNsUri, elementLocalName, type); 686 if(value != null) 687 { 688 XSSimpleTypeDefinition simpleType = type.getSimpleType(); 689 String typeName = simpleType.getName(); 690 if(attrs == null && (SimpleTypeBindings.XS_QNAME_NAME.equals(typeName) || 691 SimpleTypeBindings.XS_NOTATION_NAME.equals(typeName) || 692 simpleType.getItemType() != null && 693 (SimpleTypeBindings.XS_QNAME_NAME.equals(simpleType.getItemType().getName()) || 694 SimpleTypeBindings.XS_NOTATION_NAME.equals(simpleType.getItemType().getName()) 695 ) 696 ) 697 ) 698 { 699 attrs = new AttributesImpl(5); 700 } 701 702 characters = marshalCharacters(elementNsUri, prefix, simpleType, value, attrs); 703 } 704 } 705 706 String qName = prefixLocalName(prefix, elementLocalName); 707 content.startElement(elementNsUri, elementLocalName, qName, attrs); 708 709 if(particle != null) 710 { 711 marshalParticle(particle, false); 712 } 713 714 if(characters != null) 715 { 716 content.characters(characters.toCharArray(), 0, characters.length()); 717 } 718 content.endElement(elementNsUri, elementLocalName, qName); 719 720 if(genPrefix) 721 { 722 removePrefixMapping(prefix); 723 } 724 725 if(generatedPrefix != null) 726 { 727 removePrefixMapping(generatedPrefix); 728 } 729 } 730 731 private boolean marshalParticle(XSParticle particle, boolean declareNs) 732 { 733 boolean marshalled; 734 XSTerm term = particle.getTerm(); 735 Object o; 736 Iterator i; 737 switch(term.getType()) 738 { 739 case XSConstants.MODEL_GROUP: 740 o = stack.peek(); 741 i = o != null && isRepeatable(particle) ? getIterator(o) : null; 742 if(i != null) 743 { 744 marshalled = true; 745 while(i.hasNext() && marshalled) 746 { 747 Object value = i.next(); 748 stack.push(value); 749 marshalled = marshalModelGroup(particle, declareNs); 750 stack.pop(); 751 } 752 } 753 else 754 { 755 marshalled = marshalModelGroup(particle, declareNs); 756 } 757 break; 758 case XSConstants.WILDCARD: 759 o = stack.peek(); 760 761 boolean popWildcardValue = false; 762 ObjectLocalMarshaller marshaller = null; 763 FieldToWildcardMapping mapping = (FieldToWildcardMapping)field2WildcardMap.get(o.getClass()); 764 if(mapping != null) 765 { 766 marshaller = mapping.marshaller; 767 o = mapping.fieldInfo.getValue(o); 768 stack.push(o); 769 popWildcardValue = true; 770 } 771 772 i = o != null && isRepeatable(particle) ? getIterator(o) : null; 773 if(i != null) 774 { 775 marshalled = true; 776 while(i.hasNext() && marshalled) 777 { 778 Object value = i.next(); 779 marshalled = marshalWildcardOccurence(particle, marshaller, value, declareNs); 780 } 781 } 782 else 783 { 784 marshalled = marshalWildcardOccurence(particle, marshaller, o, declareNs); 785 } 786 787 if(popWildcardValue) 788 { 789 stack.pop(); 790 } 791 792 break; 793 case XSConstants.ELEMENT_DECLARATION: 794 XSElementDeclaration element = (XSElementDeclaration)term; 795 XSTypeDefinition type = element.getTypeDefinition(); 796 o = getElementValue(element.getNamespace(), element.getName(), type); 797 798 i = o != null && isRepeatable(particle) ? getIterator(o) : null; 799 if(i != null) 800 { 801 marshalled = true; 802 while(i.hasNext() && marshalled) 803 { 804 Object value = i.next(); 805 marshalled = 806 marshalElementOccurence(element.getNamespace(), 807 element.getName(), 808 type, 809 value, 810 element.getNillable(), 811 particle.getMinOccurs() == 0, 812 declareNs 813 ); 814 } 815 } 816 else 817 { 818 marshalled = 819 marshalElementOccurence(element.getNamespace(), 820 element.getName(), 821 type, 822 o, 823 element.getNillable(), 824 particle.getMinOccurs() == 0, 825 declareNs 826 ); 827 } 828 break; 829 default: 830 throw new IllegalStateException ("Unexpected term type: " + term.getType()); 831 } 832 return marshalled; 833 } 834 835 private boolean marshalElementOccurence(String elementNs, 836 String elementLocal, 837 XSTypeDefinition type, 838 Object value, 839 boolean nillable, 840 boolean optional, 841 boolean declareNs) 842 { 843 boolean declareXsiType = false; 844 QName xsiTypeQName = null; 845 if(value != null) 846 { 847 xsiTypeQName = (QName )cls2TypeMap.get(value.getClass()); 848 if(xsiTypeQName != null && 849 !(type.getName().equals(xsiTypeQName.getLocalPart()) && 850 type.getNamespace().equals(xsiTypeQName.getNamespaceURI()) 851 )) 852 { 853 declareXsiType = true; 854 if(log.isTraceEnabled()) 855 { 856 log.trace(value.getClass() + " is mapped to xsi:type " + xsiTypeQName); 857 } 858 859 XSTypeDefinition xsiType = model.getTypeDefinition(xsiTypeQName.getLocalPart(), 860 xsiTypeQName.getNamespaceURI() 861 ); 862 863 if(xsiType == null) 864 { 865 log.warn("Class " + 866 value.getClass() + 867 " is mapped to type " + 868 xsiTypeQName + 869 " but the type is not found in schema." 870 ); 871 } 872 else 874 { 875 type = xsiType; 876 } 877 } 878 } 879 880 stack.push(value); 881 boolean marshalled = marshalElement(elementNs, 882 elementLocal, 883 type, 884 optional, 885 nillable, 886 declareNs, 887 declareXsiType 888 ); 889 stack.pop(); 890 891 return marshalled; 892 } 893 894 private boolean marshalWildcardOccurence(XSParticle particle, 895 ObjectLocalMarshaller marshaller, 896 Object value, 897 boolean declareNs) 898 { 899 boolean marshalled = true; 900 if(marshaller != null) 901 { 902 marshaller.marshal(ctx, value); 903 } 904 else 905 { 906 stack.push(value); 907 marshalled = marshalWildcard(particle, declareNs); 908 stack.pop(); 909 } 910 return marshalled; 911 } 912 913 private boolean marshalWildcard(XSParticle particle, boolean declareNs) 914 { 915 XSWildcard wildcard = (XSWildcard)particle.getTerm(); 916 Object o = stack.peek(); 917 ClassMapping mapping = getClassMapping(o.getClass()); 918 if(mapping == null) 919 { 920 QName autoType = SimpleTypeBindings.typeQName(o.getClass()); 922 if(autoType != null) 923 { 924 String marshalled = SimpleTypeBindings.marshal(autoType.getLocalPart(), o, null); 925 content.characters(marshalled.toCharArray(), 0, marshalled.length()); 926 return true; 927 } 928 else 929 { 930 if(ignoreUnresolvedWildcard) 931 { 932 log.warn("Failed to marshal wildcard. Class mapping not found for " + 933 o.getClass() + 934 "@" + 935 o.hashCode() + 936 ": " + o 937 ); 938 return true; 939 } 940 else 941 { 942 throw new IllegalStateException ("Failed to marshal wildcard. Class mapping not found for " + 943 o.getClass() + 944 "@" + 945 o.hashCode() + 946 ": " + o 947 ); 948 } 949 } 950 } 951 952 GenericObjectModelProvider parentProvider = this.provider; 953 Object parentRoot = this.root; 954 Stack parentStack = this.stack; 955 XSModel parentModel = this.model; 956 957 this.root = o; 958 this.stack = new StackImpl(); 959 this.model = mapping.schemaUrl == null ? this.model : Util.loadSchema(mapping.schemaUrl, schemaResolver); 960 if(mapping.provider != null) 961 { 962 this.provider = mapping.provider; 963 } 964 965 boolean marshalled; 966 if(mapping.elementName != null) 967 { 968 XSElementDeclaration elDec = model.getElementDeclaration(mapping.elementName.getLocalPart(), 969 mapping.elementName.getNamespaceURI() 970 ); 971 972 if(elDec == null) 973 { 974 throw new JBossXBRuntimeException("Element " + mapping.elementName + " is not declared in the schema."); 975 } 976 977 Object elementValue = provider.getRoot(root, null, elDec.getNamespace(), elDec.getName()); 978 marshalled = marshalElementOccurence(elDec.getNamespace(), 979 elDec.getName(), 980 elDec.getTypeDefinition(), 981 elementValue, 982 elDec.getNillable(), 983 particle.getMinOccurs() == 0, 984 declareNs 985 ); 986 } 987 else if(mapping.typeName != null) 988 { 989 XSTypeDefinition typeDef = model.getTypeDefinition(mapping.typeName.getLocalPart(), 990 mapping.typeName.getNamespaceURI() 991 ); 992 993 if(typeDef == null) 994 { 995 List typeNames = new ArrayList (); 996 XSNamedMap types = model.getComponents(XSConstants.TYPE_DEFINITION); 997 for(int i = 0; i < types.getLength(); ++i) 998 { 999 XSObject type = types.item(i); 1000 if(!Constants.NS_XML_SCHEMA.equals(type.getNamespace())) 1001 { 1002 typeNames.add(new QName (type.getNamespace(), type.getName())); 1003 } 1004 } 1005 throw new JBossXBRuntimeException("Type " + 1006 mapping.typeName + 1007 " is not defined in the schema." + 1008 " Defined types are: " + typeNames 1009 ); 1010 } 1011 1012 Object elementValue = provider.getRoot(root, null, wildcard.getNamespace(), wildcard.getName()); 1013 marshalled = 1014 marshalElementOccurence(wildcard.getNamespace(), 1015 wildcard.getName(), 1016 typeDef, 1017 elementValue, 1018 true, 1019 particle.getMinOccurs() == 0, 1020 declareNs 1021 ); 1022 } 1023 else 1024 { 1025 throw new JBossXBRuntimeException("Class mapping for " + 1026 mapping.cls + 1027 " is associated with neither global element name nor global type name." 1028 ); 1029 } 1030 1031 this.root = parentRoot; 1032 this.provider = parentProvider; 1033 this.stack = parentStack; 1034 this.model = parentModel; 1035 1036 return marshalled; 1037 } 1038 1039 private boolean marshalModelGroup(XSParticle particle, boolean declareNs) 1040 { 1041 XSModelGroup modelGroup = (XSModelGroup)particle.getTerm(); 1042 boolean marshalled; 1043 switch(modelGroup.getCompositor()) 1044 { 1045 case XSModelGroup.COMPOSITOR_ALL: 1046 marshalled = marshalModelGroupAll(modelGroup.getParticles(), declareNs); 1047 break; 1048 case XSModelGroup.COMPOSITOR_CHOICE: 1049 marshalled = marshalModelGroupChoice(modelGroup.getParticles(), declareNs); 1050 break; 1051 case XSModelGroup.COMPOSITOR_SEQUENCE: 1052 marshalled = marshalModelGroupSequence(modelGroup.getParticles(), declareNs); 1053 break; 1054 default: 1055 throw new IllegalStateException ("Unexpected compsitor: " + modelGroup.getCompositor()); 1056 } 1057 return marshalled; 1058 } 1059 1060 private boolean marshalModelGroupAll(XSObjectList particles, boolean declareNs) 1061 { 1062 boolean marshalled = false; 1063 for(int i = 0; i < particles.getLength(); ++i) 1064 { 1065 XSParticle particle = (XSParticle)particles.item(i); 1066 marshalled |= marshalParticle(particle, declareNs); 1067 } 1068 return marshalled; 1069 } 1070 1071 private boolean marshalModelGroupChoice(XSObjectList particles, boolean declareNs) 1072 { 1073 boolean marshalled = false; 1074 Content mainContent = this.content; 1075 for(int i = 0; i < particles.getLength() && !marshalled; ++i) 1076 { 1077 XSParticle particle = (XSParticle)particles.item(i); 1078 this.content = new Content(); 1079 marshalled = marshalParticle(particle, declareNs); 1080 } 1081 1082 if(marshalled) 1083 { 1084 mainContent.append(this.content); 1085 } 1086 this.content = mainContent; 1087 1088 return marshalled; 1089 } 1090 1091 private boolean marshalModelGroupSequence(XSObjectList particles, boolean declareNs) 1092 { 1093 boolean marshalled = true; 1094 for(int i = 0; i < particles.getLength(); ++i) 1095 { 1096 XSParticle particle = (XSParticle)particles.item(i); 1097 marshalled &= marshalParticle(particle, declareNs); 1098 } 1099 return marshalled; 1100 } 1101 1102 private String marshalCharacters(String elementUri, 1103 String elementPrefix, 1104 XSSimpleTypeDefinition type, 1105 Object value, 1106 AttributesImpl attrs) 1107 { 1108 String marshalled; 1109 if(type.getItemType() != null) 1110 { 1111 XSSimpleTypeDefinition itemType = type.getItemType(); 1112 if(Constants.NS_XML_SCHEMA.equals(itemType.getNamespace())) 1113 { 1114 List list; 1115 if(value instanceof List ) 1116 { 1117 list = (List )value; 1118 } 1119 else if(value.getClass().isArray()) 1120 { 1121 list = asList(value); 1122 } 1123 else 1124 { 1125 throw new JBossXBRuntimeException( 1127 "Expected value for list type is an array or " + List .class.getName() + " but got: " + value 1128 ); 1129 } 1130 1131 marshalled = SimpleTypeBindings.marshalList(itemType.getName(), list, null); 1132 } 1133 else 1134 { 1135 throw new JBossXBRuntimeException("Marshalling of list types with item types not from " + 1136 Constants.NS_XML_SCHEMA + " is not supported." 1137 ); 1138 } 1139 } 1140 else if(Constants.NS_XML_SCHEMA.equals(type.getNamespace())) 1141 { 1142 String typeName = type.getName(); 1143 1144 String prefix = null; 1145 boolean removePrefix = false; 1146 if(SimpleTypeBindings.XS_QNAME_NAME.equals(typeName) || 1147 SimpleTypeBindings.XS_NOTATION_NAME.equals(typeName)) 1148 { 1149 QName qName = (QName )value; 1150 if(qName.getNamespaceURI() != null && qName.getNamespaceURI().length() > 0) 1151 { 1152 prefix = nsRegistry.getPrefix(qName.getNamespaceURI()); 1153 if(prefix == null) 1154 { 1155 prefix = qName.getPrefix(); 1156 if(prefix == null || prefix.length() == 0) 1157 { 1158 prefix = qName.getLocalPart() + "_ns"; 1159 } 1160 nsRegistry.addPrefixMapping(prefix, qName.getNamespaceURI()); 1161 declareNs(attrs, prefix, qName.getNamespaceURI()); 1162 1163 removePrefix = true; 1164 } 1165 } 1166 } 1167 marshalled = SimpleTypeBindings.marshal(typeName, value, nsRegistry); 1168 1169 if(removePrefix) 1170 { 1171 nsRegistry.removePrefixMapping(prefix); 1172 } 1173 } 1174 else if(type.getLexicalPattern().item(0) != null 1176 && 1177 type.derivedFrom(Constants.NS_XML_SCHEMA, 1178 Constants.QNAME_BOOLEAN.getLocalPart(), 1179 XSConstants.DERIVATION_RESTRICTION 1180 )) 1181 { 1182 String item = type.getLexicalPattern().item(0); 1183 if(item.indexOf('0') != -1 && item.indexOf('1') != -1) 1184 { 1185 marshalled = ((Boolean )value).booleanValue() ? "1" : "0"; 1186 } 1187 else 1188 { 1189 marshalled = ((Boolean )value).booleanValue() ? "true" : "false"; 1190 } 1191 } 1192 else 1193 { 1194 StringList lexicalEnumeration = type.getLexicalEnumeration(); 1195 if(lexicalEnumeration != null && lexicalEnumeration.getLength() > 0) 1196 { 1197 Method getValue; 1198 try 1199 { 1200 getValue = value.getClass().getMethod("value", null); 1201 } 1202 catch(NoSuchMethodException e) 1203 { 1204 try 1205 { 1206 getValue = value.getClass().getMethod("getValue", null); 1207 } 1208 catch(NoSuchMethodException e1) 1209 { 1210 List values = new ArrayList (lexicalEnumeration.getLength()); 1211 for(int i = 0; i < lexicalEnumeration.getLength(); ++i) 1212 { 1213 values.add(lexicalEnumeration.item(i)); 1214 } 1215 1216 throw new JBossXBRuntimeException("Failed to find neither value() nor getValue() in " + 1217 value.getClass() + 1218 " which is bound to enumeration type (" + 1219 type.getNamespace() + 1220 ", " + 1221 type.getName() + "): " + values 1222 ); 1223 } 1224 } 1225 1226 try 1227 { 1228 value = getValue.invoke(value, null); 1229 } 1230 catch(Exception e) 1231 { 1232 throw new JBossXBRuntimeException( 1233 "Failed to invoke getValue() on " + value + " to get the enumeration value", e 1234 ); 1235 } 1236 } 1237 1238 marshalled = marshalCharacters(elementUri, 1239 elementPrefix, 1240 (XSSimpleTypeDefinition)type.getBaseType(), 1241 value, attrs 1242 ); 1243 } 1244 return marshalled; 1245 } 1246 1247 1253 private String declareXsiType(XSTypeDefinition type, AttributesImpl attrs) 1254 { 1255 String result = null; 1256 String xsiPrefix = nsRegistry.getPrefix(Constants.NS_XML_SCHEMA_INSTANCE); 1257 if(xsiPrefix == null) 1258 { 1259 attrs.add(Constants.NS_XML_SCHEMA, "xmlns", "xmlns:xsi", null, Constants.NS_XML_SCHEMA_INSTANCE); 1260 xsiPrefix = "xsi"; 1261 } 1262 1263 String pref = getPrefix(type.getNamespace()); 1264 if(pref == null) 1265 { 1266 result = pref = type.getName() + "_ns"; 1268 } 1269 1270 String typeQName = pref == null ? type.getName() : pref + ':' + type.getName(); 1271 attrs.add(Constants.NS_XML_SCHEMA_INSTANCE, "type", xsiPrefix + ":type", null, typeQName); 1272 return result; 1273 } 1274 1275 private Object getElementValue(String elementNs, String elementLocal, XSTypeDefinition type) 1276 { 1277 Object value; 1278 Object peeked = stack.isEmpty() ? root : stack.peek(); 1279 if(peeked == null) 1280 { 1281 value = null; 1282 } 1283 else if(peeked instanceof Collection || peeked.getClass().isArray()) 1284 { 1285 value = peeked; 1287 } 1288 else 1289 { 1290 XSTypeDefinition parentType = currentElementType; 1291 currentElementType = type; 1292 1293 value = provider.getChildren(peeked, ctx, elementNs, elementLocal); 1294 if(value == null) 1295 { 1296 value = provider.getElementValue(peeked, ctx, elementNs, elementLocal); 1297 } 1298 1299 currentElementType = parentType; 1300 } 1301 return value; 1302 } 1303 1304 private Object getSimpleContentValue(String elementNs, String elementLocal, XSTypeDefinition type) 1305 { 1306 Object value; 1307 Object peeked = stack.isEmpty() ? root : stack.peek(); 1308 if(peeked == null) 1309 { 1310 value = null; 1311 } 1312 else 1313 { 1314 XSTypeDefinition parentType = currentElementType; 1315 currentElementType = type; 1316 value = provider.getElementValue(peeked, ctx, elementNs, elementLocal); 1317 currentElementType = parentType; 1318 } 1319 return value; 1320 } 1321 1322 private void writeNillable(String elementNs, String elementLocal, boolean nillable) 1323 { 1324 if(!supportNil) 1325 { 1326 return; 1327 } 1328 1329 if(!nillable) 1330 { 1331 throw new JBossXBRuntimeException("Failed to marshal " + 1332 new QName (elementNs, elementLocal) + 1333 ": Java value is null but the element is not nillable." 1334 ); 1335 } 1336 1337 AttributesImpl attrs; 1338 String prefix = getPrefix(elementNs); 1339 if(prefix == null && elementNs != null && elementNs.length() > 0) 1340 { 1341 prefix = "ns_" + elementLocal; 1342 attrs = new AttributesImpl(2); 1343 attrs.add(null, prefix, "xmlns:" + prefix, null, elementNs); 1344 } 1345 else 1346 { 1347 attrs = new AttributesImpl(1); 1348 } 1349 1350 String xsiPrefix = getPrefix(Constants.NS_XML_SCHEMA_INSTANCE); 1351 if(xsiPrefix == null) 1352 { 1353 xsiPrefix = "xsi"; 1354 attrs.add(null, 1355 xsiPrefix, 1356 "xmlns:xsi", 1357 null, 1358 Constants.NS_XML_SCHEMA_INSTANCE 1359 ); 1360 } 1361 1362 String nilQName = xsiPrefix + ":nil"; 1363 attrs.add(Constants.NS_XML_SCHEMA_INSTANCE, "nil", nilQName, null, "1"); 1364 1365 String qName = prefixLocalName(prefix, elementLocal); 1366 content.startElement(elementNs, elementLocal, qName, attrs); 1367 content.endElement(elementNs, elementLocal, qName); 1368 } 1369 1370 private static boolean isArrayWrapper(XSTypeDefinition type) 1371 { 1372 boolean is = false; 1373 if(XSTypeDefinition.COMPLEX_TYPE == type.getTypeCategory()) 1374 { 1375 XSComplexTypeDefinition cType = (XSComplexTypeDefinition)type; 1376 XSParticle particle = cType.getParticle(); 1377 if(particle != null) 1378 { 1379 is = particle.getMaxOccursUnbounded() || particle.getMaxOccurs() > 1; 1380 } 1381 } 1382 return is; 1383 } 1384 1385 private Iterator getIterator(Object value) 1386 { 1387 Iterator i = null; 1388 if(value instanceof Collection ) 1389 { 1390 i = ((Collection )value).iterator(); 1391 } 1392 else if(value.getClass().isArray()) 1393 { 1394 final Object arr = value; 1395 i = new Iterator () 1396 { 1397 private int curInd = 0; 1398 private int length = Array.getLength(arr); 1399 1400 public boolean hasNext() 1401 { 1402 return curInd < length; 1403 } 1404 1405 public Object next() 1406 { 1407 return Array.get(arr, curInd++); 1408 } 1409 1410 public void remove() 1411 { 1412 throw new UnsupportedOperationException ("remove is not implemented."); 1413 } 1414 }; 1415 } 1416 else if(value instanceof Iterator ) 1417 { 1418 i = (Iterator )value; 1419 } 1420 else 1421 { 1422 } 1424 return i; 1425 } 1426 1427 private static boolean isRepeatable(XSParticle particle) 1428 { 1429 return particle.getMaxOccursUnbounded() || particle.getMaxOccurs() > 1 || particle.getMinOccurs() > 1; 1430 } 1431 1432 private static final List asList(final Object arr) 1433 { 1434 return new AbstractList () 1435 { 1436 private final Object array = arr; 1437 1438 public Object get(int index) 1439 { 1440 return Array.get(array, index); 1441 } 1442 1443 public int size() 1444 { 1445 return Array.getLength(array); 1446 } 1447 }; 1448 } 1449} 1450 | Popular Tags |