1 /*
   2  * Copyright (c) 1997, 2014, 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.model;
  27 
  28 import java.awt.*;
  29 import java.math.BigDecimal;
  30 import java.math.BigInteger;
  31 import java.util.HashMap;
  32 import java.util.Map;
  33 
  34 import javax.activation.DataHandler;
  35 import javax.activation.MimeType;
  36 import javax.xml.bind.DatatypeConverter;
  37 import javax.xml.bind.annotation.XmlIDREF;
  38 import javax.xml.bind.annotation.adapters.CollapsedStringAdapter;
  39 import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
  40 import javax.xml.bind.annotation.adapters.NormalizedStringAdapter;
  41 import javax.xml.bind.annotation.adapters.XmlAdapter;
  42 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
  43 import javax.xml.datatype.Duration;
  44 import javax.xml.datatype.XMLGregorianCalendar;
  45 import javax.xml.namespace.QName;
  46 import javax.xml.transform.Source;
  47 
  48 import com.sun.codemodel.internal.JExpr;
  49 import com.sun.codemodel.internal.JExpression;
  50 import com.sun.codemodel.internal.JType;
  51 import com.sun.tools.internal.xjc.model.nav.NClass;
  52 import com.sun.xml.internal.bind.v2.model.annotation.Locatable;
  53 import com.sun.xml.internal.bind.v2.model.core.BuiltinLeafInfo;
  54 import com.sun.xml.internal.bind.v2.model.core.Element;
  55 import com.sun.xml.internal.bind.v2.model.core.LeafInfo;
  56 import com.sun.xml.internal.bind.v2.runtime.Location;
  57 import com.sun.tools.internal.xjc.model.nav.NType;
  58 import com.sun.tools.internal.xjc.model.nav.NavigatorImpl;
  59 import com.sun.tools.internal.xjc.outline.Outline;
  60 import com.sun.tools.internal.xjc.runtime.ZeroOneBooleanAdapter;
  61 import com.sun.tools.internal.xjc.util.NamespaceContextAdapter;
  62 import com.sun.xml.internal.bind.v2.WellKnownNamespace;
  63 import com.sun.xml.internal.bind.v2.model.core.ID;
  64 import com.sun.xml.internal.xsom.XSComponent;
  65 import com.sun.xml.internal.xsom.XmlString;
  66 
  67 import org.xml.sax.Locator;
  68 
  69 /**
  70  * Encapsulates the default handling for leaf classes (which are bound
  71  * to text in XML.) In particular this class knows how to convert
  72  * the lexical value into the Java class according to this default rule.
  73  *
  74  * <p>
  75  * This represents the spec-defined default handling for the Java
  76  * type ({@link #getType()}.
  77  *
  78  * <p>
  79  * For those Java classes (such as {@link String} or {@link Boolean})
  80  * where the spec designates a specific default handling, there are
  81  * constants in this class (such as {@link #STRING} or {@link #BOOLEAN}.)
  82  *
  83  * <p>
  84  * The generated type-safe enum classes are also a leaf class,
  85  * and as such there are {@link CEnumLeafInfo} that represents it
  86  * as {@link CBuiltinLeafInfo}.
  87  *
  88  * <p>
  89  * This class represents the <b>default handling</b>, and therefore
  90  * we can only have one instance per one {@link NType}. Handling of
  91  * other XML Schema types (such as xs:token) are represented as
  92  * a general {@link TypeUse} objects.
  93  *
  94  *
  95  * @author Kohsuke Kawaguchi
  96  */
  97 public abstract class CBuiltinLeafInfo implements CNonElement, BuiltinLeafInfo<NType,NClass>, LeafInfo<NType,NClass>, Location {
  98 
  99     private final NType type;
 100     /**
 101      * Can be null for anonymous types.
 102      */
 103     private final QName typeName;
 104 
 105     private final QName[] typeNames;
 106 
 107     private final ID id;
 108 
 109     // no derived class other than the spec-defined ones. definitely not for enum.
 110     private CBuiltinLeafInfo(NType typeToken, ID id, QName... typeNames) {
 111         this.type = typeToken;
 112         this.typeName = typeNames.length>0?typeNames[0]:null;
 113         this.typeNames = typeNames;
 114         this.id = id;
 115     }
 116 
 117     /**
 118      * Gets the code model representation of this type.
 119      */
 120     public JType toType(Outline o, Aspect aspect) {
 121         return getType().toType(o,aspect);
 122     }
 123 
 124     /**
 125      * Since {@link CBuiltinLeafInfo} represents a default binding,
 126      * it is never a collection.
 127      */
 128     @Deprecated
 129     public final boolean isCollection() {
 130         return false;
 131     }
 132 
 133     /**
 134      * Guaranteed to return this.
 135      */
 136     @Deprecated
 137     public CNonElement getInfo() {
 138         return this;
 139     }
 140 
 141     public ID idUse() {
 142         return id;
 143     }
 144 
 145     /**
 146      * {@link CBuiltinLeafInfo} never has a default associated MIME type.
 147      */
 148     public MimeType getExpectedMimeType() {
 149         return null;
 150     }
 151 
 152     @Deprecated
 153     public final CAdapter getAdapterUse() {
 154         return null;
 155     }
 156 
 157     public Locator getLocator() {
 158         return Model.EMPTY_LOCATOR;
 159     }
 160 
 161     public final XSComponent getSchemaComponent() {
 162         throw new UnsupportedOperationException("TODO. If you hit this, let us know.");
 163     }
 164 
 165     /**
 166      * Creates a {@link TypeUse} that represents a collection of this {@link CBuiltinLeafInfo}.
 167      */
 168     public final TypeUse makeCollection() {
 169         return TypeUseFactory.makeCollection(this);
 170     }
 171 
 172     /**
 173      * Creates a {@link TypeUse} that represents an adapted use of this {@link CBuiltinLeafInfo}.
 174      */
 175     public final TypeUse makeAdapted( Class<? extends XmlAdapter> adapter, boolean copy ) {
 176         return TypeUseFactory.adapt(this,adapter,copy);
 177     }
 178 
 179     /**
 180      * Creates a {@link TypeUse} that represents a MIME-type assocaited version of this {@link CBuiltinLeafInfo}.
 181      */
 182     public final TypeUse makeMimeTyped( MimeType mt ) {
 183         return TypeUseFactory.makeMimeTyped(this,mt);
 184     }
 185 
 186     /**
 187      * @deprecated always return false at this level.
 188      */
 189     public final boolean isElement() {
 190         return false;
 191     }
 192 
 193     /**
 194      * @deprecated always return null at this level.
 195      */
 196     public final QName getElementName() {
 197         return null;
 198     }
 199 
 200     /**
 201      * @deprecated always return null at this level.
 202      */
 203     public final Element<NType,NClass> asElement() {
 204         return null;
 205     }
 206 
 207     /**
 208      * A reference to the representation of the type.
 209      */
 210     public NType getType() {
 211         return type;
 212     }
 213 
 214     /**
 215      * Returns all the type names recognized by this bean info.
 216      *
 217      * @return
 218      *      do not modify the returned array.
 219      */
 220     public final QName[] getTypeNames() {
 221         return typeNames;
 222     }
 223 
 224     /**
 225      * Leaf-type cannot be referenced from IDREF.
 226      *
 227      * @deprecated
 228      *      why are you calling a method whose return value is always known?
 229      */
 230     public final boolean canBeReferencedByIDREF() {
 231         return false;
 232     }
 233 
 234     public QName getTypeName() {
 235         return typeName;
 236     }
 237 
 238     public Locatable getUpstream() {
 239         return null;
 240     }
 241 
 242     public Location getLocation() {
 243         // this isn't very accurate, but it's not too bad
 244         // doing it correctly need leaves to hold navigator.
 245         // otherwise revisit the design so that we take navigator as a parameter
 246         return this;
 247     }
 248 
 249     public boolean isSimpleType() {
 250         return true;
 251     }
 252 
 253     /**
 254      * {@link CBuiltinLeafInfo} for Java classes that have
 255      * the spec defined built-in binding semantics.
 256      */
 257     private static abstract class Builtin extends CBuiltinLeafInfo {
 258         protected Builtin(Class c, String typeName) {
 259             this(c,typeName,com.sun.xml.internal.bind.v2.model.core.ID.NONE);
 260         }
 261         protected Builtin(Class c, String typeName, ID id) {
 262             super(NavigatorImpl.theInstance.ref(c), id, new QName(WellKnownNamespace.XML_SCHEMA,typeName));
 263             LEAVES.put(getType(),this);
 264         }
 265 
 266         /**
 267          * No vendor customization in the built-in classes.
 268          */
 269         public CCustomizations getCustomizations() {
 270             return CCustomizations.EMPTY;
 271         }
 272     }
 273 
 274     private static final class NoConstantBuiltin extends Builtin {
 275         public NoConstantBuiltin(Class c, String typeName) {
 276             super(c, typeName);
 277         }
 278         public JExpression createConstant(Outline outline, XmlString lexical) {
 279             return null;
 280         }
 281     }
 282 
 283     /**
 284      * All built-in leaves.
 285      */
 286     public static final Map<NType,CBuiltinLeafInfo> LEAVES = new HashMap<NType,CBuiltinLeafInfo>();
 287 
 288 
 289     public static final CBuiltinLeafInfo ANYTYPE = new NoConstantBuiltin(Object.class,"anyType");
 290     public static final CBuiltinLeafInfo STRING = new Builtin(String.class,"string") {
 291             public JExpression createConstant(Outline outline, XmlString lexical) {
 292                 return JExpr.lit(lexical.value);
 293             }
 294     };
 295     public static final CBuiltinLeafInfo BOOLEAN = new Builtin(Boolean.class,"boolean") {
 296             public JExpression createConstant(Outline outline, XmlString lexical) {
 297                 return JExpr.lit(DatatypeConverter.parseBoolean(lexical.value));
 298             }
 299     };
 300     public static final CBuiltinLeafInfo INT = new Builtin(Integer.class,"int") {
 301         public JExpression createConstant(Outline outline, XmlString lexical) {
 302             return JExpr.lit(DatatypeConverter.parseInt(lexical.value));
 303         }
 304     };
 305     public static final CBuiltinLeafInfo LONG = new Builtin(Long.class,"long") {
 306         public JExpression createConstant(Outline outline, XmlString lexical) {
 307             return JExpr.lit(DatatypeConverter.parseLong(lexical.value));
 308         }
 309     };
 310     public static final CBuiltinLeafInfo BYTE = new Builtin(Byte.class,"byte") {
 311         public JExpression createConstant(Outline outline, XmlString lexical) {
 312             return JExpr.cast(
 313                     outline.getCodeModel().BYTE,
 314                     JExpr.lit(DatatypeConverter.parseByte(lexical.value)));
 315         }
 316     };
 317     public static final CBuiltinLeafInfo SHORT = new Builtin(Short.class,"short") {
 318         public JExpression createConstant(Outline outline, XmlString lexical) {
 319             return JExpr.cast(
 320                     outline.getCodeModel().SHORT,
 321                     JExpr.lit(DatatypeConverter.parseShort(lexical.value)));
 322         }
 323     };
 324     public static final CBuiltinLeafInfo FLOAT = new Builtin(Float.class,"float") {
 325         public JExpression createConstant(Outline outline, XmlString lexical) {
 326             return JExpr.lit(DatatypeConverter.parseFloat(lexical.value));
 327         }
 328     };
 329     public static final CBuiltinLeafInfo DOUBLE = new Builtin(Double.class,"double") {
 330         public JExpression createConstant(Outline outline, XmlString lexical) {
 331             return JExpr.lit(DatatypeConverter.parseDouble(lexical.value));
 332         }
 333     };
 334     public static final CBuiltinLeafInfo QNAME = new Builtin(QName.class,"QName") {
 335         public JExpression createConstant(Outline outline, XmlString lexical) {
 336             QName qn = DatatypeConverter.parseQName(lexical.value,new NamespaceContextAdapter(lexical));
 337             return JExpr._new(outline.getCodeModel().ref(QName.class))
 338                 .arg(qn.getNamespaceURI())
 339                 .arg(qn.getLocalPart())
 340                 .arg(qn.getPrefix());
 341         }
 342     };
 343     // XMLGregorianCalendar is mutable, so we can't support default values anyhow.
 344         // For CALENAR we are uses a most unlikely name so as to avoid potential name
 345         // conflicts in the furture.
 346         public static final CBuiltinLeafInfo CALENDAR = new NoConstantBuiltin(XMLGregorianCalendar.class,"\u0000");
 347     public static final CBuiltinLeafInfo DURATION = new NoConstantBuiltin(Duration.class,"duration");
 348 
 349     public static final CBuiltinLeafInfo BIG_INTEGER = new Builtin(BigInteger.class,"integer") {
 350         public JExpression createConstant(Outline outline, XmlString lexical) {
 351             return JExpr._new(outline.getCodeModel().ref(BigInteger.class)).arg(lexical.value.trim());
 352         }
 353     };
 354 
 355     public static final CBuiltinLeafInfo BIG_DECIMAL = new Builtin(BigDecimal.class,"decimal") {
 356         public JExpression createConstant(Outline outline, XmlString lexical) {
 357             return JExpr._new(outline.getCodeModel().ref(BigDecimal.class)).arg(lexical.value.trim());
 358         }
 359     };
 360 
 361     public static final CBuiltinLeafInfo BASE64_BYTE_ARRAY = new Builtin(byte[].class,"base64Binary") {
 362         public JExpression createConstant(Outline outline, XmlString lexical) {
 363             return outline.getCodeModel().ref(DatatypeConverter.class).staticInvoke("parseBase64Binary").arg(lexical.value);
 364         }
 365     };
 366 
 367     public static final CBuiltinLeafInfo DATA_HANDLER = new NoConstantBuiltin(DataHandler.class,"base64Binary");
 368     public static final CBuiltinLeafInfo IMAGE = new NoConstantBuiltin(Image.class,"base64Binary");
 369     public static final CBuiltinLeafInfo XML_SOURCE = new NoConstantBuiltin(Source.class,"base64Binary");
 370 
 371     public static final TypeUse HEXBIN_BYTE_ARRAY =
 372         STRING.makeAdapted(HexBinaryAdapter.class,false);
 373 
 374 
 375     // TODO: not sure if they should belong here,
 376     // but I couldn't find other places that fit.
 377     public static final TypeUse TOKEN =
 378             STRING.makeAdapted(CollapsedStringAdapter.class,false);
 379 
 380     public static final TypeUse NORMALIZED_STRING =
 381             STRING.makeAdapted(NormalizedStringAdapter.class,false);
 382 
 383     public static final TypeUse ID = TypeUseFactory.makeID(TOKEN,com.sun.xml.internal.bind.v2.model.core.ID.ID);
 384 
 385     /**
 386      * boolean restricted to 0 or 1.
 387      */
 388     public static final TypeUse BOOLEAN_ZERO_OR_ONE =
 389             STRING.makeAdapted(ZeroOneBooleanAdapter.class,true);
 390 
 391     /**
 392      * IDREF.
 393      *
 394      * IDREF is has a whitespace normalization semantics of token, but
 395      * we don't want {@link XmlJavaTypeAdapter} and {@link XmlIDREF} to interact.
 396      */
 397     public static final TypeUse IDREF = TypeUseFactory.makeID(ANYTYPE,com.sun.xml.internal.bind.v2.model.core.ID.IDREF);
 398 
 399     /**
 400      * For all list of strings, such as NMTOKENS, ENTITIES.
 401      */
 402     public static final TypeUse STRING_LIST =
 403             STRING.makeCollection();
 404 }