001: /**
002: * Objective Database Abstraction Layer (ODAL)
003: * Copyright (c) 2004, The ODAL Development Group
004: * All rights reserved.
005: * For definition of the ODAL Development Group please refer to LICENCE.txt file
006: *
007: * Distributable under LGPL license.
008: * See terms of license at gnu.org.
009: */package com.completex.objective.components.persistency;
010:
011: import com.completex.objective.components.persistency.type.TypeHandler;
012:
013: import java.io.InputStream;
014: import java.math.BigDecimal;
015: import java.sql.Blob;
016: import java.sql.Clob;
017: import java.sql.Timestamp;
018: import java.sql.Types;
019: import java.util.Collection;
020: import java.util.HashMap;
021: import java.util.Map;
022:
023: /**
024: * Meta class to facilitate database-to-java type translation and binding.
025: * Contains set of predefined (internal) types as well as allows for creation
026: * of new custom types.
027: *
028: * @author Gennady Krizhevsky
029: */
030: public class ColumnType {
031:
032: public static final Object NULL_BINARY_OBJECT = new Object() {
033: public String toString() {
034: return "NULL_BINARY_OBJECT";
035: }
036: };
037:
038: private String name;
039: private Class valueClass;
040: private boolean keyable = true;
041: private TypeHandler customTypeHandler;
042: private int defaultJdbcType;
043: private String defaultJdbcTypeName;
044: private String valueClassName;
045: /**
046: * One of type group constants
047: */
048: private int typeGroup;
049: private boolean primitive;
050:
051: /**
052: * Type group constants
053: */
054: public static final int TYPE_GROUP_NUMERIC = (int) Math.pow(2, 0);
055: public static final int TYPE_GROUP_STRING = (int) Math.pow(2, 1);
056: public static final int TYPE_GROUP_BINARY = (int) Math.pow(2, 2);
057: public static final int TYPE_GROUP_DATE = (int) Math.pow(2, 3);
058: public static final int TYPE_GROUP_BOOLEAN = (int) Math.pow(2, 4);
059: public static final int TYPE_GROUP_OBJECT = (int) Math.pow(2, 5);
060:
061: /**
062: * @param name type name
063: * @param valueClass used when generating persistent objects as field type
064: * @see TypeHandler
065: */
066: public ColumnType(String name, Class valueClass) {
067: this .name = name;
068: this .valueClass = valueClass;
069: }
070:
071: /**
072: * @param name type name
073: * @param valueClass used when generating persistent objects as field type
074: * @param defaultJdbcType used when binding null values
075: * @see TypeHandler
076: */
077: public ColumnType(String name, Class valueClass, int defaultJdbcType) {
078: this .name = name;
079: this .valueClass = valueClass;
080: this .defaultJdbcType = defaultJdbcType;
081: }
082:
083: /**
084: * @param name type name
085: * @param valueClass used when generating persistent objects as field type
086: * @param customTypeHandler TypeHandler that will be used instead of default one for this ColumnType
087: * @param defaultJdbcType used when binding null values
088: * @see TypeHandler
089: */
090: public ColumnType(String name, Class valueClass,
091: TypeHandler customTypeHandler, int defaultJdbcType) {
092: this .name = name;
093: this .valueClass = valueClass;
094: this .customTypeHandler = customTypeHandler;
095: this .defaultJdbcType = defaultJdbcType;
096: }
097:
098: /**
099: * @param name type name
100: * @param valueClass used when generating persistent objects as field type
101: * @param customTypeHandler TypeHandler that will be used instead of default one for this ColumnType
102: * @param defaultJdbcType used when binding null values
103: * @param defaultJdbcTypeName reserved
104: * @see TypeHandler
105: */
106: public ColumnType(String name, Class valueClass,
107: TypeHandler customTypeHandler, int defaultJdbcType,
108: String defaultJdbcTypeName) {
109: this .name = name;
110: this .valueClass = valueClass;
111: this .customTypeHandler = customTypeHandler;
112: this .defaultJdbcType = defaultJdbcType;
113: this .defaultJdbcTypeName = defaultJdbcTypeName;
114: }
115:
116: /**
117: * Returns column type name
118: *
119: * @return column type name
120: */
121: public String getName() {
122: return name;
123: }
124:
125: public String getValueClassName() {
126: if (valueClassName != null) {
127: return valueClassName;
128: } else if (valueClass != null) {
129: return valueClass.getName();
130: }
131: return valueClassName;
132: }
133:
134: public void setValueClassName(String valueClassName) {
135: this .valueClassName = valueClassName;
136: }
137:
138: /**
139: * Returns value class
140: *
141: * @return value class
142: */
143: public Class getValueClass() {
144: return valueClass;
145: }
146:
147: public int getTypeGroup() {
148: return typeGroup;
149: }
150:
151: protected void setTypeGroup(int typeGroup) {
152: this .typeGroup = typeGroup;
153: }
154:
155: public boolean isPrimitive() {
156: return primitive;
157: }
158:
159: protected void setPrimitive(boolean primitive) {
160: this .primitive = primitive;
161: }
162:
163: /**
164: * Returns value class simple name
165: *
166: * @return value class simple name
167: */
168: public String getValueClassSimpleName() {
169: if (valueClass == null) {
170: return null;
171: }
172:
173: if (valueClassName != null) {
174: return valueClassName;
175: }
176:
177: String[] tokens;
178: tokens = valueClass.getName().split("\\.");
179: return tokens[tokens.length - 1];
180: }
181:
182: /**
183: * Returns custom type handler
184: *
185: * @return custom type handler
186: */
187: public TypeHandler getCustomTypeHandler() {
188: return customTypeHandler;
189: }
190:
191: /**
192: * Sets custom type handler
193: *
194: * @param customTypeHandler custom type handler
195: */
196: public void setCustomTypeHandler(TypeHandler customTypeHandler) {
197: this .customTypeHandler = customTypeHandler;
198: }
199:
200: protected void setTypeGroupNumeric() {
201: setTypeGroup(TYPE_GROUP_NUMERIC);
202: }
203:
204: protected void setTypeGroupString() {
205: setTypeGroup(TYPE_GROUP_STRING);
206: }
207:
208: protected void setTypeGroupBinary() {
209: setTypeGroup(TYPE_GROUP_BINARY);
210: }
211:
212: protected void setTypeGroupDate() {
213: setTypeGroup(TYPE_GROUP_DATE);
214: }
215:
216: protected void setTypeGroupBoolean() {
217: setTypeGroup(TYPE_GROUP_BOOLEAN);
218: }
219:
220: protected void setTypeGroupObject() {
221: setTypeGroup(TYPE_GROUP_OBJECT);
222: }
223:
224: /**
225: * Returns default jdbc type
226: *
227: * @return default jdbc type
228: */
229: public int getDefaultJdbcType() {
230: return defaultJdbcType;
231: }
232:
233: protected void setDefaultJdbcType(int defaultJdbcType) {
234: this .defaultJdbcType = defaultJdbcType;
235: }
236:
237: /**
238: * Returns default jdbc type name
239: *
240: * @return default jdbc type name
241: */
242: public String getDefaultJdbcTypeName() {
243: return defaultJdbcTypeName;
244: }
245:
246: protected void setDefaultJdbcTypeName(String defaultJdbcTypeName) {
247: this .defaultJdbcTypeName = defaultJdbcTypeName;
248: }
249:
250: /**
251: * Return true if the type can be used as part of database key
252: *
253: * @return true if the type can be used as part of database key
254: */
255: public boolean isKeyable() {
256: return keyable;
257: }
258:
259: /**
260: * Set true if the type can be used as part of database key
261: *
262: * @param keyable true if the type can be used as part of database key
263: */
264: public void setKeyable(boolean keyable) {
265: this .keyable = keyable;
266: }
267:
268: /**
269: * Predefined column types:
270: */
271: public static ColumnType BOOLEAN = new BooleanColumnType("BOOLEAN",
272: Boolean.class);
273: public static ColumnType CHAR = new StringColumnType("CHAR",
274: String.class);
275: public static ColumnType STRING = new StringColumnType("STRING",
276: String.class);
277: public static ColumnType LONG = new IntegerColumnType("LONG",
278: Long.class);
279: public static ColumnType DOUBLE = new DecimalColumnType("DOUBLE",
280: Double.class);
281: public static ColumnType NUMBER = new DecimalColumnType("NUMBER",
282: Number.class);
283: public static ColumnType BIGDECIMAL = new DecimalColumnType(
284: "BIGDECIMAL", BigDecimal.class);
285: public static ColumnType DATE = new DateColumnType("DATE",
286: java.util.Date.class);
287: public static ColumnType TIMESTAMP = new DateColumnType(
288: "TIMESTAMP", Timestamp.class);
289: public static ColumnType BINARY = new BasicBinaryColumnType(
290: "BINARY", InputStream.class, Types.BINARY);
291: public static ColumnType DETACHED_INPUT_STREAM = new BasicBinaryColumnType(
292: "DETACHED_INPUT_STREAM", InputStream.class, Types.BINARY);
293: public static ColumnType BYTE_ARRAY = new BasicBinaryColumnType(
294: "BYTE_ARRAY", byte[].class, Types.BINARY);
295: static {
296: BYTE_ARRAY.setValueClassName("byte[]");
297: }
298: public static ColumnType BLOB = new BasicBinaryColumnType("BLOB",
299: Blob.class, Types.BLOB);
300: public static ColumnType DETACHED_BLOB = new BasicBinaryColumnType(
301: "DETACHED_BLOB", Blob.class, Types.BLOB);
302: public static ColumnType CLOB = new ClobColumnType("CLOB",
303: Clob.class);
304: public static ColumnType DETACHED_CLOB = new ClobColumnType(
305: "DETACHED_CLOB", Clob.class);
306: public static ColumnType CLOB_STRING = new ClobColumnType(
307: "CLOB_STRING", String.class);
308: // Primitives support:
309: public static final ColumnType LONG_PRIMITIVE = new IntegerPrimitiveColumnType(
310: "LONG_PRIMITIVE", long.class);
311: public static final ColumnType DOUBLE_PRIMITIVE = new DecimalPrimitiveColumnType(
312: "DOUBLE_PRIMITIVE", double.class);
313: public static final ColumnType BOOLEAN_PRIMITIVE = new BooleanPrimitiveColumnType(
314: "BOOLEAN_PRIMITIVE", boolean.class);
315: //
316: // Complex or unknown objects:
317: //
318: public static final ColumnType OBJECT = new ColumnType("OBJECT",
319: Object.class);
320: static {
321: OBJECT.setTypeGroupObject();
322: }
323:
324: private static final Map columns = new HashMap();
325:
326: static {
327: columns.put(BOOLEAN.getName(), BOOLEAN);
328: columns.put(LONG.getName(), LONG);
329: columns.put(DOUBLE.getName(), DOUBLE);
330: columns.put(NUMBER.getName(), NUMBER);
331: columns.put(STRING.getName(), STRING);
332: columns.put(CHAR.getName(), CHAR);
333: columns.put(DATE.getName(), DATE);
334: columns.put(BLOB.getName(), BLOB);
335: columns.put(DETACHED_BLOB.getName(), DETACHED_BLOB);
336: columns.put(CLOB.getName(), CLOB);
337: columns.put(DETACHED_CLOB.getName(), DETACHED_CLOB);
338: columns.put(BINARY.getName(), BINARY);
339: columns.put(BYTE_ARRAY.getName(), BYTE_ARRAY);
340: // columns.put(INTEGER.getName(), INTEGER);
341: columns.put(BIGDECIMAL.getName(), BIGDECIMAL);
342: columns.put(TIMESTAMP.getName(), TIMESTAMP);
343: columns.put(CLOB_STRING.getName(), CLOB_STRING);
344: // Primitives support:
345: columns.put(LONG_PRIMITIVE.getName(), LONG_PRIMITIVE);
346: columns.put(DOUBLE_PRIMITIVE.getName(), DOUBLE_PRIMITIVE);
347: columns.put(BOOLEAN_PRIMITIVE.getName(), BOOLEAN_PRIMITIVE);
348: //
349: // Complex or unknown objects:
350: //
351: columns.put(OBJECT.getName(), OBJECT);
352: }
353:
354: public boolean isNumeric() {
355: return typeGroup == TYPE_GROUP_NUMERIC;
356: }
357:
358: public boolean isBoolean() {
359: return typeGroup == TYPE_GROUP_BOOLEAN;
360: }
361:
362: public boolean isString() {
363: return typeGroup == TYPE_GROUP_STRING;
364: }
365:
366: public boolean isDate() {
367: return typeGroup == TYPE_GROUP_DATE;
368: }
369:
370: public boolean isBinary() {
371: return typeGroup == TYPE_GROUP_BINARY;
372: }
373:
374: public static boolean isNumeric(ColumnType type) {
375: return type != null && type.isNumeric();
376: }
377:
378: public static boolean isPrimitive(ColumnType type) {
379: return type != null && type.isPrimitive();
380: }
381:
382: public static boolean isBoolean(ColumnType type) {
383: return type != null && type.isBoolean();
384: }
385:
386: public static boolean isBooleanPrimitive(ColumnType type) {
387: return type != null && type.isBoolean() && type.isPrimitive();
388: }
389:
390: public static boolean isString(ColumnType type) {
391: return type != null && type.isString();
392: }
393:
394: public static boolean isDate(ColumnType type) {
395: return type != null && type.isDate();
396: }
397:
398: public static boolean isBinary(ColumnType type) {
399: return type != null && type.isBinary();
400: }
401:
402: public static boolean isObject(ColumnType type) {
403: return type != null && type.isObject();
404: }
405:
406: public boolean isObject() {
407: return false;
408: }
409:
410: private String toKey() {
411: return new StringBuffer().append(name).toString();
412: }
413:
414: public int hashCode() {
415: return toKey().hashCode();
416: }
417:
418: public boolean equals(Object obj) {
419: if (obj == null) {
420: return false;
421: }
422: ColumnType columnType = (ColumnType) obj;
423: return toKey().equals(columnType.toKey());
424: }
425:
426: public String toString() {
427: final StringBuffer sb = new StringBuffer();
428: sb.append(" name = ").append(name);
429: sb.append("; defaultJdbcType = ").append(defaultJdbcType);
430: sb.append("; defaultJdbcTypeName = ").append(
431: defaultJdbcTypeName);
432: return sb.toString();
433: }
434:
435: /**
436: * Returns true if column type is one of the internal ones
437: *
438: * @param columnType column type
439: * @return true if column type is one of the internal ones
440: */
441: public static boolean contains(ColumnType columnType) {
442: return columns.containsKey(columnType.getName());
443: }
444:
445: /**
446: * Returns true if column type is one of the internal ones
447: *
448: * @param columnTypeName column type name
449: * @return true if column type is one of the internal ones
450: */
451: public static boolean contains(String columnTypeName) {
452: return columns.containsKey(columnTypeName);
453: }
454:
455: /**
456: * Returns ColumnType by its name
457: *
458: * @param name
459: * @return ColumnType by its name
460: */
461: public static ColumnType toColumnType(String name) {
462: return (ColumnType) columns.get(name);
463: }
464:
465: /**
466: * Return true if columnType can be used as database key. If columnType is null returns false.
467: *
468: * @param columnType ColumnType to test
469: * @return true if columnType can be used as database key. If columnType is null returns false.
470: */
471: public static boolean isKeyable(ColumnType columnType) {
472: return columnType != null && columnType.isKeyable();
473: }
474:
475: /**
476: * Returns internal column types
477: *
478: * @return internal column types
479: */
480: public static ColumnType[] getColumnTypes() {
481: Collection values = columns.values();
482: return (ColumnType[]) values.toArray(new ColumnType[values
483: .size()]);
484: }
485:
486: //
487: //
488: // Subclasses:
489: //
490: //
491:
492: //
493: // String group:
494: //
495: public static class BasicStringColumnType extends ColumnType {
496: {
497: setTypeGroupString();
498: }
499:
500: public BasicStringColumnType(String name, Class valueClass) {
501: super (name, valueClass);
502: }
503:
504: public BasicStringColumnType(String name, Class valueClass,
505: int defaultJdbcType) {
506: super (name, valueClass, defaultJdbcType);
507: }
508:
509: public BasicStringColumnType(String name, Class valueClass,
510: TypeHandler customTypeHandler, int defaultJdbcType) {
511: super (name, valueClass, customTypeHandler, defaultJdbcType);
512: }
513:
514: public BasicStringColumnType(String name, Class valueClass,
515: TypeHandler customTypeHandler, int defaultJdbcType,
516: String defaultJdbcTypeName) {
517: super (name, valueClass, customTypeHandler, defaultJdbcType,
518: defaultJdbcTypeName);
519: }
520: }
521:
522: public static class StringColumnType extends BasicStringColumnType {
523: public StringColumnType(String name, Class valueClass) {
524: super (name, valueClass, Types.VARCHAR);
525: }
526:
527: public StringColumnType(String name, Class valueClass,
528: TypeHandler customTypeHandler) {
529: super (name, valueClass, customTypeHandler, Types.VARCHAR);
530: }
531: }
532:
533: //
534: // Numeric group:
535: //
536: public static class BasicNumericColumnType extends ColumnType {
537: {
538: setTypeGroupNumeric();
539: }
540:
541: public BasicNumericColumnType(String name, Class valueClass) {
542: super (name, valueClass);
543: }
544:
545: public BasicNumericColumnType(String name, Class valueClass,
546: int defaultJdbcType) {
547: super (name, valueClass, defaultJdbcType);
548: }
549:
550: public BasicNumericColumnType(String name, Class valueClass,
551: TypeHandler customTypeHandler, int defaultJdbcType) {
552: super (name, valueClass, customTypeHandler, defaultJdbcType);
553: }
554:
555: public BasicNumericColumnType(String name, Class valueClass,
556: TypeHandler customTypeHandler, int defaultJdbcType,
557: String defaultJdbcTypeName) {
558: super (name, valueClass, customTypeHandler, defaultJdbcType,
559: defaultJdbcTypeName);
560: }
561: }
562:
563: public static class IntegerColumnType extends
564: BasicNumericColumnType {
565: public IntegerColumnType(String name, Class valueClass) {
566: super (name, valueClass, Types.INTEGER);
567: }
568:
569: public IntegerColumnType(String name, Class valueClass,
570: TypeHandler customTypeHandler) {
571: super (name, valueClass, customTypeHandler, Types.INTEGER);
572: }
573: }
574:
575: public static class IntegerPrimitiveColumnType extends
576: IntegerColumnType {
577: {
578: setPrimitive(true);
579: }
580:
581: public IntegerPrimitiveColumnType(String name, Class valueClass) {
582: super (name, valueClass);
583: }
584:
585: public IntegerPrimitiveColumnType(String name,
586: Class valueClass, TypeHandler customTypeHandler) {
587: super (name, valueClass, customTypeHandler);
588: }
589: }
590:
591: public static class DecimalColumnType extends
592: BasicNumericColumnType {
593: public DecimalColumnType(String name, Class valueClass) {
594: super (name, valueClass, Types.DECIMAL);
595: }
596:
597: public DecimalColumnType(String name, Class valueClass,
598: TypeHandler customTypeHandler) {
599: super (name, valueClass, customTypeHandler, Types.DECIMAL);
600: }
601: }
602:
603: public static class DecimalPrimitiveColumnType extends
604: DecimalColumnType {
605: {
606: setPrimitive(true);
607: }
608:
609: public DecimalPrimitiveColumnType(String name, Class valueClass) {
610: super (name, valueClass);
611: }
612:
613: public DecimalPrimitiveColumnType(String name,
614: Class valueClass, TypeHandler customTypeHandler) {
615: super (name, valueClass, customTypeHandler);
616: }
617: }
618:
619: //
620: // Date group:
621: //
622: public static class BasicDateColumnType extends ColumnType {
623:
624: {
625: setTypeGroupDate();
626: }
627:
628: public BasicDateColumnType(String name, Class valueClass) {
629: super (name, valueClass);
630: }
631:
632: public BasicDateColumnType(String name, Class valueClass,
633: int defaultJdbcType) {
634: super (name, valueClass, defaultJdbcType);
635: }
636:
637: public BasicDateColumnType(String name, Class valueClass,
638: TypeHandler customTypeHandler, int defaultJdbcType) {
639: super (name, valueClass, customTypeHandler, defaultJdbcType);
640: }
641:
642: public BasicDateColumnType(String name, Class valueClass,
643: TypeHandler customTypeHandler, int defaultJdbcType,
644: String defaultJdbcTypeName) {
645: super (name, valueClass, customTypeHandler, defaultJdbcType,
646: defaultJdbcTypeName);
647: }
648: }
649:
650: public static class DateColumnType extends BasicDateColumnType {
651: public DateColumnType(String name, Class valueClass) {
652: super (name, valueClass, Types.DATE);
653: }
654:
655: public DateColumnType(String name, Class valueClass,
656: TypeHandler customTypeHandler) {
657: super (name, valueClass, customTypeHandler, Types.DATE);
658: }
659: }
660:
661: //
662: // Boolean group:
663: //
664: public static class BasicBooleanColumnType extends ColumnType {
665:
666: {
667: setTypeGroupBoolean();
668: }
669:
670: public BasicBooleanColumnType(String name, Class valueClass) {
671: super (name, valueClass);
672: }
673:
674: public BasicBooleanColumnType(String name, Class valueClass,
675: int defaultJdbcType) {
676: super (name, valueClass, defaultJdbcType);
677: }
678:
679: public BasicBooleanColumnType(String name, Class valueClass,
680: TypeHandler customTypeHandler, int defaultJdbcType) {
681: super (name, valueClass, customTypeHandler, defaultJdbcType);
682: }
683:
684: public BasicBooleanColumnType(String name, Class valueClass,
685: TypeHandler customTypeHandler, int defaultJdbcType,
686: String defaultJdbcTypeName) {
687: super (name, valueClass, customTypeHandler, defaultJdbcType,
688: defaultJdbcTypeName);
689: }
690: }
691:
692: public static class BooleanColumnType extends
693: BasicBooleanColumnType {
694: public BooleanColumnType(String name, Class valueClass) {
695: super (name, valueClass, Types.VARCHAR);
696: }
697:
698: public BooleanColumnType(String name, Class valueClass,
699: TypeHandler customTypeHandler) {
700: super (name, valueClass, customTypeHandler, Types.VARCHAR);
701: }
702: }
703:
704: public static class BooleanPrimitiveColumnType extends
705: BooleanColumnType {
706: {
707: setPrimitive(true);
708: }
709:
710: public BooleanPrimitiveColumnType(String name, Class valueClass) {
711: super (name, valueClass);
712: }
713:
714: public BooleanPrimitiveColumnType(String name,
715: Class valueClass, TypeHandler customTypeHandler) {
716: super (name, valueClass, customTypeHandler);
717: }
718: }
719:
720: //
721: // Binary group:
722: //
723: public static class BasicBinaryColumnType extends ColumnType {
724:
725: {
726: setTypeGroupBinary();
727: setKeyable(false);
728: }
729:
730: public BasicBinaryColumnType(String name, Class valueClass) {
731: super (name, valueClass);
732: }
733:
734: public BasicBinaryColumnType(String name, Class valueClass,
735: int defaultJdbcType) {
736: super (name, valueClass, defaultJdbcType);
737: }
738:
739: public BasicBinaryColumnType(String name, Class valueClass,
740: TypeHandler customTypeHandler, int defaultJdbcType) {
741: super (name, valueClass, customTypeHandler, defaultJdbcType);
742: }
743:
744: public BasicBinaryColumnType(String name, Class valueClass,
745: TypeHandler customTypeHandler, int defaultJdbcType,
746: String defaultJdbcTypeName) {
747: super (name, valueClass, customTypeHandler, defaultJdbcType,
748: defaultJdbcTypeName);
749: }
750: }
751:
752: public static class ClobColumnType extends BasicBinaryColumnType {
753: public ClobColumnType(String name, Class valueClass) {
754: super (name, valueClass, Types.CLOB);
755: }
756:
757: public ClobColumnType(String name, Class valueClass,
758: TypeHandler customTypeHandler) {
759: super(name, valueClass, customTypeHandler, Types.CLOB);
760: }
761: }
762:
763: }
|