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