mirror of
https://github.com/ebean-orm/ebean.git
synced 2024-04-21 10:51:47 +00:00
#211 - ENH: Add support for File as a bean type ... for streaming into/from db
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.io.Reader;
|
||||
import java.io.StringReader;
|
||||
import java.math.BigDecimal;
|
||||
@@ -114,7 +115,15 @@ public class DataBind {
|
||||
public void setChar(char v) throws SQLException {
|
||||
pstmt.setString(++pos, String.valueOf(v));
|
||||
}
|
||||
|
||||
|
||||
public void setBlob(InputStream inputStream, long length) throws SQLException {
|
||||
pstmt.setBlob(++pos, inputStream, length);
|
||||
}
|
||||
|
||||
public void setBlob(InputStream inputStream) throws SQLException {
|
||||
pstmt.setBlob(++pos, inputStream);
|
||||
}
|
||||
|
||||
public void setBlob(byte[] bytes) throws SQLException {
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||
pstmt.setBinaryStream(++pos, is, bytes.length);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.math.BigDecimal;
|
||||
import java.sql.Array;
|
||||
import java.sql.SQLException;
|
||||
@@ -52,4 +53,5 @@ public interface DataReader {
|
||||
|
||||
public Object getObject() throws SQLException;
|
||||
|
||||
public InputStream getBinaryStream() throws SQLException;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import java.io.File;
|
||||
import java.lang.reflect.Field;
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
@@ -66,6 +67,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
|
||||
private final DefaultTypeFactory extraTypeFactory;
|
||||
|
||||
private final ScalarTypeFile fileType = new ScalarTypeFile();
|
||||
|
||||
private final ScalarType<?> charType = new ScalarTypeChar();
|
||||
|
||||
private final ScalarType<?> charArrayType = new ScalarTypeCharArray();
|
||||
@@ -127,8 +130,8 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
*/
|
||||
public DefaultTypeManager(ServerConfig config, BootupClasses bootupClasses) {
|
||||
|
||||
int clobType = config == null ? Types.CLOB : config.getDatabasePlatform().getClobDbType();
|
||||
int blobType = config == null ? Types.BLOB : config.getDatabasePlatform().getBlobDbType();
|
||||
int clobType = config.getDatabasePlatform().getClobDbType();
|
||||
int blobType = config.getDatabasePlatform().getBlobDbType();
|
||||
|
||||
this.jsonDateTime = config.getJsonDateTime();
|
||||
this.checkImmutable = new CheckImmutable(this);
|
||||
@@ -296,7 +299,12 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> ScalarType<T> getScalarType(Class<T> type, int jdbcType) {
|
||||
|
||||
// check for Clob, LongVarchar etc first...
|
||||
// File is a special Lob so check for that first
|
||||
if (File.class.equals(type)) {
|
||||
return (ScalarType<T>) fileType;
|
||||
}
|
||||
|
||||
// check for Clob, LongVarchar etc ...
|
||||
// the reason being that String maps to multiple jdbc types
|
||||
// varchar, clob, longVarchar.
|
||||
ScalarType<?> scalarType = getLobTypes(jdbcType);
|
||||
@@ -321,8 +329,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
return (ScalarType<T>) extraTypeFactory.createCalendar(jsonDateTime, jdbcType);
|
||||
}
|
||||
|
||||
String msg = "Unmatched ScalarType for " + type + " jdbcType:" + jdbcType;
|
||||
throw new RuntimeException(msg);
|
||||
throw new RuntimeException("Unmatched ScalarType for " + type + " jdbcType:" + jdbcType);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -650,7 +657,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
* plus some other common types such as java.util.Date and java.util.Calendar.
|
||||
*/
|
||||
protected void initialiseStandard(JsonConfig.DateTime mode, int platformClobType, int platformBlobType, boolean binaryUUID) {
|
||||
|
||||
|
||||
ScalarType<?> utilDateType = extraTypeFactory.createUtilDate(mode);
|
||||
typeMap.put(java.util.Date.class, utilDateType);
|
||||
|
||||
@@ -675,6 +682,7 @@ public final class DefaultTypeManager implements TypeManager, KnownImmutable {
|
||||
ScalarType<?> uuidType = (binaryUUID) ? new ScalarTypeUUIDBinary() : new ScalarTypeUUIDVarchar();
|
||||
typeMap.put(UUID.class, uuidType);
|
||||
|
||||
typeMap.put(File.class, fileType);
|
||||
typeMap.put(InetAddress.class, inetAddressType);
|
||||
typeMap.put(Locale.class, localeType);
|
||||
typeMap.put(Currency.class, currencyType);
|
||||
|
||||
@@ -0,0 +1,193 @@
|
||||
package com.avaje.ebeaninternal.server.type;
|
||||
|
||||
import com.avaje.ebean.text.TextException;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import com.fasterxml.jackson.core.JsonParser;
|
||||
import com.fasterxml.jackson.core.JsonToken;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.*;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Types;
|
||||
|
||||
/**
|
||||
* ScalarType for streaming between a File and the database.
|
||||
*/
|
||||
public class ScalarTypeFile extends ScalarTypeBase<File> {
|
||||
|
||||
private static Logger logger = LoggerFactory.getLogger(ScalarTypeFile.class);
|
||||
|
||||
private final String prefix;
|
||||
|
||||
private final String suffix;
|
||||
|
||||
private final File directory;
|
||||
|
||||
private final int bufferSize;
|
||||
|
||||
/**
|
||||
* Construct with reasonable defaults of Blob and 8096 buffer size.
|
||||
*/
|
||||
public ScalarTypeFile() {
|
||||
this(Types.BLOB, "db-", null, null, 8096);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the ScalarTypeFile.
|
||||
*/
|
||||
public ScalarTypeFile(int jdbcType, String prefix, String suffix, File directory, int bufferSize) {
|
||||
super(File.class, false, jdbcType);
|
||||
this.prefix = prefix;
|
||||
this.suffix = suffix;
|
||||
this.directory = directory;
|
||||
this.bufferSize = bufferSize;
|
||||
}
|
||||
|
||||
private InputStream getInputStream(File value) throws IOException {
|
||||
FileInputStream fi = new FileInputStream(value);
|
||||
return new BufferedInputStream(fi, bufferSize);
|
||||
}
|
||||
|
||||
private OutputStream getOutputStream(File value) throws IOException {
|
||||
FileOutputStream fi = new FileOutputStream(value);
|
||||
return new BufferedOutputStream(fi, bufferSize);
|
||||
}
|
||||
|
||||
@Override
|
||||
public File read(DataReader dataReader) throws SQLException {
|
||||
|
||||
InputStream is = dataReader.getBinaryStream();
|
||||
if (is == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
// stream from db into our temp file
|
||||
File tempFile = File.createTempFile(prefix, suffix, directory);
|
||||
OutputStream os = getOutputStream(tempFile);
|
||||
pump(is, os);
|
||||
|
||||
return tempFile;
|
||||
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Error reading db file inputStream", e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void bind(DataBind b, File value) throws SQLException {
|
||||
if (value == null) {
|
||||
b.setNull(jdbcType);
|
||||
} else {
|
||||
try {
|
||||
// stream from our file to the db
|
||||
InputStream fi = getInputStream(value);
|
||||
b.setBlob(fi, value.length());
|
||||
} catch (IOException e) {
|
||||
throw new SQLException("Error trying to set file inputStream", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object toJdbcType(Object value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File toBeanType(Object value) {
|
||||
return (File) value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jsonWrite(JsonGenerator ctx, String name, File value) throws IOException {
|
||||
ctx.writeFieldName(name);
|
||||
InputStream is = getInputStream(value);
|
||||
ctx.writeBinary(is, (int) value.length());
|
||||
}
|
||||
|
||||
@Override
|
||||
public File jsonRead(JsonParser ctx, JsonToken event) throws IOException {
|
||||
File tempFile = File.createTempFile(prefix, suffix, directory);
|
||||
OutputStream os = getOutputStream(tempFile);
|
||||
ctx.readBinaryValue(os);
|
||||
os.flush();
|
||||
os.close();
|
||||
return tempFile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String formatValue(File file) {
|
||||
throw new TextException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File parse(String value) {
|
||||
throw new TextException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public File convertFromMillis(long systemTimeMillis) {
|
||||
throw new TextException("Not supported");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDateTimeCapable() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public File readData(DataInput dataInput) throws IOException {
|
||||
// skip reading large file
|
||||
return null;
|
||||
}
|
||||
|
||||
public void writeData(DataOutput dataOutput, File file) throws IOException {
|
||||
// skip writing large file
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper method to pump bytes from input to output.
|
||||
*/
|
||||
public long pump(InputStream is, OutputStream out) throws IOException {
|
||||
|
||||
long totalBytes = 0;
|
||||
InputStream input = null;
|
||||
OutputStream output = null;
|
||||
|
||||
try {
|
||||
input = new BufferedInputStream(is, bufferSize);
|
||||
output = new BufferedOutputStream(out, bufferSize);
|
||||
|
||||
byte[] buffer = new byte[bufferSize];
|
||||
int length;
|
||||
while (((length = input.read(buffer)) > 0)) {
|
||||
output.write(buffer, 0, length);
|
||||
totalBytes += length;
|
||||
}
|
||||
|
||||
output.flush();
|
||||
|
||||
return totalBytes;
|
||||
|
||||
} finally {
|
||||
if (output != null) {
|
||||
try {
|
||||
output.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error when closing outputstream", e);
|
||||
}
|
||||
}
|
||||
if (input != null) {
|
||||
try {
|
||||
input.close();
|
||||
} catch (IOException e) {
|
||||
logger.error("Error when closing inputstream ", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user