View Javadoc
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 }