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