KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > mckoi > database > TObject


1 /**
2  * com.mckoi.database.TObject 26 Jul 2002
3  *
4  * Mckoi SQL Database ( http://www.mckoi.com/database )
5  * Copyright (C) 2000, 2001, 2002 Diehl and Associates, Inc.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * Version 2 as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License Version 2 for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * Version 2 along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19  *
20  * Change Log:
21  *
22  *
23  */

24
25 package com.mckoi.database;
26
27 import java.io.IOException JavaDoc;
28 import java.io.ObjectOutputStream JavaDoc;
29 import java.util.Locale JavaDoc;
30 import com.mckoi.util.BigNumber;
31 import com.mckoi.database.global.ByteLongObject;
32 import com.mckoi.database.global.BlobRef;
33 import com.mckoi.database.global.ClobRef;
34 import com.mckoi.database.global.SQLTypes;
35 import com.mckoi.database.global.StringObject;
36
37 /**
38  * A TObject is a strongly typed object in a database engine. A TObject must
39  * maintain type information (eg. STRING, NUMBER, etc) along with the
40  * object value being represented itself.
41  *
42  * @author Tobias Downer
43  */

44
45 public final class TObject implements java.io.Serializable JavaDoc {
46
47   static final long serialVersionUID = -5129157457207765079L;
48
49   /**
50    * The type of this object.
51    */

52   private TType type;
53   
54   /**
55    * The Java representation of the object.
56    */

57   private Object JavaDoc ob;
58   
59   /**
60    * Constructs the TObject as the given type.
61    */

62   public TObject(TType type, Object JavaDoc ob) {
63     this.type = type;
64     if (ob instanceof String JavaDoc) {
65       this.ob = StringObject.fromString((String JavaDoc) ob);
66     }
67     else {
68       this.ob = ob;
69     }
70   }
71
72   /**
73    * Returns the type of this object.
74    */

75   public TType getTType() {
76     return type;
77   }
78   
79   /**
80    * Returns true if the object is null. Note that we must still be able to
81    * determine type information for an object that is NULL.
82    */

83   public boolean isNull() {
84     return (getObject() == null);
85   }
86
87   /**
88    * Returns a java.lang.Object that is the data behind this object.
89    */

90   public Object JavaDoc getObject() {
91     return ob;
92   }
93
94   /**
95    * Returns the approximate memory use of this object in bytes. This is used
96    * when the engine is caching objects and we need a general indication of how
97    * much space it takes up in memory.
98    */

99   public int approximateMemoryUse() {
100     return getTType().calculateApproximateMemoryUse(getObject());
101   }
102
103   /**
104    * Returns true if the type of this object is logically comparable to the
105    * type of the given object. For example, VARCHAR and LONGVARCHAR are
106    * comparable types. DOUBLE and FLOAT are comparable types. DOUBLE and
107    * VARCHAR are not comparable types.
108    */

109   public boolean comparableTypes(TObject ob) {
110     return getTType().comparableTypes(ob.getTType());
111   }
112
113   /**
114    * Returns the BigNumber of this object if this object is a numeric type. If
115    * the object is not a numeric type or is NULL then a null object is
116    * returned. This method can not be used to cast from a type to a number.
117    */

118   public BigNumber toBigNumber() {
119     if (getTType() instanceof TNumericType) {
120       return (BigNumber) getObject();
121     }
122     return null;
123   }
124
125   /**
126    * Returns the Boolean of this object if this object is a boolean type. If
127    * the object is not a boolean type or is NULL then a null object is
128    * returned. This method must not be used to cast from a type to a boolean.
129    */

130   public Boolean JavaDoc toBoolean() {
131     if (getTType() instanceof TBooleanType) {
132       return (Boolean JavaDoc) getObject();
133     }
134     return null;
135   }
136
137   /**
138    * Returns the String of this object if this object is a string type. If
139    * the object is not a string type or is NULL then a null object is
140    * returned. This method must not be used to cast from a type to a string.
141    */

142   public String JavaDoc toStringValue() {
143     if (getTType() instanceof TStringType) {
144       return getObject().toString();
145     }
146     return null;
147   }
148
149
150   public static final TObject BOOLEAN_TRUE =
151                            new TObject(TType.BOOLEAN_TYPE, Boolean.TRUE);
152   public static final TObject BOOLEAN_FALSE =
153                            new TObject(TType.BOOLEAN_TYPE, Boolean.FALSE);
154   public static final TObject BOOLEAN_NULL =
155                            new TObject(TType.BOOLEAN_TYPE, null);
156
157   public static final TObject NULL_OBJECT =
158                                       new TObject(TType.NULL_TYPE, null);
159
160   /**
161    * Returns a TObject of boolean type that is either true or false.
162    */

163   public static TObject booleanVal(boolean b) {
164     if (b) {
165       return BOOLEAN_TRUE;
166     }
167     return BOOLEAN_FALSE;
168   }
169
170   /**
171    * Returns a TObject of numeric type that represents the given int value.
172    */

173   public static TObject intVal(int val) {
174     return bigNumberVal(BigNumber.fromLong(val));
175   }
176
177   /**
178    * Returns a TObject of numeric type that represents the given long value.
179    */

180   public static TObject longVal(long val) {
181     return bigNumberVal(BigNumber.fromLong(val));
182   }
183
184   /**
185    * Returns a TObject of numeric type that represents the given double value.
186    */

187   public static TObject doubleVal(double val) {
188     return bigNumberVal(BigNumber.fromDouble(val));
189   }
190
191   /**
192    * Returns a TObject of numeric type that represents the given BigNumber
193    * value.
194    */

195   public static TObject bigNumberVal(BigNumber val) {
196     return new TObject(TType.NUMERIC_TYPE, val);
197   }
198
199   /**
200    * Returns a TObject of VARCHAR type that represents the given StringObject
201    * value.
202    */

203   public static TObject stringVal(StringObject str) {
204     return new TObject(TType.STRING_TYPE, str);
205   }
206
207   /**
208    * Returns a TObject of VARCHAR type that represents the given String value.
209    */

210   public static TObject stringVal(String JavaDoc str) {
211     return new TObject(TType.STRING_TYPE, StringObject.fromString(str));
212   }
213   
214   /**
215    * Returns a TObject of DATE type that represents the given time value.
216    */

217   public static TObject dateVal(java.util.Date JavaDoc d) {
218     return new TObject(TType.DATE_TYPE, d);
219   }
220
221   /**
222    * Returns a TObject of NULL type that represents a null value.
223    */

224   public static TObject nullVal() {
225     return NULL_OBJECT;
226   }
227
228   /**
229    * Returns a TObject from the given Java value.
230    */

231   public static TObject objectVal(Object JavaDoc ob) {
232     if (ob == null) {
233       return nullVal();
234     }
235     else if (ob instanceof BigNumber) {
236       return bigNumberVal((BigNumber) ob);
237     }
238     else if (ob instanceof StringObject) {
239       return stringVal((StringObject) ob);
240     }
241     else if (ob instanceof Boolean JavaDoc) {
242       return booleanVal(((Boolean JavaDoc) ob).booleanValue());
243     }
244     else if (ob instanceof java.util.Date JavaDoc) {
245       return dateVal((java.util.Date JavaDoc) ob);
246     }
247     else if (ob instanceof ByteLongObject) {
248       return new TObject(TType.BINARY_TYPE, (ByteLongObject) ob);
249     }
250     else if (ob instanceof byte[]) {
251       return new TObject(TType.BINARY_TYPE, new ByteLongObject((byte[]) ob));
252     }
253     else if (ob instanceof BlobRef) {
254       return new TObject(TType.BINARY_TYPE, (BlobRef) ob);
255     }
256     else if (ob instanceof ClobRef) {
257       return new TObject(TType.STRING_TYPE, (ClobRef) ob);
258     }
259     else {
260       throw new Error JavaDoc("Don't know how to convert object type " + ob.getClass());
261     }
262   }
263
264   /**
265    * Compares this object with the given object (which is of a logically
266    * comparable type). Returns 0 if the value of the objects are equal, < 0
267    * if this object is smaller than the given object, and > 0 if this object
268    * is greater than the given object.
269    * <p>
270    * This can not be used to compare null values so it assumes that checks
271    * for null have already been made.
272    */

273   public int compareToNoNulls(TObject tob) {
274     TType type = getTType();
275     // Strings must be handled as a special case.
276
if (type instanceof TStringType) {
277       // We must determine the locale to compare against and use that.
278
TStringType stype = (TStringType) type;
279       // If there is no locale defined for this type we use the locale in the
280
// given type.
281
if (stype.getLocale() == null) {
282         type = tob.getTType();
283       }
284     }
285     return type.compareObs(getObject(), tob.getObject());
286   }
287
288
289   /**
290    * Compares this object with the given object (which is of a logically
291    * comparable type). Returns 0 if the value of the objects are equal, < 0
292    * if this object is smaller than the given object, and > 0 if this object
293    * is greater than the given object.
294    * <p>
295    * This compares NULL values before non null values, and null values are
296    * equal.
297    */

298   public int compareTo(TObject tob) {
299     // If this is null
300
if (isNull()) {
301       // and value is null return 0 return less
302
if (tob.isNull()) {
303         return 0;
304       }
305       else {
306         return -1;
307       }
308     }
309     else {
310       // If this is not null and value is null return +1
311
if (tob.isNull()) {
312         return 1;
313       }
314       else {
315         // otherwise both are non null so compare normally.
316
return compareToNoNulls(tob);
317       }
318     }
319   }
320
321   /**
322    * Equality test. This will throw an exception if it is used. The reason
323    * for this is because it's not clear what we would be testing the equality
324    * of with this method. Equality of the object + the type or equality of the
325    * objects only?
326    */

327   public boolean equals(Object JavaDoc ob) {
328     throw new Error JavaDoc("equals method should not be used.");
329   }
330
331   /**
332    * Equality test. Returns true if this object is equivalent to the given
333    * TObject. This means the types are the same, and the object itself is the
334    * same.
335    */

336   public boolean valuesEqual(TObject ob) {
337     if (this == ob) {
338       return true;
339     }
340     if (getTType().comparableTypes(ob.getTType())) {
341       return compareTo(ob) == 0;
342     }
343     return false;
344   }
345
346
347
348   // ---------- Object operators ----------
349

350   /**
351    * Bitwise OR operation of this object with the given object. If either
352    * numeric value has a scale of 1 or greater then it returns null. If this
353    * or the given object is not a numeric type then it returns null. If either
354    * this object or the given object is NULL, then the NULL object is returned.
355    */

356   public TObject operatorOr(TObject val) {
357     BigNumber v1 = toBigNumber();
358     BigNumber v2 = val.toBigNumber();
359     TType result_type = TType.getWidestType(getTType(), val.getTType());
360     
361     if (v1 == null || v2 == null) {
362       return new TObject(result_type, null);
363     }
364
365     return new TObject(result_type, v1.bitWiseOr(v2));
366   }
367   
368   /**
369    * Mathematical addition of this object to the given object. If this or
370    * the given object is not a numeric type then it returns null.
371    * If either this object or the given object is NULL, then the NULL object
372    * is returned.
373    */

374   public TObject operatorAdd(TObject val) {
375     BigNumber v1 = toBigNumber();
376     BigNumber v2 = val.toBigNumber();
377     TType result_type = TType.getWidestType(getTType(), val.getTType());
378     
379     if (v1 == null || v2 == null) {
380       return new TObject(result_type, null);
381     }
382     
383     return new TObject(result_type, v1.add(v2));
384   }
385
386   /**
387    * Mathematical subtraction of this object to the given object. If this or
388    * the given object is not a numeric type then it returns null.
389    * If either this object or the given object is NULL, then the NULL object
390    * is returned.
391    */

392   public TObject operatorSubtract(TObject val) {
393     BigNumber v1 = toBigNumber();
394     BigNumber v2 = val.toBigNumber();
395     TType result_type = TType.getWidestType(getTType(), val.getTType());
396
397     if (v1 == null || v2 == null) {
398       return new TObject(result_type, null);
399     }
400
401     return new TObject(result_type, v1.subtract(v2));
402   }
403
404   /**
405    * Mathematical multiply of this object to the given object. If this or
406    * the given object is not a numeric type then it returns null.
407    * If either this object or the given object is NULL, then the NULL object
408    * is returned.
409    */

410   public TObject operatorMultiply(TObject val) {
411     BigNumber v1 = toBigNumber();
412     BigNumber v2 = val.toBigNumber();
413     TType result_type = TType.getWidestType(getTType(), val.getTType());
414
415     if (v1 == null || v2 == null) {
416       return new TObject(result_type, null);
417     }
418     
419     return new TObject(result_type, v1.multiply(v2));
420   }
421
422   /**
423    * Mathematical division of this object to the given object. If this or
424    * the given object is not a numeric type then it returns null.
425    * If either this object or the given object is NULL, then the NULL object
426    * is returned.
427    */

428   public TObject operatorDivide(TObject val) {
429     BigNumber v1 = toBigNumber();
430     BigNumber v2 = val.toBigNumber();
431     TType result_type = TType.getWidestType(getTType(), val.getTType());
432
433     if (v1 == null || v2 == null) {
434       return new TObject(result_type, null);
435     }
436     
437     return new TObject(result_type, v1.divide(v2));
438   }
439
440   /**
441    * String concat of this object to the given object. If this or the given
442    * object is not a string type then it returns null. If either this object
443    * or the given object is NULL, then the NULL object is returned.
444    * <p>
445    * This operator always returns an object that is a VARCHAR string type of
446    * unlimited size with locale inherited from either this or val depending
447    * on whether the locale information is defined or not.
448    */

449   public TObject operatorConcat(TObject val) {
450
451     // If this or val is null then return the null value
452
if (isNull()) {
453       return this;
454     }
455     else if (val.isNull()) {
456       return val;
457     }
458
459     TType tt1 = getTType();
460     TType tt2 = val.getTType();
461     
462     if (tt1 instanceof TStringType &&
463         tt2 instanceof TStringType) {
464       // Pick the first locale,
465
TStringType st1 = (TStringType) tt1;
466       TStringType st2 = (TStringType) tt2;
467       
468       Locale JavaDoc str_locale = null;
469       int str_strength = 0;
470       int str_decomposition = 0;
471
472       if (st1.getLocale() != null) {
473         str_locale = st1.getLocale();
474         str_strength = st1.getStrength();
475         str_decomposition = st1.getDecomposition();
476       }
477       else if (st2.getLocale() != null) {
478         str_locale = st2.getLocale();
479         str_strength = st2.getStrength();
480         str_decomposition = st2.getDecomposition();
481       }
482
483       TStringType dest_type = st1;
484       if (str_locale != null) {
485         dest_type = new TStringType(SQLTypes.VARCHAR, -1,
486                                  str_locale, str_strength, str_decomposition);
487       }
488
489       return new TObject(dest_type,
490               StringObject.fromString(toStringValue() + val.toStringValue()));
491
492     }
493
494     // Return null if LHS or RHS are not strings
495
return new TObject(tt1, null);
496   }
497   
498   /**
499    * Comparison of this object and the given object. The compared objects
500    * must be the same type otherwise it returns false. This
501    * is able to compare null values.
502    */

503   public TObject operatorIs(TObject val) {
504     if (isNull() && val.isNull()) {
505       return BOOLEAN_TRUE;
506     }
507     if (comparableTypes(val)) {
508       return booleanVal(compareTo(val) == 0);
509     }
510     // Not comparable types so return false
511
return BOOLEAN_FALSE;
512   }
513
514   /**
515    * Comparison of this object and the given object. The compared objects
516    * must be the same type otherwise it returns null (doesn't know). If either
517    * this object or the given object is NULL then NULL is returned.
518    */

519   public TObject operatorEquals(TObject val) {
520     // Check the types are comparable
521
if (comparableTypes(val) && !isNull() && !val.isNull()) {
522       return booleanVal(compareToNoNulls(val) == 0);
523     }
524     // Not comparable types so return null
525
return BOOLEAN_NULL;
526   }
527
528   /**
529    * Comparison of this object and the given object. The compared objects
530    * must be the same type otherwise it returns null (doesn't know). If either
531    * this object or the given object is NULL then NULL is returned.
532    */

533   public TObject operatorNotEquals(TObject val) {
534     // Check the types are comparable
535
if (comparableTypes(val) && !isNull() && !val.isNull()) {
536       return booleanVal(compareToNoNulls(val) != 0);
537     }
538     // Not comparable types so return null
539
return BOOLEAN_NULL;
540   }
541
542   /**
543    * Comparison of this object and the given object. The compared objects
544    * must be the same type otherwise it returns null (doesn't know). If either
545    * this object or the given object is NULL then NULL is returned.
546    */

547   public TObject operatorGreater(TObject val) {
548     // Check the types are comparable
549
if (comparableTypes(val) && !isNull() && !val.isNull()) {
550       return booleanVal(compareToNoNulls(val) > 0);
551     }
552     // Not comparable types so return null
553
return BOOLEAN_NULL;
554   }
555
556   /**
557    * Comparison of this object and the given object. The compared objects
558    * must be the same type otherwise it returns null (doesn't know). If either
559    * this object or the given object is NULL then NULL is returned.
560    */

561   public TObject operatorGreaterEquals(TObject val) {
562     // Check the types are comparable
563
if (comparableTypes(val) && !isNull() && !val.isNull()) {
564       return booleanVal(compareToNoNulls(val) >= 0);
565     }
566     // Not comparable types so return null
567
return BOOLEAN_NULL;
568   }
569
570   /**
571    * Comparison of this object and the given object. The compared objects
572    * must be the same type otherwise it returns null (doesn't know). If either
573    * this object or the given object is NULL then NULL is returned.
574    */

575   public TObject operatorLess(TObject val) {
576     // Check the types are comparable
577
if (comparableTypes(val) && !isNull() && !val.isNull()) {
578       return booleanVal(compareToNoNulls(val) < 0);
579     }
580     // Not comparable types so return null
581
return BOOLEAN_NULL;
582   }
583
584   /**
585    * Comparison of this object and the given object. The compared objects
586    * must be the same type otherwise it returns null (doesn't know). If either
587    * this object or the given object is NULL then NULL is returned.
588    */

589   public TObject operatorLessEquals(TObject val) {
590     // Check the types are comparable
591
if (comparableTypes(val) && !isNull() && !val.isNull()) {
592       return booleanVal(compareToNoNulls(val) <= 0);
593     }
594     // Not comparable types so return null
595
return BOOLEAN_NULL;
596   }
597
598
599
600   /**
601    * Performs a logical NOT on this value.
602    */

603   public TObject operatorNot() {
604     // If type is null
605
if (isNull()) {
606       return this;
607     }
608     Boolean JavaDoc b = toBoolean();
609     if (b != null) {
610       return booleanVal(!b.booleanValue());
611     }
612     return BOOLEAN_NULL;
613   }
614
615
616   
617
618   // ---------- Casting methods -----------
619

620   /**
621    * Returns a TObject of the given type and with the given Java object. If
622    * the object is not of the right type then it is cast to the correct type.
623    */

624   public static TObject createAndCastFromObject(TType type, Object JavaDoc ob) {
625     return new TObject(type, TType.castObjectToTType(ob, type));
626   }
627
628   /**
629    * Casts this object to the given type and returns a new TObject.
630    */

631   public TObject castTo(TType cast_to_type) {
632     Object JavaDoc ob = getObject();
633     return createAndCastFromObject(cast_to_type, ob);
634   }
635
636
637
638   public String JavaDoc toString() {
639     if (isNull()) {
640       return "NULL";
641     }
642     else {
643       return getObject().toString();
644     }
645   }
646
647
648 // // ------ Default casting objects ----------
649
//
650
// /**
651
// * Casts this object to a number. If this object is NULL then the returned
652
// * object is a numeric typed NULL.
653
// */
654
// public TObject castToNumber() {
655
// if (getTType().isString()) {
656
// try {
657
// return new BigDecimal((String) ob);
658
// }
659
// catch (Throwable e) {
660
// return BD_ZERO;
661
// }
662
// }
663
// if (getTType().isBoolean()) {
664
// if (((Boolean) ob).booleanValue() == true) {
665
// return BD_ONE;
666
// }
667
// else {
668
// return BD_ZERO;
669
// }
670
// }
671
// if (getTType().isDate()) {
672
// return new BigDecimal(((Date) ob).getTime());
673
// }
674
// return (BigDecimal) ob;
675
// }
676
//
677
//
678
// // ---------- Convenience statics ----------
679
//
680
// private final static BigDecimal BD_ZERO = new BigDecimal(0);
681
// private final static BigDecimal BD_ONE = new BigDecimal(1);
682

683
684   /**
685    * Writes the state of this object to the object stream. This method is
686    * implemented because GCJ doesn't like it if you implement readObject
687    * without writeObject.
688    */

689   private void writeObject(ObjectOutputStream JavaDoc out) throws IOException JavaDoc {
690     out.defaultWriteObject();
691   }
692
693   /**
694    * Serialization overwritten method. We overwrite this method because of a
695    * change with how strings are stored. In 0.93 we stored strings in this
696    * object as java.lang.String and in 0.94 we stored strings as
697    * java.lang.StringObject. This performs a conversion between the old and
698    * new format.
699    */

700   private void readObject(java.io.ObjectInputStream JavaDoc in)
701                                    throws IOException JavaDoc, ClassNotFoundException JavaDoc {
702     in.defaultReadObject();
703     // HACK: We convert old TObject that used String to represent a string object
704
// to StringObject
705
if (ob instanceof String JavaDoc) {
706       ob = StringObject.fromString((String JavaDoc) ob);
707     }
708   }
709
710 }
711
712
Popular Tags