KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > gnu > kawa > xml > XDataType


1 // Copyright (c) 2006 Per M.A. Bothner.
2
// This is free software; for specifics see ../../../COPYING.
3

4 package gnu.kawa.xml;
5 import gnu.bytecode.*;
6 import gnu.mapping.Procedure;
7 import gnu.expr.*;
8 import gnu.text.Printable;
9 import gnu.math.*;
10 import java.math.BigDecimal JavaDoc;
11 import gnu.lists.Consumer;
12 import gnu.xml.TextUtils;
13
14 /** An atomic type as used in XML Schema and related languages.
15  * For example the {code xs:decimal} type is {@code XDataType.decimalType}.
16  */

17
18 public class XDataType extends Type implements TypeValue
19 {
20   Type implementationType;
21
22   Object JavaDoc name;
23
24   /** The "parent" type. */
25   XDataType baseType;
26
27   /** One of the {@code XXXX_TYPE_CODE} constants. */
28   int typeCode;
29
30   public static final int DECIMAL_TYPE_CODE = 2;
31   public static final int INTEGER_TYPE_CODE = 3;
32   public static final int NON_POSITIVE_INTEGER_TYPE_CODE = 4;
33   public static final int NEGATIVE_INTEGER_TYPE_CODE = 5;
34   public static final int LONG_TYPE_CODE = 6;
35   public static final int INT_TYPE_CODE = 7;
36   public static final int SHORT_TYPE_CODE = 8;
37   public static final int BYTE_TYPE_CODE = 9;
38   public static final int NONNEGATIVE_INTEGER_TYPE_CODE = 10;
39   public static final int UNSIGNED_LONG_TYPE_CODE = 11;
40   public static final int UNSIGNED_INT_TYPE_CODE = 12;
41   public static final int UNSIGNED_SHORT_TYPE_CODE = 13;
42   public static final int UNSIGNED_BYTE_TYPE_CODE = 14;
43   public static final int POSITIVE_INTEGER_TYPE_CODE = 15;
44
45   public static final int FLOAT_TYPE_CODE = 16;
46   public static final int DOUBLE_TYPE_CODE = 17;
47
48   public static final int DATE_TIME_TYPE_CODE = 18;
49   public static final int DATE_TYPE_CODE = 19;
50   public static final int TIME_TYPE_CODE = 20;
51   public static final int G_YEAR_MONTH_TYPE_CODE = 21;
52   public static final int G_YEAR_TYPE_CODE = 22;
53   public static final int G_MONTH_DAY_TYPE_CODE = 23;
54   public static final int G_DAY_TYPE_CODE = 24;
55   public static final int G_MONTH_TYPE_CODE = 25;
56   public static final int DURATION_TYPE_CODE = 26;
57   public static final int YEAR_MONTH_DURATION_TYPE_CODE = 27;
58   public static final int DAY_TIME_DURATION_TYPE_CODE = 28;
59
60   public static final int BOOLEAN_TYPE_CODE = 29;
61
62   public static final int QNAME_TYPE_CODE = 30;
63   public static final int ANY_URI_TYPE_CODE = 31;
64   public static final int BASE64_BINARY_TYPE_CODE = 32;
65   public static final int HEX_BINARY_TYPE_CODE = 33;
66   public static final int NOTATION_TYPE_CODE = 34;
67
68   public static final int UNTYPED_ATOMIC_TYPE_CODE = 35;
69
70   public static final int STRING_TYPE_CODE = 36;
71
72   public XDataType (Object JavaDoc name, Type implementationType, int typeCode)
73   {
74     super(implementationType);
75     this.name = name;
76     if (name != null)
77       setName(name.toString());
78     this.implementationType = implementationType;
79     this.typeCode = typeCode;
80   }
81
82   public static final XDataType stringType =
83     new XDataType("string", ClassType.make("java.lang.String"),
84                   STRING_TYPE_CODE);
85
86   public static final XDataType untypedAtomicType =
87     new XDataType("string", ClassType.make("gnu.kawa.xml.UntypedAtomic"),
88                   UNTYPED_ATOMIC_TYPE_CODE);
89
90   public static final XDataType base64BinaryType =
91     new XDataType("base64Binary", ClassType.make("gnu.kawa.xml.Base64Binary"),
92                   BASE64_BINARY_TYPE_CODE);
93
94   public static final XDataType hexBinaryType =
95     new XDataType("hexBinary", ClassType.make("gnu.kawa.xml.HexBinary"),
96                   HEX_BINARY_TYPE_CODE);
97
98   public static final XDataType booleanType =
99     new XDataType("boolean", Type.boolean_type,
100                   BOOLEAN_TYPE_CODE);
101
102   public static final XDataType anyURIType =
103     new XDataType("anyURI",
104                   /* #ifdef use:java.net.URI */
105                   ClassType.make("java.net.URI"),
106                   /* #else */
107                   // ClassType.make("java.lang.String"),
108
/* #endif */
109                   ANY_URI_TYPE_CODE);
110
111   public static final XDataType NotationType =
112     new XDataType("NOTATION",
113                   ClassType.make("gnu.kawa.xml.Notation"),
114                   NOTATION_TYPE_CODE);
115
116   public static final XDataType decimalType =
117     // A decimal value is implemented using java.math.BigDecimal.
118
// However, the integer sub-type is implemented using gnu.math.IntNum.
119
// So we use their common supertype as the implementationType.
120
new XDataType("decimal", ClassType.make("java.lang.Number"),
121                   DECIMAL_TYPE_CODE);
122
123   public static final XDataType floatType =
124     new XDataType("float", ClassType.make("java.lang.Float"), FLOAT_TYPE_CODE);
125
126   public static final XDataType doubleType =
127     new XDataType("double", ClassType.make("java.lang.Double"), DOUBLE_TYPE_CODE);
128
129   public static final XDataType durationType =
130     new XDataType("duration", ClassType.make("gnu.math.Duration"),
131                   DURATION_TYPE_CODE);
132
133   public static final XDataType yearMonthDurationType =
134     new XDataType("yearMonthDuration", ClassType.make("gnu.math.Duration"),
135                   YEAR_MONTH_DURATION_TYPE_CODE);
136
137   public static final XDataType dayTimeDurationType =
138     new XDataType("dayTimeDuration", ClassType.make("gnu.math.Duration"),
139                   DAY_TIME_DURATION_TYPE_CODE);
140
141   public java.lang.Class JavaDoc getReflectClass()
142   {
143     return implementationType.getReflectClass();
144   }
145
146   public Type getImplementationType()
147   {
148     return implementationType;
149   }
150
151   public void emitCoerceFromObject (CodeAttr code)
152   {
153     Compilation comp = Compilation.getCurrent();
154     comp.compileConstant(this, Target.pushObject);
155     Method meth = ClassType.make("gnu.kawa.xml.XDataType")
156       .getDeclaredMethod("coerceFromObject", 1);
157     code.emitSwap();
158     code.emitInvokeVirtual(meth);
159     // Needed to avoid VerifyErrors.
160
implementationType.emitCoerceFromObject(code);
161   }
162
163   public void emitCoerceToObject (CodeAttr code)
164   {
165     if (typeCode == BOOLEAN_TYPE_CODE)
166       implementationType.emitCoerceToObject(code);
167     else
168       super.emitCoerceToObject(code);
169   }
170
171  public void emitTestIf(Variable incoming, Declaration decl, Compilation comp)
172   {
173     CodeAttr code = comp.getCode();
174     if (typeCode == BOOLEAN_TYPE_CODE)
175       {
176         if (incoming != null)
177           code.emitLoad(incoming);
178         Type.boolean_ctype.emitIsInstance(code);
179         code.emitIfIntNotZero();
180         if (decl != null)
181           {
182             // Error if incoming is null.
183
code.emitLoad(incoming);
184             Type.boolean_type.emitCoerceFromObject(code);
185             decl.compileStore(comp);
186           }
187         return;
188       }
189
190     comp.compileConstant(this, Target.pushObject);
191     if (incoming == null)
192       code.emitSwap();
193     else
194       code.emitLoad(incoming);
195     if (decl != null)
196       {
197         code.emitDup();
198         decl.compileStore(comp);
199       }
200     code.emitInvokeVirtual(Compilation.typeType
201                            .getDeclaredMethod("isInstance", 1));
202     code.emitIfIntNotZero();
203   }
204
205   public boolean isInstance (Object JavaDoc obj)
206   {
207     switch (typeCode)
208       {
209       case STRING_TYPE_CODE:
210         return obj instanceof java.lang.String JavaDoc;
211       case UNTYPED_ATOMIC_TYPE_CODE:
212         return obj instanceof gnu.kawa.xml.UntypedAtomic;
213       case ANY_URI_TYPE_CODE:
214         /* #ifdef use:java.net.URI */
215         return obj instanceof java.net.URI JavaDoc;
216         /* #else */
217         // return obj instanceof String;
218
/* #endif */
219       case BOOLEAN_TYPE_CODE:
220         return obj instanceof java.lang.Boolean JavaDoc;
221       case FLOAT_TYPE_CODE:
222         return obj instanceof java.lang.Float JavaDoc;
223       case DOUBLE_TYPE_CODE:
224         return obj instanceof java.lang.Double JavaDoc;
225       case DECIMAL_TYPE_CODE:
226         return obj instanceof java.math.BigDecimal JavaDoc
227           || obj instanceof gnu.math.IntNum;
228       case DURATION_TYPE_CODE:
229         return obj instanceof Duration;
230       case YEAR_MONTH_DURATION_TYPE_CODE:
231         return obj instanceof Duration
232           && ((Duration) obj).unit() == Unit.month;
233       case DAY_TIME_DURATION_TYPE_CODE:
234         return obj instanceof Duration
235           && ((Duration) obj).unit() == Unit.second;
236       default:
237         return super.isInstance(obj);
238       }
239   }
240
241   public void emitIsInstance(Variable incoming,
242                  Compilation comp, Target target)
243   {
244     gnu.kawa.reflect.InstanceOf.emitIsInstance(this, incoming, comp, target);
245   }
246
247   public String JavaDoc toString (Object JavaDoc value)
248   {
249     return value.toString();
250   }
251
252
253   public void print (Object JavaDoc value, Consumer out)
254   {
255     if (value instanceof Printable)
256       ((Printable) value).print(out);
257     else
258       out.write(toString(value));
259   }
260
261   public boolean castable (Object JavaDoc value)
262   {
263     try
264       {
265         // FIXME - inefficient!
266
cast(value);
267         return true;
268       }
269     catch (Throwable JavaDoc ex)
270       {
271         return false;
272       }
273   }
274
275   public Object JavaDoc cast (Object JavaDoc value)
276   {
277     value = KNode.atomicValue(value);
278     if (value instanceof UntypedAtomic)
279       {
280         if (typeCode == UNTYPED_ATOMIC_TYPE_CODE)
281           return value;
282         return valueOf(value.toString());
283       }
284     if (value instanceof String JavaDoc)
285       return valueOf(value.toString());
286     switch (typeCode)
287       {
288       case STRING_TYPE_CODE:
289         return TextUtils.asString(value);
290       case UNTYPED_ATOMIC_TYPE_CODE:
291         return new UntypedAtomic(TextUtils.stringValue(value));
292       case ANY_URI_TYPE_CODE:
293         return toURI(value);
294       case BOOLEAN_TYPE_CODE:
295         if (value instanceof Boolean JavaDoc)
296           return (((Boolean JavaDoc)value).booleanValue() ? Boolean.TRUE
297                   : Boolean.FALSE);
298         if (value instanceof Number JavaDoc)
299           {
300             double d = ((Number JavaDoc) value).doubleValue();
301             return d == 0.0 || Double.isNaN(d) ? Boolean.FALSE : Boolean.TRUE;
302           }
303         break;
304       case DECIMAL_TYPE_CODE:
305         // Partly duplicates Arithmetic asBigDecimal.
306
if (value instanceof java.math.BigDecimal JavaDoc)
307           return value;
308         if (value instanceof gnu.math.RealNum)
309           return ((gnu.math.RealNum) value).asBigDecimal();
310         if (value instanceof Float JavaDoc || value instanceof Double JavaDoc)
311           {
312             double d = ((Number JavaDoc) value).doubleValue();
313             /* #ifdef JAVA5 */
314             // return BigDecimal.valueOf(d);
315
/* #else */
316             return new BigDecimal JavaDoc(d);
317             /* #endif */
318           }
319         if (value instanceof Boolean JavaDoc)
320           return cast(((Boolean JavaDoc)value).booleanValue() ? IntNum.one()
321                       : IntNum.zero());
322         break;
323       case FLOAT_TYPE_CODE:
324         if (value instanceof java.lang.Float JavaDoc)
325           return value;
326         if (value instanceof java.lang.Number JavaDoc)
327           // Wrong for complex numbers with non-zero imaginary part. FIXME.
328
return makeFloat(((Number JavaDoc) value).floatValue());
329         if (value instanceof Boolean JavaDoc)
330           return ((Boolean JavaDoc)value).booleanValue() ? FLOAT_ONE : FLOAT_ZERO;
331         break;
332       case DOUBLE_TYPE_CODE:
333         if (value instanceof java.lang.Double JavaDoc)
334           return value;
335         if (value instanceof java.lang.Number JavaDoc)
336           // Wrong for complex numbers with non-zero imaginary part. FIXME.
337
return makeDouble(((Number JavaDoc) value).doubleValue());
338         if (value instanceof Boolean JavaDoc)
339           return ((Boolean JavaDoc)value).booleanValue() ? DOUBLE_ONE : DOUBLE_ZERO;
340         break;
341       case G_YEAR_TYPE_CODE:
342       case G_YEAR_MONTH_TYPE_CODE:
343       case G_MONTH_TYPE_CODE:
344       case G_MONTH_DAY_TYPE_CODE:
345       case G_DAY_TYPE_CODE:
346         if (value instanceof DateTime)
347           {
348             int dstMask = XTimeType.components(((XTimeType) this).typeCode);
349             DateTime dt = (DateTime) value;
350             int srcMask = dt.components();
351             if (dstMask == srcMask
352                 || (srcMask & DateTime.DATE_MASK) == DateTime.DATE_MASK)
353               return dt.cast(dstMask);
354             throw new ClassCastException JavaDoc();
355           }
356         break;
357       case DATE_TYPE_CODE:
358       case TIME_TYPE_CODE:
359       case DATE_TIME_TYPE_CODE:
360         if (value instanceof DateTime)
361           {
362             int mask = XTimeType.components(((XTimeType) this).typeCode);
363             return ((DateTime) value).cast(mask);
364           }
365         break;
366       case DURATION_TYPE_CODE:
367         return castToDuration(value, Unit.duration);
368       case YEAR_MONTH_DURATION_TYPE_CODE:
369         return castToDuration(value, Unit.month);
370       case DAY_TIME_DURATION_TYPE_CODE:
371         return castToDuration(value, Unit.second);
372       case BASE64_BINARY_TYPE_CODE:
373         if (value instanceof BinaryObject)
374           return new Base64Binary(((BinaryObject) value).getBytes());
375       case HEX_BINARY_TYPE_CODE:
376         if (value instanceof BinaryObject)
377           return new HexBinary(((BinaryObject) value).getBytes());
378       }
379     return coerceFromObject(value);
380   }
381
382   Duration castToDuration (Object JavaDoc value, Unit unit)
383   {
384     if (value instanceof Duration)
385       {
386         Duration dur = (Duration) value;
387         if (dur.unit() == unit)
388           return dur;
389         int months = dur.getTotalMonths();
390         long seconds = dur.getTotalSeconds();
391         int nanos = dur.getNanoSecondsOnly();
392         if (unit == Unit.second)
393           months = 0;
394         if (unit == Unit.month)
395           {
396             seconds = 0;
397             nanos = 0;
398           }
399         return Duration.make(months, seconds, nanos, unit);
400       }
401     return (Duration) coerceFromObject(value);
402   }
403
404   public Object JavaDoc coerceFromObject (Object JavaDoc obj)
405   {
406     if (! isInstance(obj))
407       throw new ClassCastException JavaDoc("cannot cast "+obj+" to "+name);
408     return obj;
409   }
410
411   public int compare(Type other)
412   {
413     if (this == other)
414       return 0;
415     return implementationType.compare(other); // FIXME
416
}
417
418   /* #ifdef use:java.net.URI */
419   public static java.net.URI JavaDoc toURI (Object JavaDoc value)
420   {
421     try
422       {
423         return gnu.text.URI_utils.toURI(value);
424       }
425     catch (java.net.URISyntaxException JavaDoc ex)
426       {
427         return (java.net.URI JavaDoc) value;
428       }
429   }
430   /* #else */
431   // public static String toURI (Object value)
432
// {
433
// return gnu.text.URI_utils.toURI(value);
434
// }
435
/* #endif */
436
437   public Object JavaDoc valueOf (String JavaDoc value)
438   {
439     switch (typeCode)
440       {
441       case STRING_TYPE_CODE:
442         return value;
443       case UNTYPED_ATOMIC_TYPE_CODE:
444         return new UntypedAtomic(value);
445       case ANY_URI_TYPE_CODE:
446         return toURI(TextUtils.replaceWhitespace(value, true));
447       case BOOLEAN_TYPE_CODE:
448         value = value.trim();
449         if (value.equals("true") || value.equals("1"))
450           return Boolean.TRUE;
451         if (value.equals("false") || value.equals("0"))
452           return Boolean.FALSE;
453         throw new IllegalArgumentException JavaDoc("not a valid boolean: '"+value+"'");
454       case FLOAT_TYPE_CODE:
455       case DOUBLE_TYPE_CODE:
456         value = value.trim();
457         if ("INF".equals(value)) value = "Infinity";
458         else if ("-INF".equals(value)) value = "-Infinity";
459         return typeCode == FLOAT_TYPE_CODE ? (Object JavaDoc) Float.valueOf(value)
460           : (Object JavaDoc) Double.valueOf(value);
461       case DECIMAL_TYPE_CODE:
462         value = value.trim();
463         // The BigDecimal constructor accepts an exponent.
464
// So check and complain if that exists.
465
for (int i = value.length(); --i >= 0; )
466           {
467             char ch = value.charAt(i);
468             if (ch == 'e' || ch == 'E')
469               throw new IllegalArgumentException JavaDoc("not a valid decimal: '"+value+"'");
470           }
471         return new java.math.BigDecimal JavaDoc(value);
472       case DURATION_TYPE_CODE:
473         return Duration.parseDuration(value);
474       case YEAR_MONTH_DURATION_TYPE_CODE:
475         return Duration.parseYearMonthDuration(value);
476       case DAY_TIME_DURATION_TYPE_CODE:
477         return Duration.parseDayTimeDuration(value);
478       case BASE64_BINARY_TYPE_CODE:
479         return Base64Binary.valueOf(value);
480       case HEX_BINARY_TYPE_CODE:
481         return HexBinary.valueOf(value);
482       default:
483         throw new RuntimeException JavaDoc("valueOf not implemented for "+name);
484       }
485   }
486
487   public static Float JavaDoc makeFloat (float value)
488   {
489     /* #ifdef JAVA5 */
490     // return Float.valueOf(value);
491
/* #else */
492     return new Float JavaDoc(value);
493     /* #endif */
494   }
495
496   public static Double JavaDoc makeDouble (double value)
497   {
498     /* #ifdef JAVA5 */
499     // return Double.valueOf(value);
500
/* #else */
501     return new Double JavaDoc(value);
502     /* #endif */
503   }
504
505   public static final Double JavaDoc DOUBLE_ZERO = makeDouble(0);
506   public static final Double JavaDoc DOUBLE_ONE = makeDouble(1);
507   public static final Float JavaDoc FLOAT_ZERO = makeFloat(0);
508   public static final Float JavaDoc FLOAT_ONE = makeFloat(1);
509   public static final BigDecimal JavaDoc DECIMAL_ONE = BigDecimal.valueOf(1);
510
511   public Procedure getConstructor ()
512   {
513     return null;
514   }
515 }
516
Popular Tags