blob: 94959bd6917dc282f028279b029c868f8bbaa7a7 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.cocoon.util;
import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Reader;
import java.math.BigDecimal;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Time;
import java.sql.Timestamp;
import java.sql.Types;
import java.util.Calendar;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.avalon.framework.configuration.Configuration;
import org.apache.cocoon.servlet.multipart.Part;
import org.apache.commons.lang.BooleanUtils;
import org.apache.excalibur.source.Source;
/**
* Provide some utility methods to read from JDBC result sets or store
* them to JDBC statements. Largely copied from
* org.apache.cocoon.acting.AbstractDatabaseAction.
*
* <p>The following table lists all available column type names
* together with the JDBC methods used to get or set a column with
* that type. In some cases the returned type differs from the type
* returned by the getXXX method. To set a column, a number of
* conversions are automatically used. For details, please see the
* actual code.</p>
*
* <p><table border="1">
* <tr><th>type </th><th>getXXX </th><th>returns </th><th>setXXX </th></tr>
* <tr><td>clob </td><td>Clob </td><td>String </td><td>Clob </td></tr>
* <tr><td>ascii </td><td>Clob </td><td>String </td><td>asciStream </td></tr>
* <tr><td>big-decimal</td><td>BigDecimal </td><td> </td><td>BigDecimal </td></tr>
* <tr><td>binary </td><td> </td><td> </td><td>BinaryStream </td></tr>
* <tr><td>blob </td><td> </td><td> </td><td>Blob </td></tr>
* <tr><td>boolean </td><td>Boolean </td><td>Boolean </td><td>Boolean </td></tr>
* <tr><td>byte </td><td>Byte </td><td>Byte </td><td>Byte </td></tr>
* <tr><td>string </td><td>String </td><td> </td><td>String </td></tr>
* <tr><td>date </td><td>Date </td><td> </td><td>Date </td></tr>
* <tr><td>double </td><td>Double </td><td>Double </td><td>Double </td></tr>
* <tr><td>float </td><td>Float </td><td>Float </td><td>Float </td></tr>
* <tr><td>int </td><td>Int </td><td>Integer </td><td>Int </td></tr>
* <tr><td>long </td><td>Long </td><td>Long </td><td>Long </td></tr>
* <tr><td>short </td><td>Short </td><td> </td><td>Short </td></tr>
* <tr><td>time </td><td>Time </td><td> </td><td>Time </td></tr>
* <tr><td>time-stamp </td><td>Timestamp </td><td> </td><td>Timestamp </td></tr>
* <tr><td>array </td><td>Array </td><td> </td><td>Array </td></tr>
* <tr><td>row </td><td>Object </td><td>Struct </td><td>Object </td></tr>
* <tr><td>object </td><td>Object </td><td> </td><td>Object </td></tr>
* </table></p>
*
* @version CVS $Id$
*/
public class JDBCTypeConversions {
public static final Map typeConstants;
static {
/** Initialize the map of type names to jdbc column types.
Note that INTEGER, BLOB, and VARCHAR column types map to more than
one type name. **/
Map constants = new HashMap();
constants.put("clob", new Integer(Types.CLOB));
constants.put("ascii", new Integer(Types.CHAR));
constants.put("big-decimal", new Integer(Types.BIGINT));
constants.put("binary", new Integer(Types.VARBINARY));
constants.put("blob", new Integer(Types.BLOB));
constants.put("boolean", new Integer(Types.BIT));
constants.put("byte", new Integer(Types.TINYINT));
constants.put("string", new Integer(Types.VARCHAR));
constants.put("date", new Integer(Types.DATE));
constants.put("double", new Integer(Types.DOUBLE));
constants.put("float", new Integer(Types.FLOAT));
constants.put("int", new Integer(Types.INTEGER));
constants.put("long", new Integer(Types.NUMERIC));
constants.put("short", new Integer(Types.SMALLINT));
constants.put("time", new Integer(Types.TIME));
constants.put("time-stamp", new Integer(Types.TIMESTAMP));
constants.put("array", new Integer(Types.ARRAY));
constants.put("row", new Integer(Types.STRUCT));
constants.put("object", new Integer(Types.OTHER));
typeConstants = Collections.unmodifiableMap(constants);
}
/**
* Converts an object to a JDBC type. This has just been started
* and does not do much at the moment.
*
*/
public static Object convert(Object value, String jType) {
Object object=null;
if (jType.equalsIgnoreCase("string")) {
if (value instanceof String) {
object = value;
} else {
object = value.toString();
}
} else if (jType.equalsIgnoreCase("int")) {
if (value instanceof String) {
object = Integer.decode((String)value);
} else if (value instanceof Integer) {
object = value;
} else {
//
}
} else if (jType.equalsIgnoreCase("long")) {
if (value instanceof String) {
object = Long.decode((String)value);
} else if (value instanceof Long) {
object = value;
} else {
//
}
} else {
// other types need parsing & creation
//
}
return object;
}
/**
* Get the Statement column so that the results are mapped correctly.
* (this has been copied from AbstractDatabaseAction and modified slightly)
*/
public static Object getColumn(ResultSet set, Configuration column)
throws Exception {
Integer type = (Integer) JDBCTypeConversions.typeConstants.get(column.getAttribute("type"));
String dbcol = column.getAttribute("name");
Object value;
switch (type.intValue()) {
case Types.CLOB:
case Types.CHAR:
Clob dbClob = set.getClob(dbcol);
if (dbClob != null) {
int length = (int) dbClob.length();
char[] buffer = new char[length];
Reader r = dbClob.getCharacterStream();
try {
length = r.read(buffer);
value = new String(buffer, 0, length);
} finally {
r.close();
}
} else {
value = null;
}
break;
case Types.BIGINT:
value = set.getBigDecimal(dbcol);
break;
case Types.TINYINT:
value = new Byte(set.getByte(dbcol));
break;
case Types.VARCHAR:
value = set.getString(dbcol);
break;
case Types.DATE:
value = set.getDate(dbcol);
break;
case Types.DOUBLE:
value = new Double(set.getDouble(dbcol));
break;
case Types.FLOAT:
value = new Float(set.getFloat(dbcol));
break;
case Types.INTEGER:
value = new Integer(set.getInt(dbcol));
break;
case Types.NUMERIC:
value = new Long(set.getLong(dbcol));
break;
case Types.SMALLINT:
value = new Short(set.getShort(dbcol));
break;
case Types.TIME:
value = set.getTime(dbcol);
break;
case Types.TIMESTAMP:
value = set.getTimestamp(dbcol);
break;
case Types.ARRAY:
value = set.getArray(dbcol); // new Integer(set.getInt(dbcol));
break;
case Types.BIT:
value = BooleanUtils.toBooleanObject(set.getBoolean(dbcol));
break;
case Types.STRUCT:
value = set.getObject(dbcol);
break;
case Types.OTHER:
value = set.getObject(dbcol);
break;
default:
// The blob types have to be requested separately, via a Reader.
value = "";
break;
}
return value;
}
/**
* Set the Statement column so that the results are mapped correctly.
*
* @param statement the prepared statement
* @param position the position of the column
* @param value the value of the column
*/
public static void setColumn(PreparedStatement statement, int position, Object value, Integer typeObject) throws Exception {
if (value instanceof String) {
value = ((String) value).trim();
}
if (typeObject == null) {
throw new SQLException("Can't set column because the type is unrecognized");
}
if (value == null) {
/** If the value is null, set the column value null and return **/
statement.setNull(position, typeObject.intValue());
return;
}
if ("".equals(value)) {
switch (typeObject.intValue()) {
case Types.CHAR:
case Types.CLOB:
case Types.VARCHAR:
/** If the value is an empty string and the column is
a string type, we can continue **/
break;
default:
/** If the value is an empty string and the column
is something else, we treat it as a null value **/
statement.setNull(position, typeObject.intValue());
return;
}
}
File file;
int length;
InputStream asciiStream;
//System.out.println("========================================================================");
//System.out.println("JDBCTypeConversions: setting type "+typeObject.intValue());
switch (typeObject.intValue()) {
case Types.CLOB:
//System.out.println("CLOB");
Clob clob;
if (value instanceof Clob) {
clob = (Clob) value;
} else if (value instanceof File) {
File asciiFile = (File) value;
asciiStream = new BufferedInputStream(new FileInputStream(asciiFile));
length = (int) asciiFile.length();
clob = new ClobHelper(asciiStream, length);
} else if (value instanceof Part) {
Part anyFile = (Part) value;
asciiStream = new BufferedInputStream(anyFile.getInputStream());
length = anyFile.getSize();
clob = new ClobHelper(asciiStream, length);
} else if (value instanceof JDBCxlobHelper) {
asciiStream = ((JDBCxlobHelper) value).inputStream;
length = ((JDBCxlobHelper) value).length;
clob = new ClobHelper(asciiStream, length);
} else if (value instanceof Source) {
asciiStream = ((Source) value).getInputStream();
length = (int)((Source) value).getContentLength();
clob = new ClobHelper(asciiStream, length);
} else {
String asciiText = value.toString();
asciiStream = new ByteArrayInputStream(asciiText.getBytes());
length = asciiText.length();
clob = new ClobHelper(asciiStream, length);
}
statement.setClob(position, clob);
break;
case Types.CHAR:
// simple large object, e.g. Informix's TEXT
//System.out.println("CHAR");
if (value instanceof File) {
File asciiFile = (File) value;
asciiStream = new BufferedInputStream(new FileInputStream(asciiFile));
length = (int) asciiFile.length();
} else if (value instanceof JDBCxlobHelper) {
asciiStream = ((JDBCxlobHelper) value).inputStream;
length = ((JDBCxlobHelper) value).length;
} else if (value instanceof Source) {
asciiStream = ((Source) value).getInputStream();
length = (int)((Source) value).getContentLength();
} else if (value instanceof Part) {
Part anyFile = (Part) value;
asciiStream = new BufferedInputStream(anyFile.getInputStream());
length = anyFile.getSize();
clob = new ClobHelper(asciiStream, length);
} else {
String asciiText = value.toString();
asciiStream = new BufferedInputStream(new ByteArrayInputStream(asciiText.getBytes()));
length = asciiText.length();
}
statement.setAsciiStream(position, asciiStream, length);
break;
case Types.BIGINT:
//System.out.println("BIGINT");
BigDecimal bd;
if (value instanceof BigDecimal) {
bd = (BigDecimal) value;
} else if (value instanceof Number) {
bd = BigDecimal.valueOf(((Number)value).longValue());
} else {
bd = new BigDecimal(value.toString());
}
statement.setBigDecimal(position, bd);
break;
case Types.TINYINT:
//System.out.println("TINYINT");
Byte b;
if (value instanceof Byte) {
b = (Byte) value;
} else if (value instanceof Number) {
b = new Byte(((Number) value).byteValue());
} else {
b = new Byte(value.toString());
}
statement.setByte(position, b.byteValue());
break;
case Types.DATE:
//System.out.println("DATE");
Date d;
if (value instanceof Date) {
d = (Date) value;
} else if (value instanceof java.util.Date) {
d = new Date(((java.util.Date) value).getTime());
} else if (value instanceof Calendar) {
d = new Date(((Calendar) value).getTime().getTime());
} else {
d = Date.valueOf(value.toString());
}
statement.setDate(position, d);
break;
case Types.DOUBLE:
//System.out.println("DOUBLE");
double db;
if (value instanceof Number) {
db = (((Number) value).doubleValue());
} else {
db = Double.parseDouble(value.toString());
}
statement.setDouble(position, db);
break;
case Types.FLOAT:
//System.out.println("FLOAT");
float f;
if (value instanceof Number) {
f = (((Number) value).floatValue());
} else {
f = Float.parseFloat(value.toString());
}
statement.setFloat(position, f);
break;
case Types.NUMERIC:
//System.out.println("NUMERIC");
long l;
if (value instanceof Number) {
l = (((Number) value).longValue());
} else {
l = Long.parseLong(value.toString());
}
statement.setLong(position, l);
break;
case Types.SMALLINT:
//System.out.println("SMALLINT");
Short s;
if (value instanceof Short) {
s = (Short) value;
} else if (value instanceof Number) {
s = new Short(((Number) value).shortValue());
} else {
s = new Short(value.toString());
}
statement.setShort(position, s.shortValue());
break;
case Types.TIME:
//System.out.println("TIME");
Time t;
if (value instanceof Time) {
t = (Time) value;
} else if (value instanceof java.util.Date){
t = new Time(((java.util.Date) value).getTime());
} else {
t = Time.valueOf(value.toString());
}
statement.setTime(position, t);
break;
case Types.TIMESTAMP:
//System.out.println("TIMESTAMP");
Timestamp ts;
if (value instanceof Time) {
ts = (Timestamp) value;
} else if (value instanceof java.util.Date) {
ts = new Timestamp(((java.util.Date) value).getTime());
} else {
ts = Timestamp.valueOf(value.toString());
}
statement.setTimestamp(position, ts);
break;
case Types.ARRAY:
//System.out.println("ARRAY");
statement.setArray(position, (Array) value); // no way to convert string to array
break;
case Types.STRUCT:
//System.out.println("STRUCT");
case Types.OTHER:
//System.out.println("OTHER");
statement.setObject(position, value);
break;
case Types.LONGVARBINARY:
//System.out.println("LONGVARBINARY");
statement.setTimestamp(position, new Timestamp((new java.util.Date()).getTime()));
break;
case Types.VARCHAR:
//System.out.println("VARCHAR");
statement.setString(position, value.toString());
break;
case Types.BLOB:
//System.out.println("BLOB");
if (value instanceof JDBCxlobHelper) {
statement.setBinaryStream(position, ((JDBCxlobHelper)value).inputStream, ((JDBCxlobHelper)value).length);
} else if (value instanceof Source){
statement.setBinaryStream(position, ((Source)value).getInputStream(), (int)((Source)value).getContentLength());
} else {
Blob blob;
if (value instanceof Blob) {
blob = (Blob) value;
} else if( value instanceof File) {
file = (File)value;
blob = new BlobHelper(new FileInputStream(file), (int) file.length());
} else if (value instanceof String) {
file = new File((String)value);
blob = new BlobHelper(new FileInputStream(file), (int) file.length());
} else if (value instanceof Part) {
Part anyFile = (Part) value;
blob = new BlobHelper(new BufferedInputStream(anyFile.getInputStream()), anyFile.getSize());
} else {
throw new SQLException("Invalid type for blob: "+value.getClass().getName());
}
//InputStream input = new BufferedInputStream(new FileInputStream(file));
statement.setBlob(position, blob);
}
break;
case Types.VARBINARY:
//System.out.println("VARBINARY");
if (value instanceof JDBCxlobHelper) {
statement.setBinaryStream(position, ((JDBCxlobHelper)value).inputStream, ((JDBCxlobHelper)value).length);
} else if (value instanceof Source){
statement.setBinaryStream(position, ((Source)value).getInputStream(), (int)((Source)value).getContentLength());
} else if (value instanceof Part) {
statement.setBinaryStream(position, ((Part)value).getInputStream(), ((Part)value).getSize());
} else {
if (value instanceof File) {
file = (File)value;
} else if (value instanceof String) {
file = new File((String)value);
} else {
throw new SQLException("Invalid type for blob: "+value.getClass().getName());
}
//InputStream input = new BufferedInputStream(new FileInputStream(file));
FileInputStream input = new FileInputStream(file);
statement.setBinaryStream(position, input, (int)file.length());
}
break;
case Types.INTEGER:
//System.out.println("INTEGER");
Integer i;
if (value instanceof Integer) {
i = (Integer) value;
} else if (value instanceof Number) {
i = new Integer(((Number) value).intValue());
} else {
i = new Integer(value.toString());
}
statement.setInt(position, i.intValue());
break;
case Types.BIT:
//System.out.println("BIT");
Boolean bo;
if (value instanceof Boolean) {
bo = (Boolean)value;
} else if (value instanceof Number) {
bo = BooleanUtils.toBooleanObject(((Number) value).intValue()==1);
} else {
bo = BooleanUtils.toBooleanObject(value.toString());
}
statement.setBoolean(position, bo.booleanValue());
break;
default:
//System.out.println("default");
throw new SQLException("Impossible exception - invalid type ");
}
//System.out.println("========================================================================");
}
}