/*
* Copyright 2004-2015 the Seasar Foundation and the Others.
*
* Licensed 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.seasar.extension.jdbc.types;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.seasar.extension.jdbc.ValueType;
import org.seasar.extension.jdbc.util.BindVariableUtil;
import org.seasar.framework.exception.SSQLException;
import org.seasar.framework.util.InputStreamUtil;
/**
* <code>byte[]</code>用の {@link ValueType}です。
*
* @author koichik
*/
public class BytesType extends AbstractValueType {
/** 空のバイト配列 */
public static final byte[] EMPTY_BYTES = new byte[0];
/** バイト配列を<code>getBytes()/setBytes()</code>で扱うトレイト */
public static final Trait BYTES_TRAIT = new BytesTrait();
/** バイト配列を<code>getBinaryStream()/setBinaryStream()</code>で扱うトレイト */
public static final Trait STREAM_TRAIT = new StreamTrait();
/** バイト配列を<code>getBlob()/setBytes()</code>で扱うトレイト */
public static final Trait BLOB_TRAIT = new BlobTrait();
/**
* バイト配列を操作するためのトレイトです。
*/
protected Trait trait;
/**
* インスタンスを構築します。
*
* @param trait
* トレイト
*/
public BytesType(final Trait trait) {
super(trait.getSqlType());
this.trait = trait;
}
public void bindValue(final PreparedStatement ps, final int index,
final Object value) throws SQLException {
if (value == null) {
setNull(ps, index);
} else if (value instanceof byte[]) {
trait.set(ps, index, (byte[]) value);
} else {
ps.setObject(index, value);
}
}
public void bindValue(final CallableStatement cs,
final String parameterName, final Object value) throws SQLException {
if (value == null) {
setNull(cs, parameterName);
} else if (value instanceof byte[]) {
trait.set(cs, parameterName, (byte[]) value);
} else {
cs.setObject(parameterName, value);
}
}
public Object getValue(final ResultSet resultSet, final int index)
throws SQLException {
return trait.get(resultSet, index);
}
public Object getValue(final ResultSet resultSet, final String columnName)
throws SQLException {
return trait.get(resultSet, columnName);
}
public Object getValue(final CallableStatement cs, final int index)
throws SQLException {
return trait.get(cs, index);
}
public Object getValue(final CallableStatement cs,
final String parameterName) throws SQLException {
return trait.get(cs, parameterName);
}
public String toText(Object value) {
if (value == null) {
return BindVariableUtil.nullText();
} else if (value instanceof byte[]) {
return BindVariableUtil.toText((byte[]) value);
}
return BindVariableUtil.toText(value);
}
/**
* {@link InputStream}からバイト配列を取得して返します。
*
* @param is
* 入力ストリーム
* @return バイト配列
* @throws SQLException
* SQL例外が発生した場合
*/
public static byte[] toBytes(final InputStream is) throws SQLException {
try {
final byte[] bytes = new byte[is.available()];
is.read(bytes);
return bytes;
} catch (final IOException e) {
throw new SSQLException("ESSR0040", new Object[] { e.getMessage() });
}
}
/**
* {@link Blob}からバイト配列を取得して返します。
*
* @param blob
* BLOB
* @return バイト配列
* @throws SQLException
* SQL例外が発生した場合
* @throws ArrayIndexOutOfBoundsException
* BLOBのデータ長が<code>int</code>型の最大長を越えている場合
*/
public static byte[] toBytes(final Blob blob) throws SQLException {
if (blob == null) {
return null;
}
final long length = blob.length();
if (length == 0) {
return EMPTY_BYTES;
}
if (length > Integer.MAX_VALUE) {
throw new ArrayIndexOutOfBoundsException();
}
return blob.getBytes(1L, (int) length);
}
/**
*
* @author koichik
*/
public interface Trait {
/**
* JDBC型を返します。
*
* @return JDBC型
*/
int getSqlType();
/**
* {@link PreparedStatement}にバイト配列をパラメータとして設定します。
*
* @param ps
* 準備されたステートメント
* @param parameterIndex
* パラメータのインデックス
* @param bytes
* パラメータ値のバイト配列
* @throws SQLException
* SQL例外が発生した場合
*/
void set(PreparedStatement ps, int parameterIndex, byte[] bytes)
throws SQLException;
/**
* {@link CallableStatement}にバイト配列を名前パラメータとして設定します。
*
* @param cs
* 呼び出し可能なステートメント
* @param parameterName
* パラメータ名
* @param bytes
* パラメータ値のバイト配列
* @throws SQLException
* SQL例外が発生した場合
*/
void set(CallableStatement cs, String parameterName, byte[] bytes)
throws SQLException;
/**
* {@link ResultSet}からバイト配列を取得します。
*
* @param rs
* 結果セット
* @param columnIndex
* カラムのインデックス
* @return バイト配列
* @throws SQLException
* SQL例外が発生した場合
*/
byte[] get(ResultSet rs, int columnIndex) throws SQLException;
/**
* {@link ResultSet}からバイト配列を取得します。
*
* @param rs
* 結果セット
* @param columnName
* カラムの名前
* @return バイト配列
* @throws SQLException
* SQL例外が発生した場合
*/
byte[] get(ResultSet rs, String columnName) throws SQLException;
/**
* {@link CallableStatement}からバイト配列を取得します。
*
* @param cs
* 呼び出し可能なステートメント
* @param columnIndex
* カラムのインデックス
* @return バイト配列
* @throws SQLException
* SQL例外が発生した場合
*/
byte[] get(CallableStatement cs, int columnIndex) throws SQLException;
/**
* {@link CallableStatement}からバイト配列を取得します。
*
* @param cs
* 呼び出し可能なステートメント
* @param columnName
* カラムの名前
* @return バイト配列
* @throws SQLException
* SQL例外が発生した場合
*/
byte[] get(CallableStatement cs, String columnName) throws SQLException;
}
/**
* バイト配列を<code>getBytes()/setBytes()</code>で扱うトレイトです。
*
* @author koichik
*/
public static class BytesTrait implements Trait {
public int getSqlType() {
return Types.BINARY;
}
public void set(final PreparedStatement ps, final int parameterIndex,
final byte[] bytes) throws SQLException {
ps.setBytes(parameterIndex, bytes);
}
public void set(final CallableStatement cs, final String parameterName,
final byte[] bytes) throws SQLException {
cs.setBytes(parameterName, bytes);
}
public byte[] get(final ResultSet rs, final int columnIndex)
throws SQLException {
return rs.getBytes(columnIndex);
}
public byte[] get(final ResultSet rs, final String columnName)
throws SQLException {
return rs.getBytes(columnName);
}
public byte[] get(final CallableStatement cs, final int columnIndex)
throws SQLException {
return cs.getBytes(columnIndex);
}
public byte[] get(final CallableStatement cs, final String columnName)
throws SQLException {
return cs.getBytes(columnName);
}
}
/**
* バイト配列を<code>getBinaryStream()/setBinaryStream()</code>で扱うトレイトです。
*
* @author koichik
*/
public static class StreamTrait implements Trait {
public int getSqlType() {
return Types.BINARY;
}
public void set(final PreparedStatement ps, final int parameterIndex,
final byte[] bytes) throws SQLException {
ps.setBinaryStream(parameterIndex, new ByteArrayInputStream(bytes),
bytes.length);
}
public void set(final CallableStatement cs, final String parameterName,
final byte[] bytes) throws SQLException {
cs.setBinaryStream(parameterName, new ByteArrayInputStream(bytes),
bytes.length);
}
public byte[] get(final ResultSet rs, final int columnIndex)
throws SQLException {
final InputStream is = rs.getBinaryStream(columnIndex);
try {
return toBytes(is);
} finally {
InputStreamUtil.close(is);
}
}
public byte[] get(final ResultSet rs, final String columnName)
throws SQLException {
final InputStream is = rs.getBinaryStream(columnName);
try {
return toBytes(is);
} finally {
InputStreamUtil.close(is);
}
}
public byte[] get(final CallableStatement cs, final int columnIndex)
throws SQLException {
return cs.getBytes(columnIndex);
}
public byte[] get(final CallableStatement cs, final String columnName)
throws SQLException {
return cs.getBytes(columnName);
}
}
/**
* バイト配列を<code>getBlob()/setBinaryStream()</code>で扱うトレイトです。
*
* @author koichik
*/
public static class BlobTrait implements Trait {
public int getSqlType() {
return Types.BLOB;
}
public void set(final PreparedStatement ps, final int parameterIndex,
final byte[] bytes) throws SQLException {
ps.setBinaryStream(parameterIndex, new ByteArrayInputStream(bytes),
bytes.length);
}
public void set(final CallableStatement cs, final String parameterName,
final byte[] bytes) throws SQLException {
cs.setBinaryStream(parameterName, new ByteArrayInputStream(bytes),
bytes.length);
}
public byte[] get(final ResultSet rs, final int columnIndex)
throws SQLException {
return toBytes(rs.getBlob(columnIndex));
}
public byte[] get(final ResultSet rs, final String columnName)
throws SQLException {
return toBytes(rs.getBlob(columnName));
}
public byte[] get(final CallableStatement cs, final int columnIndex)
throws SQLException {
return toBytes(cs.getBlob(columnIndex));
}
public byte[] get(final CallableStatement cs, final String columnName)
throws SQLException {
return toBytes(cs.getBlob(columnName));
}
}
}