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 generic
35 * implementation of the {@link #compare(Object, Object)} method.
36 *
37 * @author Manuel Laflamme
38 * @author Last changed by: $Author$
39 * @version $Revision$ $Date$
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 =
49 LoggerFactory.getLogger(AbstractDataType.class);
50
51 private final String _name;
52 private final int _sqlType;
53 private final Class _classType;
54 private final boolean _isNumber;
55
56 public AbstractDataType(final String name, final int sqlType,
57 final Class classType, final boolean isNumber)
58 {
59 _sqlType = sqlType;
60 _name = name;
61 _classType = classType;
62 _isNumber = isNumber;
63 }
64
65 ////////////////////////////////////////////////////////////////////////////
66 // DataType class
67
68 @Override
69 public int compare(final Object o1, final Object o2)
70 throws TypeCastException
71 {
72 logger.debug("compare(o1={}, o2={}) - start", o1, o2);
73
74 try
75 {
76 // New in 2.3: Object level check for equality - should give massive
77 // performance improvements
78 // in the most cases because the typecast can be avoided (null
79 // values and equal objects)
80 if (areObjectsEqual(o1, o2))
81 {
82 return 0;
83 }
84
85 // Comparable check based on the results of method "typeCast"
86 final Object value1 = typeCast(o1);
87 final Object value2 = typeCast(o2);
88
89 // Check for "null"s again because typeCast can produce them
90
91 if (value1 == null && value2 == null)
92 {
93 return 0;
94 }
95
96 if (value1 == null && value2 != null)
97 {
98 return -1;
99 }
100
101 if (value1 != null && value2 == null)
102 {
103 return 1;
104 }
105
106 return compareNonNulls(value1, value2);
107
108 } catch (final ClassCastException e)
109 {
110 throw new TypeCastException(e);
111 }
112 }
113
114 /**
115 * Compares non-null values to each other. Both objects are guaranteed to be
116 * not null and to implement the interface {@link Comparable}. The two given
117 * objects are the results of the {@link #typeCast(Object)} method call
118 * which is usually implemented by a specialized {@link DataType}
119 * implementation.
120 *
121 * @param value1
122 * First value resulting from the {@link #typeCast(Object)}
123 * method call
124 * @param value2
125 * Second value resulting from the {@link #typeCast(Object)}
126 * method call
127 * @return The result of the {@link Comparable#compareTo(Object)}
128 * invocation.
129 * @throws TypeCastException
130 */
131 protected int compareNonNulls(final Object value1, final Object value2)
132 throws TypeCastException
133 {
134 logger.debug("compareNonNulls(value1={}, value2={}) - start", value1,
135 value2);
136
137 final Comparable value1comp = (Comparable) value1;
138 final Comparable value2comp = (Comparable) value2;
139 return value1comp.compareTo(value2comp);
140 }
141
142 /**
143 * Checks whether the given objects are equal or not.
144 *
145 * @param o1
146 * first object
147 * @param o2
148 * second object
149 * @return <code>true</code> if both objects are <code>null</code> (and
150 * hence equal) or if the <code>o1.equals(o2)</code> is
151 * <code>true</code>.
152 */
153 protected final boolean areObjectsEqual(final Object o1, final Object o2)
154 {
155 if (o1 == null && o2 == null)
156 {
157 return true;
158 }
159 return o1 != null && o1.equals(o2);
160 // Note that no more check is needed for o2 because it definitely does
161 // is not equal to o1
162 // Instead immediately proceed with the typeCast method
163 }
164
165 @Override
166 public int getSqlType()
167 {
168 logger.debug("getSqlType() - start");
169
170 return _sqlType;
171 }
172
173 @Override
174 public Class getTypeClass()
175 {
176 logger.debug("getTypeClass() - start");
177
178 return _classType;
179 }
180
181 @Override
182 public boolean isNumber()
183 {
184 logger.debug("isNumber() - start");
185
186 return _isNumber;
187 }
188
189 @Override
190 public boolean isDateTime()
191 {
192 logger.debug("isDateTime() - start");
193
194 return false;
195 }
196
197 @Override
198 public Object getSqlValue(final int column, final ResultSet resultSet)
199 throws SQLException, TypeCastException
200 {
201 logger.debug("getSqlValue(column={}, resultSet={}) - start", column,
202 resultSet);
203 final Object rawValue = resultSet.getObject(column);
204 final Object value = resultSet.wasNull() ? null : rawValue;
205 logger.debug("getSqlValue: column={}, value={}", column, value);
206 return value;
207 }
208
209 @Override
210 public void setSqlValue(final Object value, final int column,
211 final PreparedStatement statement)
212 throws SQLException, TypeCastException
213 {
214 logger.debug("setSqlValue(value={}, column={}, statement={}) - start",
215 value, column, statement);
216
217 statement.setObject(column, typeCast(value), getSqlType());
218 }
219
220 /**
221 * @param clazz
222 * The fully qualified name of the class to be loaded
223 * @param connection
224 * The JDBC connection needed to load the given class
225 * @return The loaded class
226 * @throws ClassNotFoundException
227 */
228 protected final Class loadClass(final String clazz,
229 final Connection connection) throws ClassNotFoundException
230 {
231 final ClassLoader connectionClassLoader =
232 connection.getClass().getClassLoader();
233 return this.loadClass(clazz, connectionClassLoader);
234 }
235
236 /**
237 * @param clazz
238 * The fully qualified name of the class to be loaded
239 * @param classLoader
240 * The classLoader to be used to load the given class
241 * @return The loaded class
242 * @throws ClassNotFoundException
243 */
244 protected final Class loadClass(final String clazz,
245 final ClassLoader classLoader) throws ClassNotFoundException
246 {
247 return classLoader.loadClass(clazz);
248 }
249
250 ////////////////////////////////////////////////////////////////////////////
251 // Object class
252
253 @Override
254 public String toString()
255 {
256 return _name;
257 }
258 }