package org.jboss.ejb.plugins.cmp.jdbc;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Reader;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.rmi.MarshalledObject;
import java.rmi.RemoteException;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.sql.SQLException;
import java.sql.Types;
import java.sql.CallableStatement;
import java.util.Map;
import java.util.HashMap;
import java.math.BigDecimal;
import javax.ejb.EJBObject;
import javax.ejb.Handle;
import org.jboss.invocation.MarshalledValue;
import org.jboss.logging.Logger;
public final class JDBCUtil
{
private static final Logger log = Logger.getLogger(JDBCUtil.class.getName());
public static void safeClose(Connection con)
{
if(con != null)
{
try
{
con.close();
}
catch(Exception e)
{
log.error(SQL_ERROR, e);
}
}
}
public static void safeClose(ResultSet rs)
{
if(rs != null)
{
try
{
rs.close();
}
catch(Exception e)
{
log.error(SQL_ERROR, e);
}
}
}
public static void safeClose(Statement statement)
{
if(statement != null)
{
try
{
statement.close();
}
catch(Exception e)
{
log.error(SQL_ERROR, e);
}
}
}
public static void safeClose(InputStream in)
{
if(in != null)
{
try
{
in.close();
}
catch(Exception e)
{
log.error(SQL_ERROR, e);
}
}
}
public static void safeClose(OutputStream out)
{
if(out != null)
{
try
{
out.close();
}
catch(Exception e)
{
log.error(SQL_ERROR, e);
}
}
}
public static void safeClose(Reader reader)
{
if(reader != null)
{
try
{
reader.close();
}
catch(Exception e)
{
log.error(SQL_ERROR, e);
}
}
}
public static Object coerceToSQLType(int jdbcType, Object value)
{
if(value.getClass() == java.util.Date.class)
{
if(jdbcType == Types.DATE)
{
return new java.sql.Date(((java.util.Date)value).getTime());
}
else if(jdbcType == Types.TIME)
{
return new java.sql.Time(((java.util.Date)value).getTime());
}
else if(jdbcType == Types.TIMESTAMP)
{
return new java.sql.Timestamp(((java.util.Date)value).getTime());
}
}
else if(value.getClass() == Character.class && jdbcType == Types.VARCHAR)
{
value = value.toString();
}
return value;
}
public static byte[] convertObjectToByteArray(Object value)
throws SQLException
{
if(value instanceof byte[])
{
return (byte[])value;
}
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
try
{
if(value instanceof EJBObject)
{
value = ((EJBObject)value).getHandle();
}
value = new MarshalledValue(value);
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(value);
return baos.toByteArray();
}
catch(RemoteException e)
{
throw new SQLException("Cannot get Handle of EJBObject: " + e);
}
catch(IOException e)
{
throw new SQLException("Can't serialize binary object: " + e);
}
finally
{
safeClose(oos);
safeClose(baos);
}
}
public static Object convertToObject(byte[] input)
throws SQLException
{
ByteArrayInputStream bais = new ByteArrayInputStream(input);
try
{
return convertToObject(bais);
}
finally
{
safeClose(bais);
}
}
public static Object convertToObject(InputStream input)
throws SQLException
{
Object value = null;
if(input != null)
{
ObjectInputStream ois = null;
try
{
ois = new ObjectInputStream(input);
value = ois.readObject();
if(value instanceof MarshalledValue)
{
value = ((MarshalledValue)value).get();
}
else if(value instanceof MarshalledObject)
{
value = ((MarshalledObject)value).get();
}
if(value instanceof Handle)
{
value = ((Handle)value).getEJBObject();
}
}
catch(RemoteException e)
{
throw new SQLException("Unable to load EJBObject back from Handle: " + e);
}
catch(IOException e)
{
throw new SQLException("Unable to load to deserialize result: " + e);
}
catch(ClassNotFoundException e)
{
throw new SQLException("Unable to load to deserialize result: " + e);
}
finally
{
safeClose(ois);
}
}
return value;
}
public static String getLongString(ResultSet rs, int index)
throws SQLException
{
String value;
Reader textData = rs.getCharacterStream(index);
if(textData != null)
{
try
{
StringBuffer textBuffer = new StringBuffer();
char[] tmpBuffer = new char[1000];
int charsRead;
while((charsRead = textData.read(tmpBuffer)) != -1)
textBuffer.append(tmpBuffer, 0, charsRead);
value = textBuffer.toString();
}
catch(java.io.IOException ioException)
{
throw new SQLException(ioException.getMessage());
}
finally
{
safeClose(textData);
}
}
else
value = null;
return value;
}
public static byte[] getByteArray(InputStream input)
throws SQLException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
{
byte[] tmpBuffer = new byte[1000];
int bytesRead;
while((bytesRead = input.read(tmpBuffer)) != -1)
baos.write(tmpBuffer, 0, bytesRead);
return baos.toByteArray();
}
catch(java.io.IOException ioException)
{
throw new SQLException(ioException.getMessage());
}
finally
{
safeClose(baos);
}
}
public static JDBCResultSetReader getResultSetReader(int jdbcType, Class destination)
{
JDBCResultSetReader reader;
switch(jdbcType)
{
case Types.CLOB:
reader = JDBCResultSetReader.CLOB_READER;
break;
case Types.LONGVARCHAR:
reader = JDBCResultSetReader.LONGVARCHAR_READER;
break;
case Types.BINARY:
reader = JDBCResultSetReader.BINARY_READER;
break;
case Types.VARBINARY:
reader = JDBCResultSetReader.VARBINARY_READER;
break;
case Types.BLOB:
reader = JDBCResultSetReader.BLOB_READER;
break;
case Types.LONGVARBINARY:
reader = JDBCResultSetReader.LONGVARBINARY_READER;
break;
case Types.JAVA_OBJECT:
reader = JDBCResultSetReader.JAVA_OBJECT_READER;
break;
case Types.STRUCT:
reader = JDBCResultSetReader.STRUCT_READER;
break;
case Types.ARRAY:
reader = JDBCResultSetReader.ARRAY_READER;
break;
case Types.OTHER:
reader = JDBCResultSetReader.OTHER_READER;
break;
default:
{
reader = getResultReaderByType(destination);
}
}
return reader;
}
public static JDBCResultSetReader getResultReaderByType(Class destination)
{
JDBCResultSetReader reader;
if(destination == java.util.Date.class)
{
reader = JDBCResultSetReader.JAVA_UTIL_DATE_READER;
}
else if(destination == java.sql.Date.class)
{
reader = JDBCResultSetReader.JAVA_SQL_DATE_READER;
}
else if(destination == java.sql.Time.class)
{
reader = JDBCResultSetReader.JAVA_SQL_TIME_READER;
}
else if(destination == java.sql.Timestamp.class)
{
reader = JDBCResultSetReader.JAVA_SQL_TIMESTAMP_READER;
}
else if(destination == BigDecimal.class)
{
reader = JDBCResultSetReader.BIGDECIMAL_READER;
}
else if(destination == java.sql.Ref.class)
{
reader = JDBCResultSetReader.REF_READER;
}
else if(destination == String.class)
{
reader = JDBCResultSetReader.STRING_READER;
}
else if(destination == Boolean.class || destination == Boolean.TYPE)
{
reader = JDBCResultSetReader.BOOLEAN_READER;
}
else if(destination == Byte.class || destination == Byte.TYPE)
{
reader = JDBCResultSetReader.BYTE_READER;
}
else if(destination == Character.class || destination == Character.TYPE)
{
reader = JDBCResultSetReader.CHARACTER_READER;
}
else if(destination == Short.class || destination == Short.TYPE)
{
reader = JDBCResultSetReader.SHORT_READER;
}
else if(destination == Integer.class || destination == Integer.TYPE)
{
reader = JDBCResultSetReader.INT_READER;
}
else if(destination == Long.class || destination == Long.TYPE)
{
reader = JDBCResultSetReader.LONG_READER;
}
else if(destination == Float.class || destination == Float.TYPE)
{
reader = JDBCResultSetReader.FLOAT_READER;
}
else if(destination == Double.class || destination == Double.TYPE)
{
reader = JDBCResultSetReader.DOUBLE_READER;
}
else
{
reader = JDBCResultSetReader.OBJECT_READER;
}
return reader;
}
public static JDBCParameterSetter getParameterSetter(int jdbcType, Class javaType)
{
JDBCParameterSetter ps;
switch(jdbcType)
{
case Types.CLOB:
case Types.LONGVARCHAR:
ps = JDBCParameterSetter.CLOB;
break;
case Types.BINARY:
case Types.VARBINARY:
ps = JDBCParameterSetter.BINARY;
break;
case Types.BLOB:
case Types.LONGVARBINARY:
ps = JDBCParameterSetter.BLOB;
break;
case Types.DECIMAL:
case Types.NUMERIC:
ps = JDBCParameterSetter.NUMERIC;
break;
case Types.JAVA_OBJECT:
case Types.OTHER:
case Types.STRUCT:
default:
ps = JDBCParameterSetter.OBJECT;
break;
}
return ps;
}
private static final Map jdbcTypeNames;
private final static Map csTypes;
public static String getJDBCTypeName(int jdbcType)
{
return (String)jdbcTypeNames.get(new Integer(jdbcType));
}
private static final String SQL_ERROR = "SQL error";
private static final String GET_TIMESTAMP = "getTimestamp";
private static final String GET_DATE = "getDate";
private static final String GET_TIME = "getTime";
private static final String GET_BIGDECIMAL = "getBigDecimal";
private static final String GET_REF = "getRef";
private static final String GET_STRING = "getString";
private static final String GET_BOOLEAN = "getBoolean";
private static final String GET_BYTE = "getByte";
private static final String GET_SHORT = "getShort";
private static final String GET_INT = "getInt";
private static final String GET_LONG = "getLong";
private static final String GET_FLOAT = "getFloat";
private static final String GET_DOUBLE = "getDouble";
private static final String GET_BYTES = "getBytes";
static
{
Class[] arg = new Class[]{Integer.TYPE};
csTypes = new HashMap();
try
{
csTypes.put(java.util.Date.class.getName(),
CallableStatement.class.getMethod(GET_TIMESTAMP, arg));
csTypes.put(java.sql.Date.class.getName(),
CallableStatement.class.getMethod(GET_DATE, arg));
csTypes.put(java.sql.Time.class.getName(),
CallableStatement.class.getMethod(GET_TIME, arg));
csTypes.put(java.sql.Timestamp.class.getName(),
CallableStatement.class.getMethod(GET_TIMESTAMP, arg));
csTypes.put(java.math.BigDecimal.class.getName(),
CallableStatement.class.getMethod(GET_BIGDECIMAL, arg));
csTypes.put(java.sql.Ref.class.getName(),
CallableStatement.class.getMethod(GET_REF, arg));
csTypes.put(java.lang.String.class.getName(),
CallableStatement.class.getMethod(GET_STRING, arg));
csTypes.put(java.lang.Boolean.class.getName(),
CallableStatement.class.getMethod(GET_BOOLEAN, arg));
csTypes.put(Boolean.TYPE.getName(),
CallableStatement.class.getMethod(GET_BOOLEAN, arg));
csTypes.put(java.lang.Byte.class.getName(),
CallableStatement.class.getMethod(GET_BYTE, arg));
csTypes.put(Byte.TYPE.getName(),
CallableStatement.class.getMethod(GET_BYTE, arg));
csTypes.put(java.lang.Character.class.getName(),
CallableStatement.class.getMethod(GET_STRING, arg));
csTypes.put(Character.TYPE.getName(),
CallableStatement.class.getMethod(GET_STRING, arg));
csTypes.put(java.lang.Short.class.getName(),
CallableStatement.class.getMethod(GET_SHORT, arg));
csTypes.put(Short.TYPE.getName(),
CallableStatement.class.getMethod(GET_SHORT, arg));
csTypes.put(java.lang.Integer.class.getName(),
CallableStatement.class.getMethod(GET_INT, arg));
csTypes.put(Integer.TYPE.getName(),
CallableStatement.class.getMethod(GET_INT, arg));
csTypes.put(java.lang.Long.class.getName(),
CallableStatement.class.getMethod(GET_LONG, arg));
csTypes.put(Long.TYPE.getName(),
CallableStatement.class.getMethod(GET_LONG, arg));
csTypes.put(java.lang.Float.class.getName(),
CallableStatement.class.getMethod(GET_FLOAT, arg));
csTypes.put(Float.TYPE.getName(),
CallableStatement.class.getMethod(GET_FLOAT, arg));
csTypes.put(java.lang.Double.class.getName(),
CallableStatement.class.getMethod(GET_DOUBLE, arg));
csTypes.put(Double.TYPE.getName(),
CallableStatement.class.getMethod(GET_DOUBLE, arg));
csTypes.put("[B",
CallableStatement.class.getMethod(GET_BYTES, arg));
}
catch(NoSuchMethodException e)
{
log.error(SQL_ERROR, e);
}
jdbcTypeNames = new HashMap();
Field[] fields = Types.class.getFields();
for(int i = 0; i < fields.length; i++)
{
try
{
jdbcTypeNames.put(fields[i].get(null), fields[i].getName());
}
catch(IllegalAccessException e)
{
log.error(SQL_ERROR, e);
}
}
}
public static Object getParameter(Logger log, CallableStatement cs, int index, int jdbcType, Class destination) throws SQLException
{
Object value = null;
switch(jdbcType)
{
case Types.CLOB:
case Types.LONGVARCHAR:
case Types.BLOB:
case Types.LONGVARBINARY:
throw new UnsupportedOperationException();
case Types.BINARY:
case Types.VARBINARY:
{
byte[] bytes = cs.getBytes(index);
if(!cs.wasNull())
{
if(destination == byte[].class)
value = bytes;
else
value = convertToObject(bytes);
}
if(log.isTraceEnabled())
{
log.trace("Get result: index=" + index +
", javaType=" + destination.getName() +
", Binary, value=" + value);
}
}
break;
case Types.JAVA_OBJECT:
case Types.STRUCT:
case Types.ARRAY:
case Types.OTHER:
{
value = cs.getObject(index);
if(log.isTraceEnabled())
{
log.trace("Get result: index=" + index +
", javaType=" + destination.getName() +
", Object, value=" + value);
}
}
break;
default:
Method method = (Method)csTypes.get(destination.getName());
if(method != null)
{
try
{
value = method.invoke(cs, new Object[]{new Integer(index)});
if(cs.wasNull())
{
value = null;
}
if(log.isTraceEnabled())
{
log.trace("Get result: index=" + index +
", javaType=" + destination.getName() +
", Simple, value=" + value);
}
}
catch(IllegalAccessException e)
{
}
catch(InvocationTargetException e)
{
}
}
else
{
value = cs.getObject(index);
if(log.isTraceEnabled())
{
log.trace("Get result: index=" + index +
", javaType=" + destination.getName() +
", Object, value=" + value);
}
}
}
return coerceToJavaType(value, destination);
}
private static Object coerceToJavaType(
Object value,
Class destination) throws SQLException
{
try
{
if(value == null)
{
return null;
}
if(value instanceof MarshalledObject && !destination.equals(MarshalledObject.class))
{
value = ((MarshalledObject)value).get();
}
if(value instanceof Handle)
{
value = ((Handle)value).getEJBObject();
}
if(destination.isPrimitive())
{
if(value == null)
throw new IllegalStateException("Loaded NULL value for a field of a primitive type.");
if((destination.equals(Byte.TYPE) && value instanceof Byte) ||
(destination.equals(Short.TYPE) && value instanceof Short) ||
(destination.equals(Character.TYPE) && value instanceof Character) ||
(destination.equals(Boolean.TYPE) && value instanceof Boolean) ||
(destination.equals(Integer.TYPE) && value instanceof Integer) ||
(destination.equals(Long.TYPE) && value instanceof Long) ||
(destination.equals(Float.TYPE) && value instanceof Float) ||
(destination.equals(Double.TYPE) && value instanceof Double)
)
{
return value;
}
}
if(destination == java.util.Date.class && value instanceof java.util.Date)
{
if(value instanceof java.sql.Timestamp)
{
java.sql.Timestamp ts = (java.sql.Timestamp)value;
long temp = ts.getTime();
if(temp % 1000 == 0)
temp += ts.getNanos() / 1000000;
return new java.util.Date(temp);
}
else
{
return new java.util.Date(((java.util.Date)value).getTime());
}
}
if(destination == java.sql.Time.class && value instanceof java.sql.Time)
{
return new java.sql.Time(((java.sql.Time)value).getTime());
}
if(destination == java.sql.Date.class && value instanceof java.sql.Date)
{
return new java.sql.Date(((java.sql.Date)value).getTime());
}
if(destination == java.sql.Timestamp.class && value instanceof java.sql.Timestamp)
{
java.sql.Timestamp orignal = (java.sql.Timestamp)value;
java.sql.Timestamp copy = new java.sql.Timestamp(orignal.getTime());
copy.setNanos(orignal.getNanos());
return copy;
}
if(value instanceof String && (destination == Character.class || destination == Character.TYPE))
{
return new Character(((String)value).charAt(0));
}
if(destination.isAssignableFrom(value.getClass()))
{
return value;
}
if(destination == java.math.BigInteger.class && value.getClass() == java.math.BigDecimal.class)
{
return ((java.math.BigDecimal)value).toBigInteger();
}
throw new SQLException("Got a " + value.getClass().getName() + "[cl=" +
System.identityHashCode(value.getClass().getClassLoader()) +
", value=" + value + "] while looking for a " +
destination.getName() + "[cl=" +
System.identityHashCode(destination) + "]");
}
catch(RemoteException e)
{
throw new SQLException("Unable to load EJBObject back from Handle: "
+ e);
}
catch(IOException e)
{
throw new SQLException("Unable to load to deserialize result: " + e);
}
catch(ClassNotFoundException e)
{
throw new SQLException("Unable to load to deserialize result: " + e);
}
}
}