1 /*
2 *
3 * The DbUnit Database Testing Framework
4 * Copyright (C)2002-2004, DbUnit.org
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library 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 GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 *
20 */
21
22 package org.dbunit.dataset.datatype;
23
24 import java.sql.Connection;
25 import java.sql.PreparedStatement;
26 import java.sql.ResultSet;
27 import java.sql.SQLException;
28
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33 * Abstract data type implementation that provides generic methods that are
34 * appropriate for most data type implementations. Among those is the
35 * generic implementation of the {@link #compare(Object, Object)} method.
36 *
37 * @author Manuel Laflamme
38 * @author Last changed by: $Author: gommma $
39 * @version $Revision: 909 $ $Date: 2008-12-04 21:20:00 +0100 (gio, 04 dic 2008) $
40 * @since Mar 19, 2002
41 */
42 public abstract class AbstractDataType extends DataType
43 {
44
45 /**
46 * Logger for this class
47 */
48 private static final Logger logger = LoggerFactory.getLogger(AbstractDataType.class);
49
50 private final String _name;
51 private final int _sqlType;
52 private final Class _classType;
53 private final boolean _isNumber;
54
55 public AbstractDataType(String name, int sqlType, Class classType,
56 boolean isNumber)
57 {
58 _sqlType = sqlType;
59 _name = name;
60 _classType = classType;
61 _isNumber = isNumber;
62 }
63
64 ////////////////////////////////////////////////////////////////////////////
65 // DataType class
66
67 public int compare(Object o1, Object o2) throws TypeCastException
68 {
69 logger.debug("compare(o1={}, o2={}) - start", o1, o2);
70
71 try
72 {
73 // New in 2.3: Object level check for equality - should give massive performance improvements
74 // in the most cases because the typecast can be avoided (null values and equal objects)
75 if(areObjectsEqual(o1, o2))
76 {
77 return 0;
78 }
79
80
81 // Comparable check based on the results of method "typeCast"
82 Object value1 = typeCast(o1);
83 Object value2 = typeCast(o2);
84
85 // Check for "null"s again because typeCast can produce them
86
87 if (value1 == null && value2 == null)
88 {
89 return 0;
90 }
91
92 if (value1 == null && value2 != null)
93 {
94 return -1;
95 }
96
97 if (value1 != null && value2 == null)
98 {
99 return 1;
100 }
101
102 return compareNonNulls(value1, value2);
103
104 }
105 catch (ClassCastException e)
106 {
107 throw new TypeCastException(e);
108 }
109 }
110
111 /**
112 * Compares non-null values to each other. Both objects are guaranteed to be not
113 * null and to implement the interface {@link Comparable}. The two given objects
114 * are the results of the {@link #typeCast(Object)} method call which is usually
115 * implemented by a specialized {@link DataType} implementation.
116 * @param value1 First value resulting from the {@link #typeCast(Object)} method call
117 * @param value2 Second value resulting from the {@link #typeCast(Object)} method call
118 * @return The result of the {@link Comparable#compareTo(Object)} invocation.
119 * @throws TypeCastException
120 */
121 protected int compareNonNulls(Object value1, Object value2) throws TypeCastException
122 {
123 logger.debug("compareNonNulls(value1={}, value2={}) - start", value1, value2);
124
125 Comparable value1comp = (Comparable)value1;
126 Comparable value2comp = (Comparable)value2;
127 return value1comp.compareTo(value2comp);
128 }
129
130 /**
131 * Checks whether the given objects are equal or not.
132 * @param o1 first object
133 * @param o2 second object
134 * @return <code>true</code> if both objects are <code>null</code> (and hence equal)
135 * or if the <code>o1.equals(o2)</code> is <code>true</code>.
136 */
137 protected final boolean areObjectsEqual(Object o1, Object o2)
138 {
139 if(o1 == null && o2 == null)
140 {
141 return true;
142 }
143 if(o1 != null && o1.equals(o2))
144 {
145 return true;
146 }
147 // Note that no more check is needed for o2 because it definitely does is not equal to o1
148 // Instead immediately proceed with the typeCast method
149 return false;
150 }
151
152 public int getSqlType()
153 {
154 logger.debug("getSqlType() - start");
155
156 return _sqlType;
157 }
158
159 public Class getTypeClass()
160 {
161 logger.debug("getTypeClass() - start");
162
163 return _classType;
164 }
165
166 public boolean isNumber()
167 {
168 logger.debug("isNumber() - start");
169
170 return _isNumber;
171 }
172
173 public boolean isDateTime()
174 {
175 logger.debug("isDateTime() - start");
176
177 return false;
178 }
179
180 public Object getSqlValue(int column, ResultSet resultSet)
181 throws SQLException, TypeCastException
182 {
183 if(logger.isDebugEnabled())
184 logger.debug("getSqlValue(column={}, resultSet={}) - start", new Integer(column), resultSet);
185
186 Object value = resultSet.getObject(column);
187 if (value == null || resultSet.wasNull())
188 {
189 return null;
190 }
191 return value;
192 }
193
194 public void setSqlValue(Object value, int column, PreparedStatement statement)
195 throws SQLException, TypeCastException
196 {
197 if(logger.isDebugEnabled())
198 logger.debug("setSqlValue(value={}, column={}, statement={}) - start",
199 new Object[]{value, new Integer(column), statement} );
200
201 statement.setObject(column, typeCast(value), getSqlType());
202 }
203
204 /**
205 * @param clazz The fully qualified name of the class to be loaded
206 * @param connection The JDBC connection needed to load the given class
207 * @return The loaded class
208 * @throws ClassNotFoundException
209 */
210 protected final Class loadClass(String clazz, Connection connection) throws ClassNotFoundException
211 {
212 ClassLoader connectionClassLoader = connection.getClass().getClassLoader();
213 return this.loadClass(clazz, connectionClassLoader);
214 }
215
216 /**
217 * @param clazz The fully qualified name of the class to be loaded
218 * @param classLoader The classLoader to be used to load the given class
219 * @return The loaded class
220 * @throws ClassNotFoundException
221 */
222 protected final Class loadClass(String clazz, ClassLoader classLoader) throws ClassNotFoundException
223 {
224 Class loadedClass = classLoader.loadClass(clazz);
225 return loadedClass;
226 }
227
228 ////////////////////////////////////////////////////////////////////////////
229 // Object class
230
231 public String toString()
232 {
233 return _name;
234 }
235 }
236
237
238