1 22 package org.jboss.xb.binding.sunday.unmarshalling; 23 24 import java.io.InputStream ; 25 import java.io.Reader ; 26 import java.util.Collections ; 27 import java.util.HashMap ; 28 import java.util.LinkedHashSet ; 29 import java.util.Map ; 30 import java.util.ListIterator ; 31 import java.util.List ; 32 import java.util.ArrayList ; 33 import java.util.Set ; 34 35 import javax.xml.namespace.QName ; 36 37 import org.apache.xerces.xs.StringList; 38 import org.apache.xerces.xs.XSAnnotation; 39 import org.apache.xerces.xs.XSAttributeDeclaration; 40 import org.apache.xerces.xs.XSAttributeUse; 41 import org.apache.xerces.xs.XSComplexTypeDefinition; 42 import org.apache.xerces.xs.XSConstants; 43 import org.apache.xerces.xs.XSElementDeclaration; 44 import org.apache.xerces.xs.XSModel; 45 import org.apache.xerces.xs.XSModelGroup; 46 import org.apache.xerces.xs.XSModelGroupDefinition; 47 import org.apache.xerces.xs.XSNamedMap; 48 import org.apache.xerces.xs.XSObjectList; 49 import org.apache.xerces.xs.XSParticle; 50 import org.apache.xerces.xs.XSSimpleTypeDefinition; 51 import org.apache.xerces.xs.XSTerm; 52 import org.apache.xerces.xs.XSTypeDefinition; 53 import org.apache.xerces.xs.XSWildcard; 54 import org.jboss.logging.Logger; 55 import org.jboss.xb.binding.Constants; 56 import org.jboss.xb.binding.JBossXBRuntimeException; 57 import org.jboss.xb.binding.Util; 58 import org.jboss.xb.binding.sunday.xop.XOPIncludeHandler; 59 import org.jboss.xb.binding.metadata.AddMethodMetaData; 60 import org.jboss.xb.binding.metadata.CharactersMetaData; 61 import org.jboss.xb.binding.metadata.ClassMetaData; 62 import org.jboss.xb.binding.metadata.MapEntryMetaData; 63 import org.jboss.xb.binding.metadata.PackageMetaData; 64 import org.jboss.xb.binding.metadata.PropertyMetaData; 65 import org.jboss.xb.binding.metadata.PutMethodMetaData; 66 import org.jboss.xb.binding.metadata.SchemaMetaData; 67 import org.jboss.xb.binding.metadata.ValueMetaData; 68 import org.jboss.xb.binding.metadata.XsdAnnotation; 69 import org.jboss.xb.binding.metadata.XsdAppInfo; 70 71 75 public class XsdBinder 76 { 77 static final Logger log = Logger.getLogger(XsdBinder.class); 78 79 private XsdBinder() 80 { 81 } 82 83 89 public static SchemaBinding bind(String xsdUrl) 90 { 91 DefaultSchemaResolver resolver = new DefaultSchemaResolver(); 92 resolver.setBaseURI(xsdUrl); 93 return bind(xsdUrl, resolver); 94 } 95 96 104 public static SchemaBinding bind(String xsdUrl, SchemaBindingResolver resolver) 105 { 106 XSModel model = Util.loadSchema(xsdUrl, resolver); 107 return bind(model, resolver); 108 } 109 110 public static SchemaBinding bind(InputStream xsdStream, String encoding) 111 { 112 return bind(xsdStream, encoding, new DefaultSchemaResolver()); 113 } 114 115 122 public static SchemaBinding bind(InputStream xsdStream, String encoding, String baseURI) 123 { 124 return bind(xsdStream, encoding, baseURI, true); 125 } 126 127 135 public static SchemaBinding bind(InputStream xsdStream, String encoding, String baseURI, boolean processAnnotations) 136 { 137 DefaultSchemaResolver resolver = new DefaultSchemaResolver(); 138 resolver.setBaseURI(baseURI); 139 return bind(xsdStream, encoding, resolver, processAnnotations); 140 } 141 142 151 public static SchemaBinding bind(InputStream xsdStream, String encoding, SchemaBindingResolver resolver) 152 { 153 return bind(xsdStream, encoding, resolver, true); 154 } 155 156 166 public static SchemaBinding bind(InputStream xsdStream, String encoding, SchemaBindingResolver resolver, boolean processAnnotations) 167 { 168 XSModel model = Util.loadSchema(xsdStream, encoding, resolver); 169 return bind(model, resolver, processAnnotations); 170 } 171 172 public static SchemaBinding bind(Reader xsdReader, String encoding) 173 { 174 return bind(xsdReader, encoding, new DefaultSchemaResolver()); 175 } 176 177 184 public static SchemaBinding bind(Reader xsdReader, String encoding, String baseURI) 185 { 186 DefaultSchemaResolver resolver = new DefaultSchemaResolver(); 187 resolver.setBaseURI(baseURI); 188 return bind(xsdReader, encoding, resolver); 189 } 190 191 200 public static SchemaBinding bind(Reader xsdReader, String encoding, SchemaBindingResolver resolver) 201 { 202 XSModel model = Util.loadSchema(xsdReader, encoding, resolver); 203 return bind(model, resolver); 204 } 205 206 213 public static SchemaBinding bind(String xsd, String encoding) 214 { 215 return bind(xsd, encoding, new DefaultSchemaResolver()); 216 } 217 218 227 public static SchemaBinding bind(String xsd, String encoding, SchemaBindingResolver resolver) 228 { 229 XSModel model = Util.loadSchema(xsd, encoding); 230 return bind(model, resolver); 231 } 232 233 public static SchemaBinding bind(XSModel model, SchemaBindingResolver resolver) 234 { 235 return bind(model,resolver, true); 236 } 237 238 public static SchemaBinding bind(XSModel model, SchemaBindingResolver resolver, boolean processAnnotations) 239 { 240 Context ctx = new Context(); 241 ctx.processAnnotations = processAnnotations; 242 SchemaBinding schema = ctx.schema; 243 schema.setSchemaResolver(resolver); 244 245 if (ctx.processAnnotations) 247 { 248 XSObjectList annotations = model.getAnnotations(); 249 if (ctx.trace) 250 { 251 log.trace("started binding schema " + schema); 252 log.trace("Schema annotations: " + annotations.getLength()); 253 } 254 255 for(int i = 0; i < annotations.getLength(); ++i) 256 { 257 XSAnnotation annotation = (XSAnnotation)annotations.item(i); 258 XsdAnnotation an = XsdAnnotation.unmarshal(annotation.getAnnotationString()); 259 XsdAppInfo appinfo = an.getAppInfo(); 260 if(appinfo != null) 261 { 262 SchemaMetaData schemaBindings = appinfo.getSchemaMetaData(); 263 if(schemaBindings != null) 264 { 265 schema.setIgnoreUnresolvedFieldOrClass(schemaBindings.isIgnoreUnresolvedFieldOrClass()); 267 schema.setReplacePropertyRefs(schemaBindings.isReplacePropertyRefs()); 269 PackageMetaData packageMetaData = schemaBindings.getPackage(); 271 if(packageMetaData != null) 272 { 273 if (ctx.trace) 274 log.trace("schema default package: " + packageMetaData.getName()); 275 schema.setPackageMetaData(packageMetaData); 276 } 277 } 278 } 279 } 280 } 281 282 StringList namespaceList = model.getNamespaces(); 283 Set namespaces = new LinkedHashSet (namespaceList.getLength()); 284 for (int i = 0; i < namespaceList.getLength(); ++i) 285 namespaces.add(namespaceList.item(i)); 286 schema.setNamespaces(namespaces); 287 288 XSNamedMap groups = model.getComponents(XSConstants.MODEL_GROUP_DEFINITION); 289 if (ctx.trace) 290 log.trace("Model groups: " + groups.getLength()); 291 for(int i = 0; i < groups.getLength(); ++i) 292 { 293 XSModelGroupDefinition groupDef = (XSModelGroupDefinition)groups.item(i); 294 bindGlobalGroup(groupDef.getModelGroup(), ctx.sharedElements); 295 } 296 297 XSNamedMap types = model.getComponents(XSConstants.TYPE_DEFINITION); 298 if (ctx.trace) 299 log.trace("Model types: " + types.getLength()); 300 for(int i = 0; i < types.getLength(); ++i) 301 { 302 XSTypeDefinition type = (XSTypeDefinition)types.item(i); 303 if(!Constants.NS_XML_SCHEMA.equals(type.getNamespace())) 304 { 305 bindType(ctx, type); 306 } 307 } 308 309 XSNamedMap elements = model.getComponents(XSConstants.ELEMENT_DECLARATION); 310 if (ctx.trace) 311 log.trace("Model elements: " + types.getLength()); 312 for(int i = 0; i < elements.getLength(); ++i) 313 { 314 XSElementDeclaration element = (XSElementDeclaration)elements.item(i); 315 bindElement(ctx, element, 1, 0, false); 316 } 317 318 if (ctx.trace) 319 { 320 log.trace("finished binding schema " + schema); 321 } 322 323 return schema; 324 } 325 326 335 public static void bindType(SchemaBinding schema, XSTypeDefinition type) 336 { 337 TypeBinding typeBinding = bindType(new Context(schema), type); 338 schema.addType(typeBinding); 339 } 340 341 353 public static void bindElement(SchemaBinding schema, 354 XSElementDeclaration element, 355 int minOccurs, 356 int maxOccurs, 357 boolean maxOccursUnbounded) 358 { 359 ParticleBinding particle = bindElement(new Context(schema), 360 element, 361 minOccurs, 362 maxOccurs, 363 maxOccursUnbounded 364 ); 365 schema.addElementParticle(particle); 366 } 367 368 370 private static TypeBinding bindType(Context ctx, XSTypeDefinition type) 371 { 372 TypeBinding binding; 373 switch(type.getTypeCategory()) 374 { 375 case XSTypeDefinition.SIMPLE_TYPE: 376 binding = bindSimpleType(ctx, (XSSimpleTypeDefinition)type); 377 break; 378 case XSTypeDefinition.COMPLEX_TYPE: 379 binding = bindComplexType(ctx, (XSComplexTypeDefinition)type); 380 break; 381 default: 382 throw new JBossXBRuntimeException("Unexpected type category: " + type.getTypeCategory()); 383 } 384 return binding; 385 } 386 387 private static TypeBinding bindSimpleType(Context ctx, XSSimpleTypeDefinition type) 388 { 389 QName typeName = type.getName() == null ? null : new QName (type.getNamespace(), type.getName()); 390 TypeBinding binding = typeName == null ? null : ctx.schema.getType(typeName); 391 if(binding != null) 392 { 393 return binding; 394 } 395 396 if(ctx.trace) 397 { 398 log.trace("binding simple type " + typeName); 399 } 400 401 XSTypeDefinition baseTypeDef = type.getBaseType(); 402 TypeBinding baseType = baseTypeDef == null ? null : bindType(ctx, baseTypeDef); 403 404 binding = baseType == null ? new TypeBinding(typeName) : new TypeBinding(typeName, baseType); 405 406 StringList strList = type.getLexicalPattern(); 407 if(strList != null && strList.getLength() > 0) 408 { 409 for(int i = 0; i < strList.getLength(); ++i) 410 { 411 binding.addLexicalPattern(strList.item(i)); 412 } 413 } 414 415 strList = type.getLexicalEnumeration(); 416 if(strList != null && strList.getLength() > 0) 417 { 418 for(int i = 0; i < strList.getLength(); ++i) 419 { 420 binding.addEnumValue(strList.item(i)); 421 } 422 } 423 424 if(type.getItemType() != null) 425 { 426 TypeBinding itemType = bindSimpleType(ctx, type.getItemType()); 427 binding.setItemType(itemType); 428 } 429 430 if(typeName != null) 431 { 432 ctx.schema.addType(binding); 433 } 434 435 if(ctx.trace) 436 { 437 String msg = typeName == null ? "bound simple anonymous type" : "bound simple type " + typeName; 438 if(baseType != null) 439 { 440 msg += " inherited binding metadata from " + baseType.getQName(); 441 } 442 log.trace(msg); 443 } 444 445 if(ctx.processAnnotations) 447 { 448 XSObjectList annotations = type.getAnnotations(); 449 if(annotations != null) 450 { 451 if(ctx.trace) 452 { 453 log.trace(typeName + " annotations " + annotations.getLength()); 454 } 455 for(int i = 0; i < annotations.getLength(); ++i) 456 { 457 XSAnnotation an = (XSAnnotation)annotations.item(i); 458 XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString()); 459 XsdAppInfo appInfo = xsdAn.getAppInfo(); 460 if(appInfo != null) 461 { 462 ClassMetaData classMetaData = appInfo.getClassMetaData(); 463 if(classMetaData != null) 464 { 465 if(ctx.trace) 466 { 467 log.trace("simple type " + 468 type.getName() + 469 ": impl=" + 470 classMetaData.getImpl()); 471 } 472 binding.setClassMetaData(classMetaData); 473 } 474 475 ValueMetaData valueMetaData = appInfo.getValueMetaData(); 476 if(valueMetaData != null) 477 { 478 if(ctx.trace) 479 { 480 log.trace("simple type " + 481 type.getName() + 482 ": unmarshalMethod=" + 483 valueMetaData.getUnmarshalMethod() + 484 ", marshalMethod=" + 485 valueMetaData.getMarshalMethod()); 486 } 487 binding.setValueMetaData(valueMetaData); 488 } 489 } 490 } 491 } 492 } 493 494 binding.setSchemaBinding(ctx.schema); 495 496 return binding; 497 } 498 499 private static TypeBinding bindComplexType(Context ctx, XSComplexTypeDefinition type) 500 { 501 QName typeName = type.getName() == null ? null : new QName (type.getNamespace(), type.getName()); 502 TypeBinding binding = typeName == null ? null : ctx.schema.getType(typeName); 503 if(binding != null) 504 { 505 return binding; 506 } 507 508 XSTypeDefinition baseTypeDef = type.getBaseType(); 509 TypeBinding baseType = null; 511 if(baseTypeDef != null && !Constants.QNAME_ANYTYPE.equals(typeName)) 512 { 513 baseType = bindType(ctx, baseTypeDef); 514 if(typeName != null) 517 { 518 binding = ctx.schema.getType(typeName); 519 if(binding != null) 520 { 521 return binding; 522 } 523 } 524 } 525 526 if (ctx.trace) 527 log.trace("binding complex " + (typeName == null ? "anonymous type" : "type " + typeName)); 528 529 binding = new TypeBinding(typeName); 530 binding.setBaseType(baseType); 531 binding.setStartElementCreatesObject(true); 532 binding.setSimple(false); 533 534 if(type.getSimpleType() != null) 535 { 536 TypeBinding simpleType = bindSimpleType(ctx, type.getSimpleType()); 537 binding.setSimpleType(simpleType); 538 } 539 else if(type.getContentType() == XSComplexTypeDefinition.CONTENTTYPE_MIXED) 540 { 541 TypeBinding stringType = ctx.schema.getType(Constants.QNAME_STRING); 542 if(stringType == null) 543 { 544 throw new JBossXBRuntimeException("xsd:string has not been bound yet!"); 545 } 546 binding.setSimpleType(stringType); 547 } 548 549 if(typeName != null) 550 { 551 ctx.schema.addType(binding); 552 } 553 554 binding.setSchemaBinding(ctx.schema); 555 556 XSObjectList attrs = type.getAttributeUses(); 557 if (ctx.trace) 558 log.trace(typeName + " attributes " + attrs.getLength()); 559 for(int i = 0; i < attrs.getLength(); ++i) 560 { 561 XSAttributeUse attr = (XSAttributeUse)attrs.item(i); 562 bindAttributes(ctx, binding, attr); 563 } 564 565 if (ctx.processAnnotations) 567 { 568 XSObjectList annotations = type.getAnnotations(); 569 if(annotations != null) 570 { 571 if (ctx.trace) 572 log.trace(typeName + " annotations " + annotations.getLength()); 573 for(int i = 0; i < annotations.getLength(); ++i) 574 { 575 XSAnnotation an = (XSAnnotation)annotations.item(i); 576 XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString()); 577 XsdAppInfo appInfo = xsdAn.getAppInfo(); 578 if(appInfo != null) 579 { 580 ClassMetaData classMetaData = appInfo.getClassMetaData(); 581 if(classMetaData != null) 582 { 583 if (ctx.trace) 584 { 585 log.trace("complex type " + 586 type.getName() + 587 ": impl=" + 588 classMetaData.getImpl() 589 ); 590 } 591 binding.setClassMetaData(classMetaData); 592 } 593 594 CharactersMetaData charactersMetaData = appInfo.getCharactersMetaData(); 595 if(charactersMetaData != null) 596 { 597 if (ctx.trace) 598 { 599 PropertyMetaData propertyMetaData = charactersMetaData.getProperty(); 600 if(propertyMetaData != null) 601 { 602 log.trace("complex type " + 603 type.getName() + 604 ": characters bound to " + propertyMetaData.getName() 605 ); 606 } 607 608 ValueMetaData valueMetaData = charactersMetaData.getValue(); 609 if(valueMetaData != null) 610 { 611 log.trace("complex type " + 612 type.getName() + 613 ": characters unmarshalMethod=" + 614 valueMetaData.getUnmarshalMethod() + 615 ", marshalMethod=" + valueMetaData.getMarshalMethod() 616 ); 617 } 618 619 boolean mapEntryKey = appInfo.isMapEntryKey(); 620 if(mapEntryKey) 621 { 622 log.trace("complex type " + 623 type.getName() + 624 ": characters are bound as a key in a map entry" 625 ); 626 } 627 628 boolean mapEntryValue = appInfo.isMapEntryValue(); 629 if(mapEntryValue) 630 { 631 log.trace("complex type " + 632 type.getName() + 633 ": characters are bound as a value in a map entry" 634 ); 635 } 636 } 637 binding.setCharactersMetaData(charactersMetaData); 638 } 639 640 MapEntryMetaData mapEntryMetaData = appInfo.getMapEntryMetaData(); 641 if(mapEntryMetaData != null) 642 { 643 if (ctx.trace) 644 { 645 log.trace("complex type " + 646 type.getName() + 647 " is bound to a map entry: impl=" + 648 mapEntryMetaData.getImpl() + 649 ", getKeyMethod=" + 650 mapEntryMetaData.getGetKeyMethod() + 651 ", setKeyMethod=" + 652 mapEntryMetaData.getSetKeyMethod() + 653 ", getValueMethod=" + 654 mapEntryMetaData.getGetValueMethod() + 655 ", setValueMethod=" + 656 mapEntryMetaData.getSetValueMethod() + 657 ", valueType=" + 658 mapEntryMetaData.getValueType() + 659 ", nonNullValue=" + mapEntryMetaData.isNonNullValue() 660 ); 661 } 662 663 if(classMetaData != null) 664 { 665 throw new JBossXBRuntimeException("Illegal binding: both jbxb:class and jbxb:mapEntry are specified for complex type " + 666 type.getName() 667 ); 668 } 669 binding.setMapEntryMetaData(mapEntryMetaData); 670 } 671 672 boolean skip = appInfo.isSkip(); 673 if(skip) 674 { 675 if (ctx.trace) 676 { 677 log.trace("complex type " + 678 type.getName() + 679 ": elements of this type will be skipped; their attrs, character content " + 680 "and elements will be set the parent." 681 ); 682 } 683 binding.setSkip(skip); 684 } 685 686 PropertyMetaData propertyMetaData = appInfo.getPropertyMetaData(); 687 if(propertyMetaData != null) 688 { 689 if (ctx.trace) 690 { 691 log.trace("complex type " + 692 type.getName() + 693 ": the content of elements of this type is bound to property " + propertyMetaData.getName() 694 ); 695 } 696 binding.setPropertyMetaData(propertyMetaData); 697 } 698 699 AddMethodMetaData addMethodMetaData = appInfo.getAddMethodMetaData(); 700 if(addMethodMetaData != null) 701 { 702 if (ctx.trace) 703 { 704 log.trace("complex type " + 705 type.getName() + 706 ": elements of this type will be added to parent objects with addMethod=" + 707 addMethodMetaData.getMethodName() + ", valueType=" + addMethodMetaData.getValueType() 708 ); 709 } 710 binding.setAddMethodMetaData(addMethodMetaData); 711 } 712 } 713 } 714 } 715 } 716 717 XSParticle particle = type.getParticle(); 718 if(particle != null) 719 { 720 ctx.pushType(binding); 721 bindParticle(ctx, particle); 722 ctx.popType(); 723 } 724 725 if(binding.hasOnlyXmlMimeAttributes()) 726 { 727 addXOPInclude(binding, ctx.schema); 728 } 729 730 if(ctx.trace) 731 { 732 log.trace(typeName == null ? "bound complex anonymous type" : "bound complex type " + typeName); 733 } 734 735 return binding; 736 } 737 738 private static void bindAttributes(Context ctx, TypeBinding type, XSAttributeUse attrUse) 739 { 740 XSAttributeDeclaration attr = attrUse.getAttrDeclaration(); 741 QName attrName = new QName (attr.getNamespace(), attr.getName()); 742 743 if (ctx.trace) 744 { 745 log.trace("binding attribute " + attrName + " for " + type.getQName() + ", required=" + attrUse.getRequired()); 746 } 747 748 XSSimpleTypeDefinition attrType = attr.getTypeDefinition(); 749 TypeBinding typeBinding = bindSimpleType(ctx, attrType); 750 AttributeBinding binding = type.addAttribute(attrName, typeBinding, DefaultHandlers.ATTRIBUTE_HANDLER); 751 binding.setRequired(attrUse.getRequired()); 752 if(attrUse.getConstraintType() == XSConstants.VC_DEFAULT) 753 { 754 binding.setDefaultConstraint(attrUse.getConstraintValue()); 756 } 757 758 if (ctx.processAnnotations) 759 { 760 XSAnnotation an = attr.getAnnotation(); 761 if(an != null) 762 { 763 if (ctx.trace) 764 { 765 log.trace(attrName + " attribute annotation"); 766 } 767 768 XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString()); 769 XsdAppInfo appInfo = xsdAn.getAppInfo(); 770 if(appInfo != null) 771 { 772 PropertyMetaData propertyMetaData = appInfo.getPropertyMetaData(); 773 if(propertyMetaData != null) 774 { 775 binding.setPropertyMetaData(propertyMetaData); 776 } 777 778 boolean mapEntryKey = appInfo.isMapEntryKey(); 779 if(mapEntryKey) 780 { 781 binding.setMapEntryKey(mapEntryKey); 782 } 783 784 boolean mapEntryValue = appInfo.isMapEntryValue(); 785 if(mapEntryValue) 786 { 787 binding.setMapEntryValue(mapEntryValue); 788 } 789 } 790 } 791 } 792 793 794 if (ctx.trace) 795 { 796 String msg = "bound attribute " + attrName; 797 798 if(binding.getPropertyMetaData() != null) 799 { 800 msg += " property=" + 801 binding.getPropertyMetaData().getName() + 802 ", collectionType=" + binding.getPropertyMetaData().getCollectionType(); 803 } 804 else if(binding.isMapEntryKey()) 805 { 806 msg += "bound as a key in a map entry"; 807 } 808 else if(binding.isMapEntryValue()) 809 { 810 msg += "bound as a value in a map entry"; 811 } 812 else 813 { 814 msg += " type=" + attrType.getName() + ", owner type=" + type.getQName(); 815 } 816 817 if(binding.getDefaultConstraint() != null) 818 { 819 msg += ", default=" + binding.getDefaultConstraint(); 820 } 821 822 log.trace(msg); 823 } 824 } 825 826 private static void bindParticle(Context ctx, XSParticle particle) 827 { 828 XSTerm term = particle.getTerm(); 829 switch(term.getType()) 830 { 831 case XSConstants.MODEL_GROUP: 832 XSModelGroup modelGroup = (XSModelGroup)term; 833 if(modelGroup.getParticles().getLength() > 0) 835 { 836 ModelGroupBinding groupBinding; 837 switch(modelGroup.getCompositor()) 838 { 839 case XSModelGroup.COMPOSITOR_ALL: 840 groupBinding = new AllBinding(ctx.schema); 841 break; 842 case XSModelGroup.COMPOSITOR_CHOICE: 843 groupBinding = new ChoiceBinding(ctx.schema); 844 break; 845 case XSModelGroup.COMPOSITOR_SEQUENCE: 846 groupBinding = new SequenceBinding(ctx.schema); 847 break; 848 default: 849 throw new JBossXBRuntimeException("Unexpected model group: " + modelGroup.getCompositor()); 850 } 851 852 ParticleBinding particleBinding = new ParticleBinding(groupBinding); 853 particleBinding.setMaxOccursUnbounded(particle.getMaxOccursUnbounded()); 854 particleBinding.setMinOccurs(particle.getMinOccurs()); 855 particleBinding.setMaxOccurs(particle.getMaxOccurs()); 856 857 if (ctx.trace) 858 { 859 log.trace("created model group " + groupBinding); 860 } 861 862 if (ctx.processAnnotations) 863 { 864 XSAnnotation annotation = modelGroup.getAnnotation(); 865 if(annotation != null) 866 { 867 customizeTerm(annotation, groupBinding, ctx.trace); 868 } 869 } 870 871 Object o = ctx.peekTypeOrGroup(); 872 if(o instanceof ModelGroupBinding) 873 { 874 ModelGroupBinding parentGroup = (ModelGroupBinding)o; 875 parentGroup.addParticle(particleBinding); 876 if (ctx.trace) 877 { 878 log.trace("added " + groupBinding + " to " + parentGroup); 879 } 880 } 881 else if(o instanceof TypeBinding) 882 { 883 TypeBinding typeBinding = (TypeBinding)o; 884 typeBinding.setParticle(particleBinding); 885 if (ctx.trace) 886 { 887 log.trace("added " + groupBinding + " to type " + typeBinding.getQName()); 888 } 889 } 890 891 ctx.pushModelGroup(groupBinding); 892 bindModelGroup(ctx, modelGroup); 893 ctx.popModelGroup(); 894 } 895 break; 896 case XSConstants.WILDCARD: 897 bindWildcard(ctx, particle); 898 break; 899 case XSConstants.ELEMENT_DECLARATION: 900 bindElement(ctx, 901 (XSElementDeclaration)term, 902 particle.getMinOccurs(), 903 particle.getMaxOccurs(), 904 particle.getMaxOccursUnbounded() 905 ); 906 break; 907 default: 908 throw new IllegalStateException ("Unexpected term type: " + term.getType()); 909 } 910 } 911 912 private static void bindWildcard(Context ctx, XSParticle particle) 913 { 914 WildcardBinding binding = new WildcardBinding(ctx.schema); 915 916 ModelGroupBinding group = (ModelGroupBinding)ctx.peekTypeOrGroup(); 917 ParticleBinding particleBinding = new ParticleBinding(binding); 918 particleBinding.setMaxOccurs(particle.getMaxOccurs()); 919 particleBinding.setMaxOccursUnbounded(particle.getMaxOccursUnbounded()); 920 particleBinding.setMinOccurs(particle.getMinOccurs()); 921 group.addParticle(particleBinding); 922 923 TypeBinding type = ctx.peekType(); 924 type.setWildcard(binding); 925 926 if (ctx.trace) 927 { 928 log.trace("added wildcard to " + group); 929 log.trace("added wildcard to type " + type.getQName()); 930 } 931 932 XSWildcard wildcard = (XSWildcard)particle.getTerm(); 933 if(wildcard.getName() != null) 934 { 935 binding.setQName(new QName (wildcard.getNamespace(), wildcard.getName())); 936 } 937 938 binding.setProcessContents(wildcard.getProcessContents()); 939 940 if (ctx.processAnnotations) 941 { 942 XSAnnotation annotation = wildcard.getAnnotation(); 943 if(annotation != null) 944 { 945 customizeTerm(annotation, binding, ctx.trace); 946 } 947 } 948 } 949 950 private static ParticleBinding bindElement(Context ctx, 951 XSElementDeclaration elementDec, 952 int minOccurs, 953 int maxOccurs, 954 boolean maxOccursUnbounded) 955 { 956 QName qName = new QName (elementDec.getNamespace(), elementDec.getName()); 957 958 ModelGroupBinding parentGroup = (ModelGroupBinding)ctx.peekTypeOrGroup(); 959 960 boolean global = elementDec.getScope() == XSConstants.SCOPE_GLOBAL; 961 ElementBinding element = ctx.schema.getElement(qName); 962 ParticleBinding particle; 963 if(global && element != null) 964 { 965 particle = new ParticleBinding(element); 966 if(parentGroup != null) 967 { 968 parentGroup.addParticle(particle); 969 } 970 971 particle.setMinOccurs(minOccurs); 972 if(maxOccursUnbounded) 973 { 974 particle.setMaxOccursUnbounded(maxOccursUnbounded); 975 } 976 else 977 { 978 particle.setMaxOccurs(maxOccurs); 979 } 980 981 return particle; 982 } 983 984 TypeBinding type = null; 985 986 boolean shared = ctx.sharedElements.isShared(elementDec); 987 if(shared) 988 { 989 type = ctx.sharedElements.getTypeBinding(elementDec); 990 } 991 992 if(type == null) 993 { 994 type = bindType(ctx, elementDec.getTypeDefinition()); 995 if(shared) 996 { 997 ctx.sharedElements.setTypeBinding(elementDec, type); 998 } 999 } 1000 1001 element = new ElementBinding(ctx.schema, qName, type); 1002 element.setNillable(elementDec.getNillable()); 1003 particle = new ParticleBinding(element); 1004 particle.setMinOccurs(minOccurs); 1005 particle.setMaxOccurs(maxOccurs); 1006 particle.setMaxOccursUnbounded(maxOccursUnbounded); 1007 if(global) 1008 { 1009 ctx.schema.addElementParticle(particle); 1010 } 1011 1012 if(parentGroup != null) 1013 { 1014 parentGroup.addParticle(particle); 1015 if (ctx.trace) 1016 { 1017 log.trace("Element " + element.getQName() + " added to " + parentGroup); 1018 } 1019 } 1020 1021 if (ctx.trace) 1022 { 1023 TypeBinding parentType = ctx.peekType(); 1024 log.trace("element: name=" + 1025 qName + 1026 ", type=" + 1027 type.getQName() + 1028 ", repeatable=" + 1029 particle.isRepeatable() + 1030 ", nillable=" + 1031 element.isNillable() + 1032 ", minOccurs=" + minOccurs + 1033 ", maxOccurs=" + (maxOccursUnbounded ? "unbounded" : "" + maxOccurs) + 1034 ", " + (global ? "global scope" : " owner type=" + parentType.getQName()) 1035 ); 1036 } 1037 1038 if (ctx.processAnnotations) 1040 { 1041 XSAnnotation an = elementDec.getAnnotation(); 1042 if(an != null) 1043 { 1044 customizeTerm(an, element, ctx.trace); 1045 } 1046 } 1047 return particle; 1048 } 1049 1050 private static void bindModelGroup(Context ctx, XSModelGroup modelGroup) 1051 { 1052 XSObjectList particles = modelGroup.getParticles(); 1053 for(int i = 0; i < particles.getLength(); ++i) 1054 { 1055 XSParticle particle = (XSParticle)particles.item(i); 1056 bindParticle(ctx, particle); 1057 } 1058 } 1059 1060 1062 private static void addXOPInclude(TypeBinding binding, SchemaBinding schema) 1063 { 1064 binding.setHandler(DefaultHandlers.XOP_HANDLER); 1065 if(binding.getParticle() != null) 1066 { 1067 throw new JBossXBRuntimeException( 1068 "XOP optimizable type has a particle which is unexpected, please, open a JIRA issue!" 1069 ); 1070 } 1071 1072 TypeBinding anyUriType = schema.getType(Constants.QNAME_ANYURI); 1073 if(anyUriType == null) 1074 { 1075 log.warn("Type " + Constants.QNAME_ANYURI + " not bound."); 1076 } 1077 1078 TypeBinding xopIncludeType = new TypeBinding(new QName (Constants.NS_XOP_INCLUDE, "Include")); 1079 xopIncludeType.setSchemaBinding(schema); 1080 xopIncludeType.addAttribute(new QName ("href"), anyUriType, DefaultHandlers.ATTRIBUTE_HANDLER); 1081 xopIncludeType.setHandler(new XOPIncludeHandler(binding)); 1082 1083 ElementBinding xopInclude = new ElementBinding(schema, new QName (Constants.NS_XOP_INCLUDE, "Include"), xopIncludeType); 1084 1085 ParticleBinding particleBinding = new ParticleBinding(xopInclude); 1086 particleBinding.setMinOccurs(0); 1087 1088 binding.addParticle(particleBinding); 1089 } 1090 1091 private static void customizeTerm(XSAnnotation an, TermBinding term, boolean trace) 1092 { 1093 XsdAnnotation xsdAn = XsdAnnotation.unmarshal(an.getAnnotationString()); 1094 XsdAppInfo appInfo = xsdAn.getAppInfo(); 1095 if(appInfo != null) 1096 { 1097 Boolean skip = null; 1098 1099 ClassMetaData classMetaData = appInfo.getClassMetaData(); 1100 if(classMetaData != null) 1101 { 1102 if (trace) 1103 { 1104 String msg; 1105 if(term.isModelGroup()) 1106 { 1107 msg = term + " bound to "; 1108 } 1109 else if(term.isWildcard()) 1110 { 1111 msg = " wildcard bound to "; 1112 } 1113 else 1114 { 1115 msg = "element: name=" + ((ElementBinding)term).getQName() + ", class="; 1116 } 1117 1118 msg += classMetaData.getImpl(); 1119 log.trace(msg); 1120 } 1121 term.setClassMetaData(classMetaData); 1122 skip = Boolean.FALSE; 1123 } 1124 1125 PropertyMetaData propertyMetaData = appInfo.getPropertyMetaData(); 1126 if(propertyMetaData != null) 1127 { 1128 if (trace) 1129 { 1130 String msg = term.isWildcard() || term.isModelGroup() ? term + " " : "element: name=" + 1131 ((ElementBinding)term).getQName() + ", "; 1132 msg += " property=" + 1133 propertyMetaData.getName() + 1134 ", collectionType=" + propertyMetaData.getCollectionType(); 1135 log.trace(msg); 1136 } 1137 term.setPropertyMetaData(propertyMetaData); 1138 } 1139 1140 MapEntryMetaData mapEntryMetaData = appInfo.getMapEntryMetaData(); 1141 if(mapEntryMetaData != null) 1142 { 1143 if(propertyMetaData != null) 1144 { 1145 String msg = "A term can be bound either as a property or as a map" + 1146 " entry but not both: " + 1147 (term.isModelGroup() ? term.toString() : ((ElementBinding)term).getQName().toString()); 1148 throw new JBossXBRuntimeException(msg); 1149 } 1150 1151 if (trace) 1152 { 1153 String msg = term.isWildcard() || term.isModelGroup() ? term.toString() : "element name=" + 1154 ((ElementBinding)term).getQName(); 1155 1156 msg += " is bound to a map entry: impl=" + 1157 mapEntryMetaData.getImpl() + 1158 ", getKeyMethod=" + 1159 mapEntryMetaData.getGetKeyMethod() + 1160 ", setKeyMethod=" + 1161 mapEntryMetaData.getSetKeyMethod() + 1162 ", getValueMethod=" + 1163 mapEntryMetaData.getGetValueMethod() + 1164 ", setValueMethod=" + 1165 mapEntryMetaData.getSetValueMethod() + 1166 ", valueType=" + 1167 mapEntryMetaData.getValueType() + 1168 ", nonNullValue=" + mapEntryMetaData.isNonNullValue(); 1169 log.trace(msg); 1170 } 1171 1172 if(classMetaData != null) 1173 { 1174 String msg = "Invalid customization: both jbxb:class and jbxb:mapEntry are specified for term " + 1175 (term.isWildcard() || term.isModelGroup() ? term.toString() : ((ElementBinding)term).getQName().toString()); 1176 throw new JBossXBRuntimeException(msg); 1177 } 1178 term.setMapEntryMetaData(mapEntryMetaData); 1179 skip = Boolean.FALSE; 1180 } 1181 1182 PutMethodMetaData putMethodMetaData = appInfo.getPutMethodMetaData(); 1183 if(putMethodMetaData != null) 1184 { 1185 if (trace) 1186 { 1187 String msg = term.isWildcard() || term.isModelGroup() ? term.toString() : "element: name=" + 1188 ((ElementBinding)term).getQName() + ","; 1189 1190 msg += " putMethod=" + 1191 putMethodMetaData.getName() + 1192 ", keyType=" + 1193 putMethodMetaData.getKeyType() + 1194 ", valueType=" + putMethodMetaData.getValueType(); 1195 log.trace(msg); 1196 } 1197 term.setPutMethodMetaData(putMethodMetaData); 1198 } 1199 1200 AddMethodMetaData addMethodMetaData = appInfo.getAddMethodMetaData(); 1201 if(addMethodMetaData != null) 1202 { 1203 if (trace) 1204 { 1205 String msg = term.isWildcard() || term.isModelGroup() ? term.toString() : "element: name=" + 1206 ((ElementBinding)term).getQName() + ","; 1207 msg += " addMethod=" + 1208 addMethodMetaData.getMethodName() + 1209 ", valueType=" + 1210 addMethodMetaData.getValueType() + 1211 ", isChildType=" + addMethodMetaData.isChildType(); 1212 log.trace(msg); 1213 } 1214 term.setAddMethodMetaData(addMethodMetaData); 1215 } 1216 1217 ValueMetaData valueMetaData = appInfo.getValueMetaData(); 1218 if(valueMetaData != null) 1219 { 1220 if (trace) 1221 { 1222 String msg = term.isWildcard() || term.isModelGroup() ? term.toString() : "element " + 1223 ((ElementBinding)term).getQName(); 1224 msg += ": unmarshalMethod=" + valueMetaData.getUnmarshalMethod(); 1225 log.trace(msg); 1226 } 1227 term.setValueMetaData(valueMetaData); 1228 } 1229 1230 boolean mapEntryKey = appInfo.isMapEntryKey(); 1231 if(mapEntryKey) 1232 { 1233 if (trace) 1234 { 1235 String msg = term.isWildcard() || term.isModelGroup() ? term.toString() : "element name=" + 1236 ((ElementBinding)term).getQName(); 1237 msg += ": is bound to a key in a map entry"; 1238 log.trace(msg); 1239 } 1240 term.setMapEntryKey(mapEntryKey); 1241 skip = Boolean.FALSE; 1242 } 1243 1244 boolean mapEntryValue = appInfo.isMapEntryValue(); 1245 if(mapEntryValue) 1246 { 1247 if (trace) 1248 { 1249 String msg = term.isWildcard() || term.isModelGroup() ? term.toString() : "element name=" + 1250 ((ElementBinding)term).getQName(); 1251 msg += ": is bound to a value in a map entry"; 1252 log.trace(msg); 1253 } 1254 term.setMapEntryValue(mapEntryValue); 1255 skip = Boolean.FALSE; 1256 } 1257 1258 boolean skipAnnotation = appInfo.isSkip(); 1259 if(skip != null) 1260 { 1261 term.setSkip(skip); 1262 } 1263 else if(skipAnnotation) 1264 { 1265 if (trace) 1266 { 1267 String msg = term.isWildcard() || term.isModelGroup() ? term.toString() : "element name=" + 1268 ((ElementBinding)term).getQName(); 1269 msg += ": will be skipped, it's attributes, character content and children will be set on the parent"; 1270 log.trace(msg); 1271 } 1272 term.setSkip(skipAnnotation ? Boolean.TRUE : Boolean.FALSE); 1273 } 1274 } 1275 } 1276 1277 private static void bindGlobalGroup(XSModelGroup group, SharedElements sharedElements) 1278 { 1279 XSObjectList particles = group.getParticles(); 1280 for(int j = 0; j < particles.getLength(); ++j) 1281 { 1282 XSParticle particle = (XSParticle)particles.item(j); 1283 XSTerm term = particle.getTerm(); 1284 switch(term.getType()) 1285 { 1286 case XSConstants.ELEMENT_DECLARATION: 1287 XSElementDeclaration element = ((XSElementDeclaration)term); 1288 sharedElements.add(element); 1289 break; 1290 case XSConstants.WILDCARD: 1291 break; 1293 case XSConstants.MODEL_GROUP: 1294 bindGlobalGroup((XSModelGroup)term, sharedElements); 1295 } 1296 } 1297 } 1298 1299 1300 1302 private static final class SharedElements 1303 { 1304 private Map elements = Collections.EMPTY_MAP; 1305 1306 public void add(XSElementDeclaration element) 1307 { 1308 switch(elements.size()) 1309 { 1310 case 0: 1311 elements = Collections.singletonMap(element, null); 1312 break; 1313 case 1: 1314 elements = new HashMap (elements); 1315 default: 1316 elements.put(element, null); 1317 } 1318 } 1319 1320 public boolean isShared(XSElementDeclaration element) 1321 { 1322 return elements.containsKey(element); 1323 } 1324 1325 public TypeBinding getTypeBinding(XSElementDeclaration element) 1326 { 1327 return (TypeBinding)elements.get(element); 1328 } 1329 1330 public void setTypeBinding(XSElementDeclaration element, TypeBinding type) 1331 { 1332 switch(elements.size()) 1333 { 1334 case 0: 1335 elements = Collections.singletonMap(element, type); 1336 break; 1337 case 1: 1338 elements = new HashMap (elements); 1339 default: 1340 elements.put(element, type); 1341 } 1342 } 1343 } 1344 1345 private static final class Context 1346 { 1347 public final SchemaBinding schema; 1348 public SharedElements sharedElements = new SharedElements(); 1349 public boolean processAnnotations = true; 1350 public boolean trace = log.isTraceEnabled(); 1351 private final List typeGroupStack = new ArrayList (); 1352 1353 public Context() 1354 { 1355 this(new SchemaBinding()); 1356 } 1357 1358 public Context(SchemaBinding schema) 1359 { 1360 this.schema = schema; 1361 } 1362 1363 public void popType() 1364 { 1365 Object o = typeGroupStack.remove(typeGroupStack.size() - 1); 1366 if(!(o instanceof TypeBinding)) 1367 { 1368 throw new JBossXBRuntimeException("Should have poped type binding but got " + o); 1369 } 1370 } 1371 1372 public void pushType(TypeBinding binding) 1373 { 1374 typeGroupStack.add(binding); 1375 } 1376 1377 public void popModelGroup() 1378 { 1379 Object o = typeGroupStack.remove(typeGroupStack.size() - 1); 1380 if(!(o instanceof ModelGroupBinding)) 1381 { 1382 throw new JBossXBRuntimeException("Should have poped model group binding but got " + o); 1383 } 1384 } 1385 1386 public void pushModelGroup(ModelGroupBinding binding) 1387 { 1388 typeGroupStack.add(binding); 1389 } 1390 1391 public Object peekTypeOrGroup() 1392 { 1393 return typeGroupStack.isEmpty() ? null : typeGroupStack.get(typeGroupStack.size() - 1); 1394 } 1395 1396 public TypeBinding peekType() 1397 { 1398 TypeBinding binding = null; 1399 for(ListIterator i = typeGroupStack.listIterator(typeGroupStack.size()); i.hasPrevious();) 1400 { 1401 Object o = i.previous(); 1402 if(o instanceof TypeBinding) 1403 { 1404 binding = (TypeBinding)o; 1405 break; 1406 } 1407 } 1408 return binding; 1409 } 1410 } 1411} 1412 | Popular Tags |