001: /*
002: * JBoss, Home of Professional Open Source.
003: * Copyright 2006, Red Hat Middleware LLC, and individual contributors
004: * as indicated by the @author tags. See the copyright.txt file in the
005: * distribution for a full listing of individual contributors.
006: *
007: * This is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU Lesser General Public License as
009: * published by the Free Software Foundation; either version 2.1 of
010: * the License, or (at your option) any later version.
011: *
012: * This software is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this software; if not, write to the Free
019: * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
021: */
022: package org.jboss.ejb.plugins.cmp.jdbc;
023:
024: import org.jboss.logging.Logger;
025:
026: import javax.ejb.Handle;
027: import java.sql.ResultSet;
028: import java.sql.SQLException;
029: import java.sql.Clob;
030: import java.sql.Blob;
031: import java.rmi.MarshalledObject;
032: import java.rmi.RemoteException;
033: import java.io.IOException;
034: import java.io.Reader;
035: import java.io.InputStream;
036:
037: /**
038: * Implementations of this interface are used to read java.sql.ResultSet.
039: *
040: * @author <a href="mailto:alex@jboss.org">Alexey Loubyansky</a>
041: * @version <tt>$Revision: 57209 $</tt>
042: */
043: public interface JDBCResultSetReader {
044: /**
045: * Reads one column from the java.sql.ResultSet.
046: * @param rs the java.sql.ResultSet to read from
047: * @param index the index of the column
048: * @param destination the expected Java class of result
049: * @param log the logger
050: * @return column value
051: * @throws SQLException
052: */
053: Object get(ResultSet rs, int index, Class destination, Logger log)
054: throws SQLException;
055:
056: public static final JDBCResultSetReader CLOB_READER = new AbstractResultSetReader() {
057: protected Object readResult(ResultSet rs, int index,
058: Class destination) throws SQLException {
059: Clob clob = rs.getClob(index);
060:
061: String content;
062: if (clob == null) {
063: content = null;
064: } else {
065: final Reader reader = clob.getCharacterStream();
066: if (reader != null) {
067: int intLength = (int) clob.length();
068:
069: char[] chars;
070: try {
071: if (intLength <= 8192) {
072: chars = new char[intLength];
073: reader.read(chars);
074: content = String.valueOf(chars);
075: } else {
076: StringBuffer buf = new StringBuffer(
077: intLength);
078: chars = new char[8192];
079: int i = reader.read(chars);
080: while (i > 0) {
081: buf.append(chars, 0, i);
082: i = reader.read(chars);
083: }
084: content = buf.toString();
085: }
086: } catch (IOException e) {
087: throw new SQLException(
088: "Failed to read CLOB character stream: "
089: + e.getMessage());
090: } finally {
091: JDBCUtil.safeClose(reader);
092: }
093: } else {
094: content = null;
095: }
096: }
097:
098: return content;
099: }
100: };
101:
102: public static final JDBCResultSetReader LONGVARCHAR_READER = new AbstractResultSetReader() {
103: protected Object readResult(ResultSet rs, int index,
104: Class destination) throws SQLException {
105: return JDBCUtil.getLongString(rs, index);
106: }
107: };
108:
109: public static final JDBCResultSetReader BINARY_READER = new AbstractResultSetReader() {
110: protected Object readResult(ResultSet rs, int index,
111: Class destination) throws SQLException {
112: Object value = null;
113: byte[] bytes = rs.getBytes(index);
114: if (!rs.wasNull()) {
115: if (destination == byte[].class)
116: value = bytes;
117: else
118: value = JDBCUtil.convertToObject(bytes);
119: }
120: return value;
121: }
122: };
123:
124: public static final JDBCResultSetReader VARBINARY_READER = new AbstractResultSetReader() {
125: protected Object readResult(ResultSet rs, int index,
126: Class destination) throws SQLException {
127: Object value = null;
128: byte[] bytes = rs.getBytes(index);
129: if (!rs.wasNull()) {
130: if (destination == byte[].class)
131: value = bytes;
132: else
133: value = JDBCUtil.convertToObject(bytes);
134: }
135: return value;
136: }
137: };
138:
139: public static final JDBCResultSetReader BLOB_READER = new AbstractResultSetReader() {
140: protected Object readResult(ResultSet rs, int index,
141: Class destination) throws SQLException {
142: Blob blob = rs.getBlob(index);
143:
144: Object value;
145: if (blob == null) {
146: value = null;
147: } else {
148: InputStream binaryData = blob.getBinaryStream();
149: if (binaryData != null) {
150: if (destination == byte[].class)
151: value = JDBCUtil.getByteArray(binaryData);
152: else
153: value = JDBCUtil.convertToObject(binaryData);
154: } else {
155: value = null;
156: }
157: }
158:
159: return value;
160: }
161: };
162:
163: public static final JDBCResultSetReader LONGVARBINARY_READER = new AbstractResultSetReader() {
164: protected Object readResult(ResultSet rs, int index,
165: Class destination) throws SQLException {
166: Object value = null;
167: InputStream binaryData = rs.getBinaryStream(index);
168: if (binaryData != null && !rs.wasNull()) {
169: if (destination == byte[].class)
170: value = JDBCUtil.getByteArray(binaryData);
171: else
172: value = JDBCUtil.convertToObject(binaryData);
173: }
174: return value;
175: }
176: };
177:
178: public static final JDBCResultSetReader JAVA_OBJECT_READER = new AbstractResultSetReader() {
179: protected Object readResult(ResultSet rs, int index,
180: Class destination) throws SQLException {
181: return rs.getObject(index);
182: }
183: };
184:
185: public static final JDBCResultSetReader STRUCT_READER = new AbstractResultSetReader() {
186: protected Object readResult(ResultSet rs, int index,
187: Class destination) throws SQLException {
188: return rs.getObject(index);
189: }
190: };
191:
192: public static final JDBCResultSetReader ARRAY_READER = new AbstractResultSetReader() {
193: protected Object readResult(ResultSet rs, int index,
194: Class destination) throws SQLException {
195: return rs.getObject(index);
196: }
197: };
198:
199: public static final JDBCResultSetReader OTHER_READER = new AbstractResultSetReader() {
200: protected Object readResult(ResultSet rs, int index,
201: Class destination) throws SQLException {
202: return rs.getObject(index);
203: }
204: };
205:
206: public static final JDBCResultSetReader JAVA_UTIL_DATE_READER = new AbstractResultSetReader() {
207: protected Object readResult(ResultSet rs, int index,
208: Class destination) throws SQLException {
209: return rs.getTimestamp(index);
210: }
211:
212: protected Object coerceToJavaType(Object value,
213: Class destination) {
214: // make new copy as sub types have problems in comparions
215: java.util.Date result;
216: // handle timestamp special becauses it hoses the milisecond values
217: if (value instanceof java.sql.Timestamp) {
218: java.sql.Timestamp ts = (java.sql.Timestamp) value;
219: // Timestamp returns whole seconds from getTime and partial
220: // seconds are retrieved from getNanos()
221: // Adrian Brock: Not in 1.4 it doesn't
222: long temp = ts.getTime();
223: if (temp % 1000 == 0)
224: temp += ts.getNanos() / 1000000;
225: result = new java.util.Date(temp);
226: } else {
227: result = new java.util.Date(((java.util.Date) value)
228: .getTime());
229: }
230: return result;
231: }
232: };
233:
234: public static final JDBCResultSetReader JAVA_SQL_DATE_READER = new AbstractResultSetReader() {
235: protected Object readResult(ResultSet rs, int index,
236: Class destination) throws SQLException {
237: return rs.getDate(index);
238: }
239:
240: protected Object coerceToJavaType(Object value,
241: Class destination) {
242: // make a new copy object; you never know what a driver will return
243: return new java.sql.Date(((java.sql.Date) value).getTime());
244: }
245: };
246:
247: public static final JDBCResultSetReader JAVA_SQL_TIME_READER = new AbstractResultSetReader() {
248: protected Object readResult(ResultSet rs, int index,
249: Class destination) throws SQLException {
250: return rs.getTime(index);
251: }
252:
253: protected Object coerceToJavaType(Object value,
254: Class destination) {
255: // make a new copy object; you never know what a driver will return
256: return new java.sql.Time(((java.sql.Time) value).getTime());
257: }
258: };
259:
260: public static final JDBCResultSetReader JAVA_SQL_TIMESTAMP_READER = new AbstractResultSetReader() {
261: protected Object readResult(ResultSet rs, int index,
262: Class destination) throws SQLException {
263: return rs.getTimestamp(index);
264: }
265:
266: protected Object coerceToJavaType(Object value,
267: Class destination) {
268: // make a new copy object; you never know what a driver will return
269: java.sql.Timestamp orignal = (java.sql.Timestamp) value;
270: java.sql.Timestamp copy = new java.sql.Timestamp(orignal
271: .getTime());
272: copy.setNanos(orignal.getNanos());
273: return copy;
274: }
275: };
276:
277: public static final JDBCResultSetReader BIGDECIMAL_READER = new AbstractResultSetReader() {
278: protected Object readResult(ResultSet rs, int index,
279: Class destination) throws SQLException {
280: return rs.getBigDecimal(index);
281: }
282: };
283:
284: public static final JDBCResultSetReader REF_READER = new AbstractResultSetReader() {
285: protected Object readResult(ResultSet rs, int index,
286: Class destination) throws SQLException {
287: return rs.getRef(index);
288: }
289: };
290:
291: public static final JDBCResultSetReader BYTE_ARRAY_READER = new AbstractResultSetReader() {
292: protected Object readResult(ResultSet rs, int index,
293: Class destination) throws SQLException {
294: return rs.getBytes(index);
295: }
296: };
297:
298: public static final JDBCResultSetReader OBJECT_READER = new AbstractResultSetReader() {
299: protected Object readResult(ResultSet rs, int index,
300: Class destination) throws SQLException {
301: return rs.getObject(index);
302: }
303: };
304:
305: public static final JDBCResultSetReader STRING_READER = new JDBCResultSetReader() {
306: public Object get(ResultSet rs, int index, Class destination,
307: Logger log) throws SQLException {
308: final String result = rs.getString(index);
309:
310: if (log.isTraceEnabled()) {
311: log.trace("result: i=" + index + ", type="
312: + destination.getName() + ", value=" + result);
313: }
314:
315: return result;
316: }
317: };
318:
319: abstract class AbstractPrimitiveReader extends
320: AbstractResultSetReader {
321: // ResultSetReader implementation
322:
323: public Object get(ResultSet rs, int index, Class destination,
324: Logger log) throws SQLException {
325: Object result = readResult(rs, index, destination);
326: if (rs.wasNull())
327: result = null;
328: else
329: result = coerceToJavaType(result, destination);
330:
331: if (log.isTraceEnabled()) {
332: log.trace("result: i=" + index + ", type="
333: + destination.getName() + ", value=" + result);
334: }
335:
336: return result;
337: }
338:
339: // Protected
340:
341: protected Object coerceToJavaType(Object value,
342: Class destination) throws SQLException {
343: return value;
344: }
345: }
346:
347: public static final JDBCResultSetReader BOOLEAN_READER = new AbstractPrimitiveReader() {
348: protected Object readResult(ResultSet rs, int index,
349: Class destination) throws SQLException {
350: return (rs.getBoolean(index) ? Boolean.TRUE : Boolean.FALSE);
351: }
352: };
353:
354: public static final JDBCResultSetReader BYTE_READER = new AbstractPrimitiveReader() {
355: protected Object readResult(ResultSet rs, int index,
356: Class destination) throws SQLException {
357: return new Byte(rs.getByte(index));
358: }
359: };
360:
361: public static final JDBCResultSetReader CHARACTER_READER = new AbstractPrimitiveReader() {
362: protected Object readResult(ResultSet rs, int index,
363: Class destination) throws SQLException {
364: return rs.getString(index);
365: }
366:
367: protected Object coerceToJavaType(Object value,
368: Class destination) {
369: //
370: // java.lang.String --> java.lang.Character or char
371: //
372: // just grab first character
373: if (value instanceof String
374: && (destination == Character.class || destination == Character.TYPE)) {
375: return new Character(((String) value).charAt(0));
376: } else {
377: return value;
378: }
379: }
380: };
381:
382: public static final JDBCResultSetReader SHORT_READER = new AbstractPrimitiveReader() {
383: protected Object readResult(ResultSet rs, int index,
384: Class destination) throws SQLException {
385: return new Short(rs.getShort(index));
386: }
387: };
388:
389: public static final JDBCResultSetReader INT_READER = new AbstractPrimitiveReader() {
390: protected Object readResult(ResultSet rs, int index,
391: Class destination) throws SQLException {
392: return new Integer(rs.getInt(index));
393: }
394: };
395:
396: public static final JDBCResultSetReader LONG_READER = new AbstractPrimitiveReader() {
397: protected Object readResult(ResultSet rs, int index,
398: Class destination) throws SQLException {
399: return new Long(rs.getLong(index));
400: }
401: };
402:
403: public static final JDBCResultSetReader FLOAT_READER = new AbstractPrimitiveReader() {
404: protected Object readResult(ResultSet rs, int index,
405: Class destination) throws SQLException {
406: return new Float(rs.getFloat(index));
407: }
408: };
409:
410: public static final JDBCResultSetReader DOUBLE_READER = new AbstractPrimitiveReader() {
411: protected Object readResult(ResultSet rs, int index,
412: Class destination) throws SQLException {
413: return new Double(rs.getDouble(index));
414: }
415: };
416:
417: abstract class AbstractResultSetReader implements
418: JDBCResultSetReader {
419: public Object get(ResultSet rs, int index, Class destination,
420: Logger log) throws SQLException {
421: Object result = readResult(rs, index, destination);
422: if (result != null)
423: result = coerceToJavaType(result, destination);
424:
425: if (log.isTraceEnabled()) {
426: log.trace("result: i=" + index + ", type="
427: + destination.getName() + ", value=" + result);
428: }
429:
430: return result;
431: }
432:
433: protected abstract Object readResult(ResultSet rs, int index,
434: Class destination) throws SQLException;
435:
436: protected Object coerceToJavaType(Object value,
437: Class destination) throws SQLException {
438: try {
439: //
440: // java.rmi.MarshalledObject
441: //
442: // get unmarshalled value
443: if (value instanceof MarshalledObject
444: && !destination.equals(MarshalledObject.class)) {
445: value = ((MarshalledObject) value).get();
446: }
447:
448: //
449: // javax.ejb.Handle
450: //
451: // get the object back from the handle
452: if (value instanceof Handle) {
453: value = ((Handle) value).getEJBObject();
454: }
455:
456: // Did we get the desired result?
457: if (destination.isAssignableFrom(value.getClass())) {
458: return value;
459: }
460:
461: if (destination == java.math.BigInteger.class
462: && value.getClass() == java.math.BigDecimal.class) {
463: return ((java.math.BigDecimal) value)
464: .toBigInteger();
465: }
466:
467: // oops got the wrong type - nothing we can do
468: throw new SQLException("Got a "
469: + value.getClass().getName()
470: + "[cl="
471: + System.identityHashCode(value.getClass()
472: .getClassLoader()) + ", value=" + value
473: + "] while looking for a "
474: + destination.getName() + "[cl="
475: + System.identityHashCode(destination) + "]");
476: } catch (RemoteException e) {
477: throw new SQLException(
478: "Unable to load EJBObject back from Handle: "
479: + e);
480: } catch (IOException e) {
481: throw new SQLException(
482: "Unable to load to deserialize result: " + e);
483: } catch (ClassNotFoundException e) {
484: throw new SQLException(
485: "Unable to load to deserialize result: " + e);
486: }
487: }
488: }
489: }
|