1 /*
   2  * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package com.sun.tools.internal.xjc.reader.xmlschema.bindinfo;
  27 
  28 import java.util.Collection;
  29 import java.util.Collections;
  30 
  31 import javax.xml.bind.annotation.XmlAttribute;
  32 import javax.xml.bind.annotation.XmlElement;
  33 import javax.xml.bind.annotation.XmlElementRef;
  34 import javax.xml.bind.annotation.XmlRootElement;
  35 import javax.xml.namespace.QName;
  36 
  37 import com.sun.codemodel.internal.JJavaName;
  38 import com.sun.codemodel.internal.JType;
  39 import com.sun.tools.internal.xjc.ErrorReceiver;
  40 import com.sun.tools.internal.xjc.generator.bean.field.FieldRenderer;
  41 import com.sun.tools.internal.xjc.generator.bean.field.FieldRendererFactory;
  42 import com.sun.tools.internal.xjc.generator.bean.field.IsSetFieldRenderer;
  43 import com.sun.tools.internal.xjc.model.CAttributePropertyInfo;
  44 import com.sun.tools.internal.xjc.model.CCustomizations;
  45 import com.sun.tools.internal.xjc.model.CElementPropertyInfo;
  46 import com.sun.tools.internal.xjc.model.CPropertyInfo;
  47 import com.sun.tools.internal.xjc.model.CReferencePropertyInfo;
  48 import com.sun.tools.internal.xjc.model.CValuePropertyInfo;
  49 import com.sun.tools.internal.xjc.model.TypeUse;
  50 import com.sun.tools.internal.xjc.reader.Const;
  51 import com.sun.tools.internal.xjc.reader.RawTypeSet;
  52 import com.sun.tools.internal.xjc.reader.Ring;
  53 import com.sun.tools.internal.xjc.reader.TypeUtil;
  54 import com.sun.tools.internal.xjc.reader.xmlschema.BGMBuilder;
  55 import com.sun.xml.internal.bind.api.impl.NameConverter;
  56 import com.sun.xml.internal.xsom.XSAnnotation;
  57 import com.sun.xml.internal.xsom.XSAttGroupDecl;
  58 import com.sun.xml.internal.xsom.XSAttributeDecl;
  59 import com.sun.xml.internal.xsom.XSAttributeUse;
  60 import com.sun.xml.internal.xsom.XSComplexType;
  61 import com.sun.xml.internal.xsom.XSComponent;
  62 import com.sun.xml.internal.xsom.XSContentType;
  63 import com.sun.xml.internal.xsom.XSElementDecl;
  64 import com.sun.xml.internal.xsom.XSFacet;
  65 import com.sun.xml.internal.xsom.XSIdentityConstraint;
  66 import com.sun.xml.internal.xsom.XSModelGroup;
  67 import com.sun.xml.internal.xsom.XSModelGroupDecl;
  68 import com.sun.xml.internal.xsom.XSNotation;
  69 import com.sun.xml.internal.xsom.XSParticle;
  70 import com.sun.xml.internal.xsom.XSSchema;
  71 import com.sun.xml.internal.xsom.XSSimpleType;
  72 import com.sun.xml.internal.xsom.XSWildcard;
  73 import com.sun.xml.internal.xsom.XSXPath;
  74 import com.sun.xml.internal.xsom.util.XSFinder;
  75 import com.sun.xml.internal.xsom.visitor.XSFunction;
  76 
  77 import org.xml.sax.Locator;
  78 
  79 /**
  80  * Property customization.
  81  *
  82  * This customization turns an arbitrary schema component
  83  * into a Java property (some restrictions apply.)
  84  *
  85  * <p>
  86  * All the getter methods (such as <code>getBaseType</code> or
  87  * <code>getBindStyle</code>) honors the delegation chain of
  88  * property customization specified in the spec. Namely,
  89  * if two property customizations are attached to an attribute
  90  * use and an attribute decl, then anything unspecified in the
  91  * attribute use defaults to attribute decl.
  92  *
  93  * <p>
  94  * Property customizations are acknowledged
  95  * (1) when they are actually used, and
  96  * (2) when they are given at the component, which is mapped to a class.
  97  *     (so-called "point of declaration" customization)
  98  *
  99  * @author
 100  *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
 101  */
 102 @XmlRootElement(name="property")
 103 public final class BIProperty extends AbstractDeclarationImpl {
 104 
 105     // can be null
 106     @XmlAttribute
 107     private String name = null;
 108 
 109     // can be null
 110     @XmlElement
 111     private String javadoc = null;
 112 
 113     // can be null
 114     @XmlElement
 115     private BaseTypeBean baseType = null;
 116 
 117     // TODO: report 'unsupported' error if this is true
 118     @XmlAttribute
 119     private boolean generateFailFastSetterMethod = false;
 120 
 121 
 122 
 123     public BIProperty(Locator loc, String _propName, String _javadoc,
 124                       BaseTypeBean _baseType, CollectionTypeAttribute collectionType, Boolean isConst,
 125                       OptionalPropertyMode optionalProperty, Boolean genElemProp) {
 126         super(loc);
 127 
 128         this.name = _propName;
 129         this.javadoc = _javadoc;
 130         this.baseType = _baseType;
 131         this.collectionType = collectionType;
 132         this.isConstantProperty = isConst;
 133         this.optionalProperty = optionalProperty;
 134         this.generateElementProperty = genElemProp;
 135     }
 136 
 137     protected BIProperty() {}
 138 
 139     @Override
 140     public Collection<BIDeclaration> getChildren() {
 141         BIConversion conv = getConv();
 142         if(conv==null)
 143             return super.getChildren();
 144         else
 145             return Collections.<BIDeclaration>singleton(conv);
 146     }
 147 
 148     public void setParent( BindInfo parent ) {
 149         super.setParent(parent);
 150         if(baseType!=null && baseType.conv!=null)
 151             baseType.conv.setParent(parent);
 152     }
 153 
 154 
 155 
 156     /**
 157      * Returns the customized property name.
 158      *
 159      * This method honors the "enableJavaNamingConvention" customization
 160      * and formats the property name accordingly if necessary.
 161      *
 162      * Thus the caller should <em>NOT</em> apply the XML-to-Java name
 163      * conversion algorithm to the value returned from this method.
 164      *
 165      * @param forConstant
 166      *      If the property name is intended for a constant property name,
 167      *      set to true. This will change the result
 168      *
 169      * @return
 170      *      This method can return null if the customization doesn't
 171      *      specify the name.
 172      */
 173     public String getPropertyName( boolean forConstant ) {
 174         if(name!=null) {
 175             BIGlobalBinding gb = getBuilder().getGlobalBinding();
 176             NameConverter nc = getBuilder().model.getNameConverter();
 177 
 178             if( gb.isJavaNamingConventionEnabled() && !forConstant )
 179                 // apply XML->Java conversion
 180                 return nc.toPropertyName(name);
 181             else
 182                 return name;    // ... or don't change the value
 183         }
 184         BIProperty next = getDefault();
 185         if(next!=null)  return next.getPropertyName(forConstant);
 186         else            return null;
 187     }
 188 
 189     /**
 190      * Gets the associated javadoc.
 191      *
 192      * @return
 193      *      null if none is specfieid.
 194      */
 195     public String getJavadoc() {
 196         return javadoc;
 197     }
 198 
 199     // can be null
 200     public JType getBaseType() {
 201         if(baseType!=null && baseType.name!=null) {
 202             return TypeUtil.getType(getCodeModel(),
 203                     baseType.name,
 204                     Ring.get(ErrorReceiver.class),getLocation());
 205         }
 206         BIProperty next = getDefault();
 207         if(next!=null)  return next.getBaseType();
 208         else            return null;
 209     }
 210 
 211 
 212     // can be null
 213     @XmlAttribute
 214     private CollectionTypeAttribute collectionType = null;
 215 
 216     /**
 217      * Gets the realization of this field.
 218      * @return Always return non-null.
 219      */
 220     CollectionTypeAttribute getCollectionType() {
 221         if(collectionType!=null)   return collectionType;
 222         return getDefault().getCollectionType();
 223     }
 224 
 225 
 226     @XmlAttribute
 227     private OptionalPropertyMode optionalProperty = null;
 228 
 229     // virtual property for @generateIsSetMethod
 230     @XmlAttribute
 231     void setGenerateIsSetMethod(boolean b) {
 232         optionalProperty = b ? OptionalPropertyMode.ISSET : OptionalPropertyMode.WRAPPER;
 233     }
 234 
 235     public OptionalPropertyMode getOptionalPropertyMode() {
 236         if(optionalProperty!=null)   return optionalProperty;
 237         return getDefault().getOptionalPropertyMode();
 238     }
 239 
 240     // null if delegated
 241     @XmlAttribute
 242     private Boolean generateElementProperty = null;
 243     /**
 244      * If true, the property will automatically be a reference property.
 245      * (Talk about confusing names!)
 246      */
 247     private Boolean generateElementProperty() {
 248         if(generateElementProperty!=null)   return generateElementProperty;
 249         BIProperty next = getDefault();
 250         if(next!=null)      return next.generateElementProperty();
 251 
 252         return null;
 253     }
 254 
 255 
 256     // true, false, or null (which means the value should be inherited.)
 257     @XmlAttribute(name="fixedAttributeAsConstantProperty")
 258     private Boolean isConstantProperty;
 259     /**
 260      * Gets the inherited value of the "fixedAttrToConstantProperty" customization.
 261      *
 262      * <p>
 263      * Note that returning true from this method doesn't necessarily mean
 264      * that a property needs to be mapped to a constant property.
 265      * It just means that it's mapped to a constant property
 266      * <b>if an attribute use carries a fixed value.</b>
 267      *
 268      * <p>
 269      * I don't like this semantics but that's what the spec implies.
 270      */
 271     public boolean isConstantProperty() {
 272         if(isConstantProperty!=null)    return isConstantProperty;
 273 
 274         BIProperty next = getDefault();
 275         if(next!=null)      return next.isConstantProperty();
 276 
 277         // globalBinding always has true or false in this property,
 278         // so this can't happen
 279         throw new AssertionError();
 280     }
 281 
 282     public CValuePropertyInfo createValueProperty(String defaultName,boolean forConstant,
 283         XSComponent source,TypeUse tu, QName typeName) {
 284 
 285         markAsAcknowledged();
 286         constantPropertyErrorCheck();
 287 
 288         String name = getPropertyName(forConstant);
 289         if(name==null) {
 290             name = defaultName;
 291             if(tu.isCollection() && getBuilder().getGlobalBinding().isSimpleMode())
 292                 name = JJavaName.getPluralForm(name);
 293         }
 294 
 295         CValuePropertyInfo prop = wrapUp(new CValuePropertyInfo(name, source, getCustomizations(source), source.getLocator(), tu, typeName), source);
 296         BIInlineBinaryData.handle(source, prop);
 297         return prop;
 298     }
 299 
 300     public CAttributePropertyInfo createAttributeProperty( XSAttributeUse use, TypeUse tu ) {
 301 
 302         boolean forConstant =
 303             getCustomization(use).isConstantProperty() &&
 304             use.getFixedValue()!=null;
 305 
 306         String name = getPropertyName(forConstant);
 307         if(name==null) {
 308             NameConverter conv = getBuilder().getNameConverter();
 309             if(forConstant)
 310                 name = conv.toConstantName(use.getDecl().getName());
 311             else
 312                 name = conv.toPropertyName(use.getDecl().getName());
 313             if(tu.isCollection() && getBuilder().getGlobalBinding().isSimpleMode())
 314                 name = JJavaName.getPluralForm(name);
 315         }
 316 
 317         markAsAcknowledged();
 318         constantPropertyErrorCheck();
 319 
 320         return wrapUp(new CAttributePropertyInfo(name,use,getCustomizations(use),use.getLocator(),
 321                 BGMBuilder.getName(use.getDecl()), tu,
 322                 BGMBuilder.getName(use.getDecl().getType()), use.isRequired() ),use);
 323     }
 324 
 325     /**
 326      *
 327      *
 328      * @param defaultName
 329      *      If the name is not customized, this name will be used
 330      *      as the default. Note that the name conversion <b>MUST</b>
 331      *      be applied before this method is called if necessary.
 332      * @param source
 333      *      Source schema component from which a field is built.
 334      */
 335     public CElementPropertyInfo createElementProperty(String defaultName, boolean forConstant, XSParticle source,
 336                                                       RawTypeSet types) {
 337 
 338         if(!types.refs.isEmpty())
 339             // if this property is empty, don't acknowleedge the customization
 340             // this allows pointless property customization to be reported as an error
 341             markAsAcknowledged();
 342         constantPropertyErrorCheck();
 343 
 344         String name = getPropertyName(forConstant);
 345         if(name==null)
 346             name = defaultName;
 347 
 348         CElementPropertyInfo prop = wrapUp(
 349             new CElementPropertyInfo(
 350                 name, types.getCollectionMode(),
 351                 types.id(),
 352                 types.getExpectedMimeType(),
 353                 source, getCustomizations(source),
 354                 source.getLocator(), types.isRequired()),
 355             source);
 356 
 357         types.addTo(prop);
 358 
 359         BIInlineBinaryData.handle(source.getTerm(), prop);
 360         return prop;
 361     }
 362 
 363     public CReferencePropertyInfo createDummyExtendedMixedReferenceProperty(
 364             String defaultName, XSComponent source, RawTypeSet types) {
 365             return createReferenceProperty(
 366                     defaultName,
 367                     false,
 368                     source,
 369                     types,
 370                     true,
 371                     true,
 372                     false,
 373                     true);
 374     }
 375 
 376     public CReferencePropertyInfo createContentExtendedMixedReferenceProperty(
 377             String defaultName, XSComponent source, RawTypeSet types) {
 378             return createReferenceProperty(
 379                     defaultName,
 380                     false,
 381                     source,
 382                     types,
 383                     true,
 384                     false,
 385                     true,
 386                     true);
 387     }
 388 
 389     public CReferencePropertyInfo createReferenceProperty(
 390             String defaultName, boolean forConstant, XSComponent source,
 391             RawTypeSet types, boolean isMixed, boolean dummy, boolean content, boolean isMixedExtended) {
 392 
 393         if (types == null) {    // this is a special case where we need to generate content because potential subtypes would need to be able to override what's store inside
 394             content = true;
 395         } else {
 396             if(!types.refs.isEmpty())
 397                 // if this property is empty, don't acknowleedge the customization
 398                 // this allows pointless property customization to be reported as an error
 399                 markAsAcknowledged();
 400         }
 401         constantPropertyErrorCheck();
 402 
 403         String name = getPropertyName(forConstant);
 404         if(name==null)
 405             name = defaultName;
 406 
 407         CReferencePropertyInfo prop = wrapUp(
 408                                             new CReferencePropertyInfo(
 409                                                 name,
 410                                                 (types == null) ? true : types.getCollectionMode().isRepeated()||isMixed,
 411                                                 (types == null) ? false : types.isRequired(),
 412                                                 isMixed,
 413                                                 source,
 414                                                 getCustomizations(source), source.getLocator(), dummy, content, isMixedExtended),
 415                                         source);
 416         if (types != null) {
 417             types.addTo(prop);
 418         }
 419 
 420         BIInlineBinaryData.handle(source, prop);
 421         return prop;
 422     }
 423 
 424     public CPropertyInfo createElementOrReferenceProperty(
 425             String defaultName, boolean forConstant, XSParticle source,
 426             RawTypeSet types) {
 427 
 428         boolean generateRef;
 429 
 430         switch(types.canBeTypeRefs) {
 431         case CAN_BE_TYPEREF:
 432         case SHOULD_BE_TYPEREF:
 433             // it's up to the use
 434             Boolean b = generateElementProperty();
 435             if(b==null) // follow XJC recommendation
 436                 generateRef = types.canBeTypeRefs== RawTypeSet.Mode.CAN_BE_TYPEREF;
 437             else // use the value user gave us
 438                 generateRef = b;
 439             break;
 440         case MUST_BE_REFERENCE:
 441             generateRef = true;
 442             break;
 443         default:
 444             throw new AssertionError();
 445         }
 446 
 447         if(generateRef) {
 448             return createReferenceProperty(defaultName,forConstant,source,types, false, false, false, false);
 449         } else {
 450             return createElementProperty(defaultName,forConstant,source,types);
 451         }
 452     }
 453 
 454     /**
 455      * Common finalization of {@link CPropertyInfo} for the create***Property methods.
 456      */
 457     private <T extends CPropertyInfo> T wrapUp(T prop, XSComponent source) {
 458         prop.javadoc = concat(javadoc,
 459             getBuilder().getBindInfo(source).getDocumentation());
 460         if(prop.javadoc==null)
 461             prop.javadoc="";
 462 
 463         // decide the realization.
 464         FieldRenderer r;
 465         OptionalPropertyMode opm = getOptionalPropertyMode();
 466         if(prop.isCollection()) {
 467             CollectionTypeAttribute ct = getCollectionType();
 468             r = ct.get(getBuilder().model);
 469         } else {
 470             FieldRendererFactory frf = getBuilder().fieldRendererFactory;
 471 
 472             if(prop.isOptionalPrimitive()) {
 473                 // the property type can be primitive type if we are to ignore absence
 474                 switch(opm) {
 475                 case PRIMITIVE:
 476                     r = frf.getRequiredUnboxed();
 477                     break;
 478                 case WRAPPER:
 479                     // force the wrapper type
 480                     r = frf.getSingle();
 481                     break;
 482                 case ISSET:
 483                     r = frf.getSinglePrimitiveAccess();
 484                     break;
 485                 default:
 486                     throw new Error();
 487                 }
 488             } else {
 489                 r = frf.getDefault();
 490             }
 491         }
 492         if(opm==OptionalPropertyMode.ISSET) {
 493             // only isSet is allowed on a collection. these 3 modes aren't really symmetric.
 494 
 495             // if the property is a primitive type, we need an explicit unset because
 496             // we can't overload the meaning of set(null).
 497             // if it's a collection, we need to be able to unset it so that we can distinguish
 498             // null list and empty list.
 499             r = new IsSetFieldRenderer( r, prop.isOptionalPrimitive()||prop.isCollection(), true );
 500         }
 501 
 502         prop.realization = r;
 503 
 504         JType bt = getBaseType();
 505         if(bt!=null)
 506             prop.baseType = bt;
 507 
 508         return prop;
 509     }
 510 
 511     private CCustomizations getCustomizations( XSComponent src ) {
 512         return getBuilder().getBindInfo(src).toCustomizationList();
 513     }
 514 
 515     private CCustomizations getCustomizations( XSComponent... src ) {
 516         CCustomizations c = null;
 517         for (XSComponent s : src) {
 518             CCustomizations r = getCustomizations(s);
 519             if(c==null)     c = r;
 520             else            c = CCustomizations.merge(c,r);
 521         }
 522         return c;
 523     }
 524 
 525     private CCustomizations getCustomizations( XSAttributeUse src ) {
 526         // customizations for an attribute use should include those defined in the local attribute.
 527         // this is so that the schema like:
 528         //
 529         // <xs:attribute name="foo" type="xs:int">
 530         //   <xs:annotation><xs:appinfo>
 531         //     <hyperjaxb:... />
 532         //
 533         // would be picked up
 534         if(src.getDecl().isLocal())
 535             return getCustomizations(src,src.getDecl());
 536         else
 537             return getCustomizations((XSComponent)src);
 538     }
 539 
 540     private CCustomizations getCustomizations( XSParticle src ) {
 541         // customizations for a particle  should include those defined in the term unless it's global
 542         // this is so that the schema like:
 543         //
 544         // <xs:sequence>
 545         //   <xs:element name="foo" type="xs:int">
 546         //     <xs:annotation><xs:appinfo>
 547         //       <hyperjaxb:... />
 548         //
 549         // would be picked up
 550         if(src.getTerm().isElementDecl()) {
 551             XSElementDecl xed = src.getTerm().asElementDecl();
 552             if(xed.isGlobal())
 553                 return getCustomizations((XSComponent)src);
 554         }
 555 
 556         return getCustomizations(src,src.getTerm());
 557     }
 558 
 559 
 560 
 561     public void markAsAcknowledged() {
 562         if( isAcknowledged() )  return;
 563 
 564         // mark the parent as well.
 565         super.markAsAcknowledged();
 566 
 567         BIProperty def = getDefault();
 568         if(def!=null)   def.markAsAcknowledged();
 569     }
 570 
 571     private void constantPropertyErrorCheck() {
 572         if( isConstantProperty!=null && getOwner()!=null ) {
 573             // run additional check on the isCOnstantProperty value.
 574             // this value is not allowed if the schema component doesn't have
 575             // a fixed value constraint.
 576             //
 577             // the setParent method associates a customization with the rest of
 578             // XSOM object graph, so this is the earliest possible moment where
 579             // we can test this.
 580 
 581             if( !hasFixedValue.find(getOwner()) ) {
 582                 Ring.get(ErrorReceiver.class).error(
 583                     getLocation(),
 584                     Messages.ERR_ILLEGAL_FIXEDATTR.format()
 585                 );
 586                 // set this value to null to avoid the same error to be reported more than once.
 587                 isConstantProperty = null;
 588             }
 589         }
 590     }
 591 
 592     /**
 593      * Function object that returns true if a component has
 594      * a fixed value constraint.
 595      */
 596     private final XSFinder hasFixedValue = new XSFinder() {
 597         public Boolean attributeDecl(XSAttributeDecl decl) {
 598             return decl.getFixedValue()!=null;
 599         }
 600 
 601         public Boolean attributeUse(XSAttributeUse use) {
 602             return use.getFixedValue()!=null;
 603         }
 604 
 605         public Boolean schema(XSSchema s) {
 606             // we allow globalBindings to have isConstantProperty==true,
 607             // so this method returns true to allow this.
 608             return true;
 609         }
 610     };
 611 
 612     /**
 613      * Finds a BIProperty which this object should delegate to.
 614      *
 615      * @return
 616      *      always return non-null for normal BIProperties.
 617      *      If this object is contained in the BIGlobalBinding, then
 618      *      this method returns null to indicate that there's no more default.
 619      */
 620     protected BIProperty getDefault() {
 621         if(getOwner()==null)    return null;
 622         BIProperty next = getDefault(getBuilder(),getOwner());
 623         if(next==this)  return null;    // global.
 624         else            return next;
 625     }
 626 
 627     private static BIProperty getDefault( BGMBuilder builder, XSComponent c ) {
 628         while(c!=null) {
 629             c = c.apply(defaultCustomizationFinder);
 630             if(c!=null) {
 631                 BIProperty prop = builder.getBindInfo(c).get(BIProperty.class);
 632                 if(prop!=null)  return prop;
 633             }
 634         }
 635 
 636         // default to the global one
 637         return builder.getGlobalBinding().getDefaultProperty();
 638     }
 639 
 640 
 641     /**
 642      * Finds a property customization that describes how the given
 643      * component should be mapped to a property (if it's mapped to
 644      * a property at all.)
 645      *
 646      * <p>
 647      * Consider an attribute use that does NOT carry a property
 648      * customization. This schema component is nonetheless considered
 649      * to carry a (sort of) implicit property customization, whose values
 650      * are defaulted.
 651      *
 652      * <p>
 653      * This method can be think of the method that returns this implied
 654      * property customization.
 655      *
 656      * <p>
 657      * Note that this doesn't mean the given component needs to be
 658      * mapped to a property. But if it does map to a property, it needs
 659      * to follow this customization.
 660      *
 661      * I think this semantics is next to non-sense but I couldn't think
 662      * of any other way to follow the spec.
 663      *
 664      * @param c
 665      *      A customization effective on this component will be returned.
 666      *      Can be null just to get the global customization.
 667      * @return
 668      *      Always return non-null valid object.
 669      */
 670     public static BIProperty getCustomization( XSComponent c ) {
 671         BGMBuilder builder = Ring.get(BGMBuilder.class);
 672 
 673         // look for a customization on this component
 674         if( c!=null ) {
 675             BIProperty prop = builder.getBindInfo(c).get(BIProperty.class);
 676             if(prop!=null)  return prop;
 677         }
 678 
 679         // if no such thing exists, defeault.
 680         return getDefault(builder,c);
 681     }
 682 
 683     private final static XSFunction<XSComponent> defaultCustomizationFinder = new XSFunction<XSComponent>() {
 684 
 685         public XSComponent attributeUse(XSAttributeUse use) {
 686             return use.getDecl();   // inherit from the declaration
 687         }
 688 
 689         public XSComponent particle(XSParticle particle) {
 690             return particle.getTerm(); // inherit from the term
 691         }
 692 
 693         public XSComponent schema(XSSchema schema) {
 694             // no more delegation
 695             return null;
 696         }
 697 
 698         // delegates to the context schema object
 699         public XSComponent attributeDecl(XSAttributeDecl decl) { return decl.getOwnerSchema(); }
 700         public XSComponent wildcard(XSWildcard wc) { return wc.getOwnerSchema(); }
 701         public XSComponent modelGroupDecl(XSModelGroupDecl decl) { return decl.getOwnerSchema(); }
 702         public XSComponent modelGroup(XSModelGroup group) { return group.getOwnerSchema(); }
 703         public XSComponent elementDecl(XSElementDecl decl) { return decl.getOwnerSchema(); }
 704         public XSComponent complexType(XSComplexType type) { return type.getOwnerSchema(); }
 705         public XSComponent simpleType(XSSimpleType st) { return st.getOwnerSchema(); }
 706 
 707         // property customizations are not allowed on these components.
 708         public XSComponent attGroupDecl(XSAttGroupDecl decl) { throw new IllegalStateException(); }
 709         public XSComponent empty(XSContentType empty) { throw new IllegalStateException(); }
 710         public XSComponent annotation(XSAnnotation xsAnnotation) { throw new IllegalStateException(); }
 711         public XSComponent facet(XSFacet xsFacet) { throw new IllegalStateException(); }
 712         public XSComponent notation(XSNotation xsNotation) { throw new IllegalStateException(); }
 713         public XSComponent identityConstraint(XSIdentityConstraint x) { throw new IllegalStateException(); }
 714         public XSComponent xpath(XSXPath xsxPath) { throw new IllegalStateException(); }
 715     };
 716 
 717 
 718     private static String concat( String s1, String s2 ) {
 719         if(s1==null)    return s2;
 720         if(s2==null)    return s1;
 721         return s1+"\n\n"+s2;
 722     }
 723 
 724     public QName getName() { return NAME; }
 725 
 726     /** Name of this declaration. */
 727     public static final QName NAME = new QName(
 728         Const.JAXB_NSURI, "property" );
 729 
 730     public BIConversion getConv() {
 731         if(baseType!=null)
 732             return baseType.conv;
 733         else
 734             return null;
 735     }
 736 
 737     private static final class BaseTypeBean {
 738         /**
 739          * If there's a nested javaType customization, this field
 740          * will keep that customization. Otherwise null.
 741          *
 742          * This customization, if present, is used to customize
 743          * the simple type mapping at the point of reference.
 744          */
 745         @XmlElementRef
 746         BIConversion conv;
 747 
 748         /**
 749          * Java type name.
 750          */
 751         @XmlAttribute
 752         String name;
 753     }
 754 }