001: //$Id: NullableType.java 11046 2007-01-16 15:25:54Z steve.ebersole@jboss.com $
002: package org.hibernate.type;
003:
004: import java.sql.PreparedStatement;
005: import java.sql.ResultSet;
006: import java.sql.SQLException;
007:
008: import org.apache.commons.logging.LogFactory;
009: import org.apache.commons.logging.Log;
010: import org.dom4j.Node;
011:
012: import org.hibernate.EntityMode;
013: import org.hibernate.HibernateException;
014: import org.hibernate.engine.Mapping;
015: import org.hibernate.engine.SessionFactoryImplementor;
016: import org.hibernate.engine.SessionImplementor;
017: import org.hibernate.util.ArrayHelper;
018: import org.hibernate.util.EqualsHelper;
019: import org.hibernate.util.StringHelper;
020:
021: /**
022: * Superclass of single-column nullable types.
023: * @author Gavin King
024: */
025: public abstract class NullableType extends AbstractType {
026:
027: /**
028: * This is the old scheme where logging of parameter bindings and value extractions
029: * was controlled by the trace level enablement on the 'org.hibernate.type' package...
030: * <p/>
031: * Originally was cached such because of performance of looking up the logger each time
032: * in order to check the trace-enablement. Driving this via a central Log-specific class
033: * would alleviate that performance hit, and yet still allow more "normal" logging usage/config..
034: */
035: private static final boolean IS_VALUE_TRACING_ENABLED = LogFactory
036: .getLog(StringHelper.qualifier(Type.class.getName()))
037: .isTraceEnabled();
038: private transient Log log;
039:
040: private Log log() {
041: if (log == null) {
042: log = LogFactory.getLog(getClass());
043: }
044: return log;
045: }
046:
047: /**
048: * Get a column value from a result set, without worrying about the
049: * possibility of null values. Called from {@link #nullSafeGet} after
050: * nullness checks have been performed.
051: *
052: * @param rs The result set from which to extract the value.
053: * @param name The name of the value to extract.
054: *
055: * @return The extracted value.
056: *
057: * @throws org.hibernate.HibernateException Generally some form of mismatch error.
058: * @throws java.sql.SQLException Indicates problem making the JDBC call(s).
059: */
060: public abstract Object get(ResultSet rs, String name)
061: throws HibernateException, SQLException;
062:
063: /**
064: * Set a parameter value without worrying about the possibility of null
065: * values. Called from {@link #nullSafeSet} after nullness checks have
066: * been performed.
067: *
068: * @param st The statement into which to bind the parameter value.
069: * @param value The parameter value to bind.
070: * @param index The position or index at which to bind the param value.
071: *
072: * @throws org.hibernate.HibernateException Generally some form of mismatch error.
073: * @throws java.sql.SQLException Indicates problem making the JDBC call(s).
074: */
075: public abstract void set(PreparedStatement st, Object value,
076: int index) throws HibernateException, SQLException;
077:
078: /**
079: * A convenience form of {@link #sqlTypes(org.hibernate.engine.Mapping)}, returning
080: * just a single type value since these are explicitly dealing with single column
081: * mappings.
082: *
083: * @return The {@link java.sql.Types} mapping value.
084: */
085: public abstract int sqlType();
086:
087: /**
088: * A null-safe version of {@link #toString(Object)}. Specifically we are
089: * worried about null safeness in regards to the incoming value parameter,
090: * not the return.
091: *
092: * @param value The value to convert to a string representation; may be null.
093: * @return The string representation; may be null.
094: * @throws HibernateException Thrown by {@link #toString(Object)}, which this calls.
095: */
096: public String nullSafeToString(Object value)
097: throws HibernateException {
098: return value == null ? null : toString(value);
099: }
100:
101: public abstract String toString(Object value)
102: throws HibernateException;
103:
104: public abstract Object fromStringValue(String xml)
105: throws HibernateException;
106:
107: public final void nullSafeSet(PreparedStatement st, Object value,
108: int index, boolean[] settable, SessionImplementor session)
109: throws HibernateException, SQLException {
110: if (settable[0]) {
111: nullSafeSet(st, value, index);
112: }
113: }
114:
115: public final void nullSafeSet(PreparedStatement st, Object value,
116: int index, SessionImplementor session)
117: throws HibernateException, SQLException {
118: nullSafeSet(st, value, index);
119: }
120:
121: public final void nullSafeSet(PreparedStatement st, Object value,
122: int index) throws HibernateException, SQLException {
123: try {
124: if (value == null) {
125: if (IS_VALUE_TRACING_ENABLED) {
126: log().trace("binding null to parameter: " + index);
127: }
128:
129: st.setNull(index, sqlType());
130: } else {
131: if (IS_VALUE_TRACING_ENABLED) {
132: log().trace(
133: "binding '" + toString(value)
134: + "' to parameter: " + index);
135: }
136:
137: set(st, value, index);
138: }
139: } catch (RuntimeException re) {
140: log().info(
141: "could not bind value '" + nullSafeToString(value)
142: + "' to parameter: " + index + "; "
143: + re.getMessage());
144: throw re;
145: } catch (SQLException se) {
146: log().info(
147: "could not bind value '" + nullSafeToString(value)
148: + "' to parameter: " + index + "; "
149: + se.getMessage());
150: throw se;
151: }
152: }
153:
154: public final Object nullSafeGet(ResultSet rs, String[] names,
155: SessionImplementor session, Object owner)
156: throws HibernateException, SQLException {
157: return nullSafeGet(rs, names[0]);
158: }
159:
160: public final Object nullSafeGet(ResultSet rs, String[] names)
161: throws HibernateException, SQLException {
162: return nullSafeGet(rs, names[0]);
163: }
164:
165: public final Object nullSafeGet(ResultSet rs, String name)
166: throws HibernateException, SQLException {
167: try {
168: Object value = get(rs, name);
169: if (value == null || rs.wasNull()) {
170: if (IS_VALUE_TRACING_ENABLED) {
171: log().trace("returning null as column: " + name);
172: }
173: return null;
174: } else {
175: if (IS_VALUE_TRACING_ENABLED) {
176: log().trace(
177: "returning '" + toString(value)
178: + "' as column: " + name);
179: }
180: return value;
181: }
182: } catch (RuntimeException re) {
183: log().info(
184: "could not read column value from result set: "
185: + name + "; " + re.getMessage());
186: throw re;
187: } catch (SQLException se) {
188: log().info(
189: "could not read column value from result set: "
190: + name + "; " + se.getMessage());
191: throw se;
192: }
193: }
194:
195: public final Object nullSafeGet(ResultSet rs, String name,
196: SessionImplementor session, Object owner)
197: throws HibernateException, SQLException {
198: return nullSafeGet(rs, name);
199: }
200:
201: public final String toXMLString(Object value,
202: SessionFactoryImplementor pc) throws HibernateException {
203: return toString(value);
204: }
205:
206: public final Object fromXMLString(String xml, Mapping factory)
207: throws HibernateException {
208: return xml == null || xml.length() == 0 ? null
209: : fromStringValue(xml);
210: }
211:
212: public final int getColumnSpan(Mapping session) {
213: return 1;
214: }
215:
216: public final int[] sqlTypes(Mapping session) {
217: return new int[] { sqlType() };
218: }
219:
220: public final boolean isEqual(Object x, Object y,
221: EntityMode entityMode) {
222: return isEqual(x, y);
223: }
224:
225: public boolean isEqual(Object x, Object y) {
226: return EqualsHelper.equals(x, y);
227: }
228:
229: public String toLoggableString(Object value,
230: SessionFactoryImplementor factory) {
231: return value == null ? "null" : toString(value);
232: }
233:
234: public Object fromXMLNode(Node xml, Mapping factory)
235: throws HibernateException {
236: return fromXMLString(xml.getText(), factory);
237: }
238:
239: public void setToXMLNode(Node xml, Object value,
240: SessionFactoryImplementor factory)
241: throws HibernateException {
242: xml.setText(toXMLString(value, factory));
243: }
244:
245: public boolean[] toColumnNullness(Object value, Mapping mapping) {
246: return value == null ? ArrayHelper.FALSE : ArrayHelper.TRUE;
247: }
248:
249: public boolean isDirty(Object old, Object current,
250: boolean[] checkable, SessionImplementor session)
251: throws HibernateException {
252: return checkable[0] && isDirty(old, current, session);
253: }
254:
255: }
|