/* * 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("========================================================================"); } }