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 
35   * generic 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 = 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