src/share/jaxws_classes/com/sun/tools/internal/xjc/reader/xmlschema/SimpleTypeBuilder.java

Tue, 06 Mar 2012 16:09:35 -0800

author
ohair
date
Tue, 06 Mar 2012 16:09:35 -0800
changeset 286
f50545b5e2f1
child 368
0989ad8c0860
permissions
-rw-r--r--

7150322: Stop using drop source bundles in jaxws
Reviewed-by: darcy, ohrstrom

     1 /*
     2  * Copyright (c) 1997, 2011, 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  */
    26 package com.sun.tools.internal.xjc.reader.xmlschema;
    28 import java.io.StringWriter;
    29 import java.math.BigInteger;
    30 import java.text.ParseException;
    31 import java.util.ArrayList;
    32 import java.util.Arrays;
    33 import java.util.Collections;
    34 import java.util.HashMap;
    35 import java.util.HashSet;
    36 import java.util.List;
    37 import java.util.Map;
    38 import java.util.Set;
    39 import java.util.Stack;
    41 import javax.activation.MimeTypeParseException;
    43 import com.sun.codemodel.internal.JJavaName;
    44 import com.sun.codemodel.internal.util.JavadocEscapeWriter;
    45 import com.sun.tools.internal.xjc.ErrorReceiver;
    46 import com.sun.tools.internal.xjc.model.CBuiltinLeafInfo;
    47 import com.sun.tools.internal.xjc.model.CClassInfo;
    48 import com.sun.tools.internal.xjc.model.CClassInfoParent;
    49 import com.sun.tools.internal.xjc.model.CClassRef;
    50 import com.sun.tools.internal.xjc.model.CEnumConstant;
    51 import com.sun.tools.internal.xjc.model.CEnumLeafInfo;
    52 import com.sun.tools.internal.xjc.model.CNonElement;
    53 import com.sun.tools.internal.xjc.model.Model;
    54 import com.sun.tools.internal.xjc.model.TypeUse;
    55 import com.sun.tools.internal.xjc.model.TypeUseFactory;
    56 import com.sun.tools.internal.xjc.reader.Const;
    57 import com.sun.tools.internal.xjc.reader.Ring;
    58 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIConversion;
    59 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIEnum;
    60 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIEnumMember;
    61 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BIProperty;
    62 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.BindInfo;
    63 import com.sun.tools.internal.xjc.reader.xmlschema.bindinfo.EnumMemberMode;
    64 import com.sun.tools.internal.xjc.util.MimeTypeRange;
    65 import com.sun.xml.internal.bind.DatatypeConverterImpl;
    66 import com.sun.xml.internal.bind.v2.WellKnownNamespace;
    67 import static com.sun.xml.internal.bind.v2.WellKnownNamespace.XML_MIME_URI;
    68 import com.sun.xml.internal.bind.v2.runtime.SwaRefAdapter;
    69 import com.sun.xml.internal.xsom.XSAttributeDecl;
    70 import com.sun.xml.internal.xsom.XSComplexType;
    71 import com.sun.xml.internal.xsom.XSComponent;
    72 import com.sun.xml.internal.xsom.XSElementDecl;
    73 import com.sun.xml.internal.xsom.XSFacet;
    74 import com.sun.xml.internal.xsom.XSListSimpleType;
    75 import com.sun.xml.internal.xsom.XSRestrictionSimpleType;
    76 import com.sun.xml.internal.xsom.XSSimpleType;
    77 import com.sun.xml.internal.xsom.XSUnionSimpleType;
    78 import com.sun.xml.internal.xsom.XSVariety;
    79 import com.sun.xml.internal.xsom.impl.util.SchemaWriter;
    80 import com.sun.xml.internal.xsom.visitor.XSSimpleTypeFunction;
    81 import com.sun.xml.internal.xsom.visitor.XSVisitor;
    83 import org.xml.sax.Locator;
    85 /**
    86  * Builds {@link TypeUse} from simple types.
    87  *
    88  * <p>
    89  * This code consists of two main portions. The {@link #compose(XSSimpleType)} method
    90  * and {@link #composer} forms an outer cycle, which gradually ascends the type
    91  * inheritance chain until it finds the suitable binding. When it does this
    92  * {@link #initiatingType} is set to the type which started binding, so that we can refer
    93  * to the actual constraint facets and such that are applicable on the type.
    94  *
    95  * <p>
    96  * For each intermediate type in the chain, the {@link #find(XSSimpleType)} method
    97  * is used to find the binding on that type, sine the outer loop is doing the ascending,
    98  * this method only sees if the current type has some binding available.
    99  *
   100  * <p>
   101  * There is at least one ugly code that you need to aware of
   102  * when you are modifying the code. See the documentation
   103  * about <a href="package.html#stref_cust">
   104  * "simple type customization at the point of reference."</a>
   105  *
   106  *
   107  * @author
   108  *     Kohsuke Kawaguchi (kohsuke.kawaguchi@sun.com)
   109  */
   110 public final class SimpleTypeBuilder extends BindingComponent {
   112     protected final BGMBuilder builder = Ring.get(BGMBuilder.class);
   114     private final Model model = Ring.get(Model.class);
   116     /**
   117      * The component that is refering to the simple type
   118      * which we are building. This is ugly but necessary
   119      * to support the customization of simple types at
   120      * its point of reference. See my comment at the header
   121      * of this class for details.
   122      *
   123      * UGLY: Implemented as a Stack of XSComponent to fix a bug
   124      */
   125     public final Stack<XSComponent> refererStack = new Stack<XSComponent>();
   127     /**
   128      * Records what xmime:expectedContentTypes annotations we honored and processed,
   129      * so that we can later check if the user had these annotations in the places
   130      * where we didn't anticipate them.
   131      */
   132     private final Set<XSComponent> acknowledgedXmimeContentTypes = new HashSet<XSComponent>();
   134     /**
   135      * The type that was originally passed to this {@link SimpleTypeBuilder#build(XSSimpleType)}.
   136      * Never null.
   137      */
   138     private XSSimpleType initiatingType;
   140     /** {@link TypeUse}s for the built-in types. Read-only. */
   141     public static final Map<String,TypeUse> builtinConversions = new HashMap<String,TypeUse>();
   144     /**
   145      * Entry point from outside. Builds a BGM type expression
   146      * from a simple type schema component.
   147      *
   148      * @param type
   149      *      the simple type to be bound.
   150      */
   151     public TypeUse build( XSSimpleType type ) {
   152         XSSimpleType oldi = initiatingType;
   153         this.initiatingType = type;
   155         TypeUse e = checkRefererCustomization(type);
   156         if(e==null)
   157             e = compose(type);
   159         initiatingType = oldi;
   161         return e;
   162     }
   164     /**
   165      * A version of the {@link #build(XSSimpleType)} method
   166      * used to bind the definition of a class generated from
   167      * the given simple type.
   168      */
   169     public TypeUse buildDef( XSSimpleType type ) {
   170         XSSimpleType oldi = initiatingType;
   171         this.initiatingType = type;
   173         TypeUse e = type.apply(composer);
   175         initiatingType = oldi;
   177         return e;
   178     }
   181     /**
   182      * Returns a javaType customization specified to the referer, if present.
   183      * @return can be null.
   184      */
   185     private BIConversion getRefererCustomization() {
   186         BindInfo info = builder.getBindInfo(getReferer());
   187         BIProperty prop = info.get(BIProperty.class);
   188         if(prop==null)  return null;
   189         return prop.getConv();
   190     }
   192     public XSComponent getReferer() {
   193         return refererStack.peek();
   194     }
   196     /**
   197      * Checks if the referer has a conversion customization or not.
   198      * If it does, use it to bind this simple type. Otherwise
   199      * return null;
   200      */
   201     private TypeUse checkRefererCustomization( XSSimpleType type ) {
   203         // assertion check. referer must be set properly
   204         // before the build method is called.
   205         // since the handling of the simple type point-of-reference
   206         // customization is very error prone, it deserves a strict
   207         // assertion check.
   208         // UGLY CODE WARNING
   209         XSComponent top = getReferer();
   211         if( top instanceof XSElementDecl ) {
   212             // if the parent is element type, its content type must be us.
   213             XSElementDecl eref = (XSElementDecl)top;
   214             assert eref.getType()==type;
   216             // for elements, you can't use <property>,
   217             // so we allow javaType to appear directly.
   218             BindInfo info = builder.getBindInfo(top);
   219             BIConversion conv = info.get(BIConversion.class);
   220             if(conv!=null) {
   221                 conv.markAsAcknowledged();
   222                 // the conversion is given.
   223                 return conv.getTypeUse(type);
   224             }
   225             detectJavaTypeCustomization();
   226         } else
   227         if( top instanceof XSAttributeDecl ) {
   228             XSAttributeDecl aref = (XSAttributeDecl)top;
   229             assert aref.getType()==type;
   230             detectJavaTypeCustomization();
   231         } else
   232         if( top instanceof XSComplexType ) {
   233             XSComplexType tref = (XSComplexType)top;
   234             assert tref.getBaseType()==type || tref.getContentType()==type;
   235             detectJavaTypeCustomization();
   236         } else
   237         if( top == type ) {
   238             // this means the simple type is built by itself and
   239             // not because it's referenced by something.
   240         } else
   241             // unexpected referer type.
   242             assert false;
   244         // now we are certain that the referer is OK.
   245         // see if it has a conversion customization.
   246         BIConversion conv = getRefererCustomization();
   247         if(conv!=null) {
   248             conv.markAsAcknowledged();
   249             // the conversion is given.
   250             return conv.getTypeUse(type);
   251         } else
   252             // not found
   253             return null;
   254     }
   256     /**
   257      * Detect "javaType" customizations placed directly on simple types, rather
   258      * than being enclosed by "property" and "baseType" customizations (see
   259      * sec 6.8.1 of the spec).
   260      *
   261      * Report an error if any exist.
   262      */
   263     private void detectJavaTypeCustomization() {
   264         BindInfo info = builder.getBindInfo(getReferer());
   265         BIConversion conv = info.get(BIConversion.class);
   267         if( conv != null ) {
   268             // ack this conversion to prevent further error messages
   269             conv.markAsAcknowledged();
   271             // report the error
   272             getErrorReporter().error( conv.getLocation(),
   273                     Messages.ERR_UNNESTED_JAVATYPE_CUSTOMIZATION_ON_SIMPLETYPE );
   274         }
   275     }
   277     /**
   278      * Recursively decend the type inheritance chain to find a binding.
   279      */
   280     TypeUse compose( XSSimpleType t ) {
   281         TypeUse e = find(t);
   282         if(e!=null)     return e;
   283         return t.apply(composer);
   284     }
   286     public final XSSimpleTypeFunction<TypeUse> composer = new XSSimpleTypeFunction<TypeUse>() {
   288         public TypeUse listSimpleType(XSListSimpleType type) {
   289             // bind item type individually and then compose them into a list
   290             // facets on the list shouldn't be taken account when binding item types,
   291             // so weed to call build(), not compose().
   292             XSSimpleType itemType = type.getItemType();
   293             refererStack.push(itemType);
   294             TypeUse tu = TypeUseFactory.makeCollection(build(type.getItemType()));
   295             refererStack.pop();
   296             return tu;
   297         }
   299         public TypeUse unionSimpleType(XSUnionSimpleType type) {
   300             boolean isCollection = false;
   301             for( int i=0; i<type.getMemberSize(); i++ )
   302                 if(type.getMember(i).getVariety()==XSVariety.LIST || type.getMember(i).getVariety()==XSVariety.UNION) {
   303                     isCollection = true;
   304                     break;
   305                 }
   307             TypeUse r = CBuiltinLeafInfo.STRING;
   308             if(isCollection)
   309                 r = TypeUseFactory.makeCollection(r);
   310             return r;
   311         }
   313         public TypeUse restrictionSimpleType(XSRestrictionSimpleType type) {
   314             // just process the base type.
   315             return compose(type.getSimpleBaseType());
   316         }
   317     };
   320     /**
   321      * Checks if there's any binding available on the given type.
   322      *
   323      * @return
   324      *      null if not (which causes the {@link #compose(XSSimpleType)} method
   325      *      to do ascending.
   326      */
   327     private TypeUse find( XSSimpleType type ) {
   328         TypeUse r;
   329         boolean noAutoEnum = false;
   331         // check for user specified conversion
   332         BindInfo info = builder.getBindInfo(type);
   333         BIConversion conv = info.get(BIConversion.class);
   335         if( conv!=null ) {
   336             // a conversion was found
   337             conv.markAsAcknowledged();
   338             return conv.getTypeUse(type);
   339         }
   341         // look for enum customization, which is another user specified conversion
   342         BIEnum en = info.get(BIEnum.class);
   343         if( en!=null ) {
   344             en.markAsAcknowledged();
   346             if(!en.isMapped()) {
   347                 noAutoEnum = true;
   348             } else {
   349                 // if an enum customization is specified, make sure
   350                 // the type is OK
   351                 if( !canBeMappedToTypeSafeEnum(type) ) {
   352                     getErrorReporter().error( en.getLocation(),
   353                         Messages.ERR_CANNOT_BE_TYPE_SAFE_ENUM );
   354                     getErrorReporter().error( type.getLocator(),
   355                         Messages.ERR_CANNOT_BE_TYPE_SAFE_ENUM_LOCATION );
   356                     // recover by ignoring this customization
   357                     return null;
   358                 }
   360                 // reference?
   361                 if(en.ref!=null) {
   362                     if(!JJavaName.isFullyQualifiedClassName(en.ref)) {
   363                         Ring.get(ErrorReceiver.class).error( en.getLocation(),
   364                             Messages.format(Messages.ERR_INCORRECT_CLASS_NAME, en.ref) );
   365                         // recover by ignoring @ref
   366                         return null;
   367                     }
   369                     return new CClassRef(model, type, en, info.toCustomizationList() );
   370                 }
   372                 // list and union cannot be mapped to a type-safe enum,
   373                 // so in this stage we can safely cast it to XSRestrictionSimpleType
   374                 return bindToTypeSafeEnum( (XSRestrictionSimpleType)type,
   375                         en.className, en.javadoc, en.members,
   376                         getEnumMemberMode().getModeWithEnum(),
   377                         en.getLocation() );
   378             }
   379         }
   382         // if the type is built in, look for the default binding
   383         if(type.getTargetNamespace().equals(WellKnownNamespace.XML_SCHEMA)) {
   384             String name = type.getName();
   385             if(name!=null) {
   386                 r = lookupBuiltin(name);
   387                 if(r!=null)
   388                     return r;
   389             }
   390         }
   392         // also check for swaRef
   393         if(type.getTargetNamespace().equals(WellKnownNamespace.SWA_URI)) {
   394             String name = type.getName();
   395             if(name!=null && name.equals("swaRef"))
   396                 return CBuiltinLeafInfo.STRING.makeAdapted(SwaRefAdapter.class,false);
   397         }
   400         // see if this type should be mapped to a type-safe enumeration by default.
   401         // if so, built a EnumXDucer from it and return it.
   402         if(type.isRestriction() && !noAutoEnum) {
   403             XSRestrictionSimpleType rst = type.asRestriction();
   404             if(shouldBeMappedToTypeSafeEnumByDefault(rst)) {
   405                 r = bindToTypeSafeEnum(rst,null,null, Collections.<String, BIEnumMember>emptyMap(),
   406                             getEnumMemberMode(),null);
   407                 if(r!=null)
   408                     return r;
   409             }
   410         }
   412         return (CNonElement)getClassSelector()._bindToClass(type,null,false);
   413     }
   415     private static Set<XSRestrictionSimpleType> reportedEnumMemberSizeWarnings;
   417     /**
   418      * Returns true if a type-safe enum should be created from
   419      * the given simple type by default without an explicit &lt;jaxb:enum> customization.
   420      */
   421     private boolean shouldBeMappedToTypeSafeEnumByDefault( XSRestrictionSimpleType type ) {
   423         // if not, there will be a problem wrt the class name of this type safe enum type.
   424         if( type.isLocal() )    return false;
   426         // if redefined, we should map the new definition, not the old one.
   427         if( type.getRedefinedBy()!=null )   return false;
   429         List<XSFacet> facets = type.getDeclaredFacets(XSFacet.FACET_ENUMERATION);
   430         if( facets.isEmpty() )
   431             // if the type itself doesn't have the enumeration facet,
   432             // it won't be mapped to a type-safe enum.
   433             return false;
   435         if(facets.size() > builder.getGlobalBinding().getDefaultEnumMemberSizeCap()) {
   436             // if there are too many facets, it's not very useful
   437             // produce warning when simple type is not mapped to enum
   438             // see issue https://jaxb.dev.java.net/issues/show_bug.cgi?id=711
   440             if(reportedEnumMemberSizeWarnings == null)
   441                 reportedEnumMemberSizeWarnings = new HashSet<XSRestrictionSimpleType>();
   443             if(!reportedEnumMemberSizeWarnings.contains(type)) {
   444                 getErrorReporter().warning(type.getLocator(), Messages.WARN_ENUM_MEMBER_SIZE_CAP,
   445                         type.getName(), facets.size(), builder.getGlobalBinding().getDefaultEnumMemberSizeCap());
   447                 reportedEnumMemberSizeWarnings.add(type);
   448             }
   450             return false;
   451         }
   453         if( !canBeMappedToTypeSafeEnum(type) )
   454             // we simply can't map this to an enumeration
   455             return false;
   457         // check for collisions among constant names. if a collision will happen,
   458         // don't try to bind it to an enum.
   460         // return true only when this type is derived from one of the "enum base type".
   461         for( XSSimpleType t = type; t!=null; t=t.getSimpleBaseType() )
   462             if( t.isGlobal() && builder.getGlobalBinding().canBeMappedToTypeSafeEnum(t) )
   463                 return true;
   465         return false;
   466     }
   469     private static final Set<String> builtinTypeSafeEnumCapableTypes;
   471     static {
   472         Set<String> s = new HashSet<String>();
   474         // see a bullet of 6.5.1 of the spec.
   475         String[] typeNames = new String[] {
   476             "string", "boolean", "float", "decimal", "double", "anyURI"
   477         };
   478         s.addAll(Arrays.asList(typeNames));
   480         builtinTypeSafeEnumCapableTypes = Collections.unmodifiableSet(s);
   481     }
   484     /**
   485      * Returns true if the given simple type can be mapped to a
   486      * type-safe enum class.
   487      *
   488      * <p>
   489      * JAXB spec places a restrictrion as to what type can be
   490      * mapped to a type-safe enum. This method enforces this
   491      * constraint.
   492      */
   493     public static boolean canBeMappedToTypeSafeEnum( XSSimpleType type ) {
   494         do {
   495             if( WellKnownNamespace.XML_SCHEMA.equals(type.getTargetNamespace()) ) {
   496                 // type must be derived from one of these types
   497                 String localName = type.getName();
   498                 if( localName!=null ) {
   499                     if( localName.equals("anySimpleType") )
   500                         return false;   // catch all case
   501                     if( localName.equals("ID") || localName.equals("IDREF") )
   502                         return false;   // not ID/IDREF
   504                     // other allowed list
   505                     if( builtinTypeSafeEnumCapableTypes.contains(localName) )
   506                         return true;
   507                 }
   508             }
   510             type = type.getSimpleBaseType();
   511         } while( type!=null );
   513         return false;
   514     }
   518     /**
   519      * Builds a type-safe enum conversion from a simple type
   520      * with enumeration facets.
   521      *
   522      * @param className
   523      *      The class name of the type-safe enum. Or null to
   524      *      create a default name.
   525      * @param javadoc
   526      *      Additional javadoc that will be added at the beginning of the
   527      *      class, or null if none is necessary.
   528      * @param members
   529      *      A map from enumeration values (as String) to BIEnumMember objects.
   530      *      if some of the value names need to be overrided.
   531      *      Cannot be null, but the map may not contain entries
   532      *      for all enumeration values.
   533      * @param loc
   534      *      The source location where the above customizations are
   535      *      specified, or null if none is available.
   536      */
   537     private TypeUse bindToTypeSafeEnum( XSRestrictionSimpleType type,
   538                                         String className, String javadoc, Map<String,BIEnumMember> members,
   539                                         EnumMemberMode mode, Locator loc ) {
   541         if( loc==null )  // use the location of the simple type as the default
   542             loc = type.getLocator();
   544         if( className==null ) {
   545             // infer the class name. For this to be possible,
   546             // the simple type must be a global one.
   547             if( !type.isGlobal() ) {
   548                 getErrorReporter().error( loc, Messages.ERR_NO_ENUM_NAME_AVAILABLE );
   549                 // recover by returning a meaningless conversion
   550                 return CBuiltinLeafInfo.STRING;
   551             }
   552             className = type.getName();
   553         }
   555         // we apply name conversion in any case
   556         className = builder.deriveName(className,type);
   558         {// compute Javadoc
   559             StringWriter out = new StringWriter();
   560             SchemaWriter sw = new SchemaWriter(new JavadocEscapeWriter(out));
   561             type.visit((XSVisitor)sw);
   563             if(javadoc!=null)   javadoc += "\n\n";
   564             else                javadoc = "";
   566             javadoc += Messages.format( Messages.JAVADOC_HEADING, type.getName() )
   567                 +"\n<p>\n<pre>\n"+out.getBuffer()+"</pre>";
   569         }
   571         // build base type
   572         refererStack.push(type.getSimpleBaseType());
   573         TypeUse use = build(type.getSimpleBaseType());
   574         refererStack.pop();
   576         if(use.isCollection())
   577             return null;    // can't bind a list to enum constant
   579         CNonElement baseDt = use.getInfo();   // for now just ignore that case
   581         if(baseDt instanceof CClassInfo)
   582             return null;    // can't bind to an enum if the base is a class, since we don't have the value constrctor
   584         // if the member names collide, re-generate numbered constant names.
   585         XSFacet[] errorRef = new XSFacet[1];
   586         List<CEnumConstant> memberList = buildCEnumConstants(type, false, members, errorRef);
   587         if(memberList==null || checkMemberNameCollision(memberList)!=null) {
   588             switch(mode) {
   589             case SKIP:
   590                 // abort
   591                 return null;
   592             case ERROR:
   593                 // error
   594                 if(memberList==null) {
   595                     getErrorReporter().error( errorRef[0].getLocator(),
   596                         Messages.ERR_CANNOT_GENERATE_ENUM_NAME,
   597                         errorRef[0].getValue() );
   598                 } else {
   599                     CEnumConstant[] collision = checkMemberNameCollision(memberList);
   600                     getErrorReporter().error( collision[0].getLocator(),
   601                         Messages.ERR_ENUM_MEMBER_NAME_COLLISION,
   602                         collision[0].getName() );
   603                     getErrorReporter().error( collision[1].getLocator(),
   604                         Messages.ERR_ENUM_MEMBER_NAME_COLLISION_RELATED );
   605                 }
   606                 return null;    // recover from error
   607             case GENERATE:
   608                 // generate
   609                 memberList = buildCEnumConstants(type,true,members,null);
   610                 break;
   611             }
   612         }
   613         if(memberList.isEmpty()) {
   614             getErrorReporter().error( loc, Messages.ERR_NO_ENUM_FACET );
   615             return null;
   616         }
   618         // use the name of the simple type as the name of the class.
   619         CClassInfoParent scope;
   620         if(type.isGlobal())
   621             scope = new CClassInfoParent.Package(getClassSelector().getPackage(type.getTargetNamespace()));
   622         else
   623             scope = getClassSelector().getClassScope();
   624         CEnumLeafInfo xducer = new CEnumLeafInfo( model, BGMBuilder.getName(type), scope,
   625             className, baseDt, memberList, type,
   626             builder.getBindInfo(type).toCustomizationList(), loc );
   627         xducer.javadoc = javadoc;
   629         BIConversion conv = new BIConversion.Static( type.getLocator(),xducer);
   630         conv.markAsAcknowledged();
   632         // attach this new conversion object to this simple type
   633         // so that successive look up will use the same object.
   634         builder.getOrCreateBindInfo(type).addDecl(conv);
   636         return conv.getTypeUse(type);
   637     }
   639     /**
   640      *
   641      * @param errorRef
   642      *      if constant names couldn't be generated, return a reference to that enum facet.
   643      * @return
   644      *      null if unable to generate names for some of the constants.
   645      */
   646     private List<CEnumConstant> buildCEnumConstants(XSRestrictionSimpleType type, boolean needsToGenerateMemberName, Map<String, BIEnumMember> members, XSFacet[] errorRef) {
   647         List<CEnumConstant> memberList = new ArrayList<CEnumConstant>();
   648         int idx=1;
   649         Set<String> enums = new HashSet<String>(); // to avoid duplicates. See issue #366
   651         for( XSFacet facet : type.getDeclaredFacets(XSFacet.FACET_ENUMERATION)) {
   652             String name=null;
   653             String mdoc=builder.getBindInfo(facet).getDocumentation();
   655             if(!enums.add(facet.getValue().value))
   656                 continue;   // ignore the 2nd occasion
   658             if( needsToGenerateMemberName ) {
   659                 // generate names for all member names.
   660                 // this will even override names specified by the user. that's crazy.
   661                 name = "VALUE_"+(idx++);
   662             } else {
   663                 String facetValue = facet.getValue().value;
   664                 BIEnumMember mem = members.get(facetValue);
   665                 if( mem==null )
   666                     // look at the one attached to the facet object
   667                     mem = builder.getBindInfo(facet).get(BIEnumMember.class);
   669                 if (mem!=null) {
   670                     name = mem.name;
   671                     if (mdoc != null) {
   672                         mdoc = mem.javadoc;
   673                     }
   674                 }
   676                 if(name==null) {
   677                     StringBuilder sb = new StringBuilder();
   678                     for( int i=0; i<facetValue.length(); i++) {
   679                         char ch = facetValue.charAt(i);
   680                         if(Character.isJavaIdentifierPart(ch))
   681                             sb.append(ch);
   682                         else
   683                             sb.append('_');
   684                     }
   685                     name = model.getNameConverter().toConstantName(sb.toString());
   686                 }
   687             }
   689             if(!JJavaName.isJavaIdentifier(name)) {
   690                 if(errorRef!=null)  errorRef[0] = facet;
   691                 return null;    // unable to generate a name
   692             }
   694             memberList.add(new CEnumConstant(name,mdoc,facet.getValue().value,facet,builder.getBindInfo(facet).toCustomizationList(),facet.getLocator()));
   695         }
   696         return memberList;
   697     }
   699     /**
   700      * Returns non-null if {@link CEnumConstant}s have name collisions among them.
   701      *
   702      * @return
   703      *      if there's a collision, return two {@link CEnumConstant}s that collided.
   704      *      otherwise return null.
   705      */
   706     private CEnumConstant[] checkMemberNameCollision( List<CEnumConstant> memberList ) {
   707         Map<String,CEnumConstant> names = new HashMap<String,CEnumConstant>();
   708         for (CEnumConstant c : memberList) {
   709             CEnumConstant old = names.put(c.getName(),c);
   710             if(old!=null)
   711                 // collision detected
   712                 return new CEnumConstant[]{old,c};
   713         }
   714         return null;
   715     }
   719     private EnumMemberMode getEnumMemberMode() {
   720         return builder.getGlobalBinding().getEnumMemberMode();
   721     }
   723     private TypeUse lookupBuiltin( String typeLocalName ) {
   724         if(typeLocalName.equals("integer") || typeLocalName.equals("long")) {
   725             /*
   726                 attempt an optimization so that we can
   727                 improve the binding for types like this:
   729                 <simpleType>
   730                   <restriciton baseType="integer">
   731                     <maxInclusive value="100" />
   732                   </
   733                 </
   735                 ... to int, not BigInteger.
   736             */
   738             BigInteger xe = readFacet(XSFacet.FACET_MAXEXCLUSIVE,-1);
   739             BigInteger xi = readFacet(XSFacet.FACET_MAXINCLUSIVE,0);
   740             BigInteger max = min(xe,xi);    // most restrictive one takes precedence
   742             if(max!=null) {
   743                 BigInteger ne = readFacet(XSFacet.FACET_MINEXCLUSIVE,+1);
   744                 BigInteger ni = readFacet(XSFacet.FACET_MININCLUSIVE,0);
   745                 BigInteger min = max(ne,ni);
   747                 if(min!=null) {
   748                     if(min.compareTo(INT_MIN )>=0 && max.compareTo(INT_MAX )<=0)
   749                         typeLocalName = "int";
   750                     else
   751                     if(min.compareTo(LONG_MIN)>=0 && max.compareTo(LONG_MAX)<=0)
   752                         typeLocalName = "long";
   753                 }
   754             }
   755         } else
   756         if(typeLocalName.equals("boolean") && isRestrictedTo0And1()) {
   757             // this is seen in the SOAP schema and too common to ignore
   758             return CBuiltinLeafInfo.BOOLEAN_ZERO_OR_ONE;
   759         } else
   760         if(typeLocalName.equals("base64Binary")) {
   761             return lookupBinaryTypeBinding();
   762         } else
   763         if(typeLocalName.equals("anySimpleType")) {
   764             if(getReferer() instanceof XSAttributeDecl || getReferer() instanceof XSSimpleType)
   765                 return CBuiltinLeafInfo.STRING;
   766             else
   767                 return CBuiltinLeafInfo.ANYTYPE;
   768         }
   769         return builtinConversions.get(typeLocalName);
   770     }
   772     /**
   773      * Decides the way xs:base64Binary binds.
   774      *
   775      * This method checks the expected media type.
   776      */
   777     private TypeUse lookupBinaryTypeBinding() {
   778         XSComponent referer = getReferer();
   779         String emt = referer.getForeignAttribute(XML_MIME_URI, Const.EXPECTED_CONTENT_TYPES);
   780         if(emt!=null) {
   781             acknowledgedXmimeContentTypes.add(referer);
   782             try {
   783                 // see http://www.xml.com/lpt/a/2004/07/21/dive.html
   784                 List<MimeTypeRange> types = MimeTypeRange.parseRanges(emt);
   785                 MimeTypeRange mt = MimeTypeRange.merge(types);
   787                 // see spec table I-1 in appendix I section 2.1.1 for bindings
   788                 if(mt.majorType.equalsIgnoreCase("image"))
   789                     return CBuiltinLeafInfo.IMAGE.makeMimeTyped(mt.toMimeType());
   791                 if(( mt.majorType.equalsIgnoreCase("application") || mt.majorType.equalsIgnoreCase("text"))
   792                         && isXml(mt.subType))
   793                     return CBuiltinLeafInfo.XML_SOURCE.makeMimeTyped(mt.toMimeType());
   795                 if((mt.majorType.equalsIgnoreCase("text") && (mt.subType.equalsIgnoreCase("plain")) )) {
   796                     return CBuiltinLeafInfo.STRING.makeMimeTyped(mt.toMimeType());
   797                 }
   799                 return CBuiltinLeafInfo.DATA_HANDLER.makeMimeTyped(mt.toMimeType());
   800             } catch (ParseException e) {
   801                 getErrorReporter().error( referer.getLocator(),
   802                     Messages.format(Messages.ERR_ILLEGAL_EXPECTED_MIME_TYPE,emt, e.getMessage()) );
   803                 // recover by using the default
   804             } catch (MimeTypeParseException e) {
   805                 getErrorReporter().error( referer.getLocator(),
   806                     Messages.format(Messages.ERR_ILLEGAL_EXPECTED_MIME_TYPE,emt, e.getMessage()) );
   807             }
   808         }
   809         // default
   810         return CBuiltinLeafInfo.BASE64_BYTE_ARRAY;
   811     }
   813     public boolean isAcknowledgedXmimeContentTypes(XSComponent c) {
   814         return acknowledgedXmimeContentTypes.contains(c);
   815     }
   817     /**
   818      * Returns true if the specified sub-type is an XML type.
   819      */
   820     private boolean isXml(String subType) {
   821         return subType.equals("xml") || subType.endsWith("+xml");
   822     }
   824     /**
   825      * Returns true if the {@link #initiatingType} is restricted
   826      * to '0' and '1'. This logic is not complete, but it at least
   827      * finds the such definition in SOAP @mustUnderstand.
   828      */
   829     private boolean isRestrictedTo0And1() {
   830         XSFacet pattern = initiatingType.getFacet(XSFacet.FACET_PATTERN);
   831         if(pattern!=null) {
   832             String v = pattern.getValue().value;
   833             if(v.equals("0|1") || v.equals("1|0") || v.equals("\\d"))
   834                 return true;
   835         }
   836         XSFacet enumf = initiatingType.getFacet(XSFacet.FACET_ENUMERATION);
   837         if(enumf!=null) {
   838             String v = enumf.getValue().value;
   839             if(v.equals("0") || v.equals("1"))
   840                 return true;
   841         }
   842         return false;
   843     }
   845     private BigInteger readFacet(String facetName,int offset) {
   846         XSFacet me = initiatingType.getFacet(facetName);
   847         if(me==null)
   848             return null;
   849         BigInteger bi = DatatypeConverterImpl._parseInteger(me.getValue().value);
   850         if(offset!=0)
   851             bi = bi.add(BigInteger.valueOf(offset));
   852         return bi;
   853     }
   855     private BigInteger min(BigInteger a, BigInteger b) {
   856         if(a==null) return b;
   857         if(b==null) return a;
   858         return a.min(b);
   859     }
   861     private BigInteger max(BigInteger a, BigInteger b) {
   862         if(a==null) return b;
   863         if(b==null) return a;
   864         return a.max(b);
   865     }
   867     private static final BigInteger LONG_MIN = BigInteger.valueOf(Long.MIN_VALUE);
   868     private static final BigInteger LONG_MAX = BigInteger.valueOf(Long.MAX_VALUE);
   869     private static final BigInteger INT_MIN = BigInteger.valueOf(Integer.MIN_VALUE);
   870     private static final BigInteger INT_MAX = BigInteger.valueOf(Integer.MAX_VALUE);
   872     static {
   873         // list of datatypes which have built-in conversions.
   874         // note that although xs:token and xs:normalizedString are not
   875         // specified in the spec, they need to be here because they
   876         // have different whitespace normalization semantics.
   877         Map<String,TypeUse> m = builtinConversions;
   879         // TODO: this is so dumb
   880         m.put("string",         CBuiltinLeafInfo.STRING);
   881         m.put("anyURI",         CBuiltinLeafInfo.STRING);
   882         m.put("boolean",        CBuiltinLeafInfo.BOOLEAN);
   883         // we'll also look at the expected media type, so don't just add this to the map
   884         // m.put("base64Binary",   CBuiltinLeafInfo.BASE64_BYTE_ARRAY);
   885         m.put("hexBinary",      CBuiltinLeafInfo.HEXBIN_BYTE_ARRAY);
   886         m.put("float",          CBuiltinLeafInfo.FLOAT);
   887         m.put("decimal",        CBuiltinLeafInfo.BIG_DECIMAL);
   888         m.put("integer",        CBuiltinLeafInfo.BIG_INTEGER);
   889         m.put("long",           CBuiltinLeafInfo.LONG);
   890         m.put("unsignedInt",    CBuiltinLeafInfo.LONG);
   891         m.put("int",            CBuiltinLeafInfo.INT);
   892         m.put("unsignedShort",  CBuiltinLeafInfo.INT);
   893         m.put("short",          CBuiltinLeafInfo.SHORT);
   894         m.put("unsignedByte",   CBuiltinLeafInfo.SHORT);
   895         m.put("byte",           CBuiltinLeafInfo.BYTE);
   896         m.put("double",         CBuiltinLeafInfo.DOUBLE);
   897         m.put("QName",          CBuiltinLeafInfo.QNAME);
   898         m.put("NOTATION",       CBuiltinLeafInfo.QNAME);
   899         m.put("dateTime",       CBuiltinLeafInfo.CALENDAR);
   900         m.put("date",           CBuiltinLeafInfo.CALENDAR);
   901         m.put("time",           CBuiltinLeafInfo.CALENDAR);
   902         m.put("gYearMonth",     CBuiltinLeafInfo.CALENDAR);
   903         m.put("gYear",          CBuiltinLeafInfo.CALENDAR);
   904         m.put("gMonthDay",      CBuiltinLeafInfo.CALENDAR);
   905         m.put("gDay",           CBuiltinLeafInfo.CALENDAR);
   906         m.put("gMonth",         CBuiltinLeafInfo.CALENDAR);
   907         m.put("duration",       CBuiltinLeafInfo.DURATION);
   908         m.put("token",          CBuiltinLeafInfo.TOKEN);
   909         m.put("normalizedString",CBuiltinLeafInfo.NORMALIZED_STRING);
   910         m.put("ID",             CBuiltinLeafInfo.ID);
   911         m.put("IDREF",          CBuiltinLeafInfo.IDREF);
   912         // TODO: handling dateTime, time, and date type
   913 //        String[] names = {
   914 //            "date", "dateTime", "time", "hexBinary" };
   915     }
   916 }

mercurial