diff --git a/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java b/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java index aca14e1a4..1af29fb35 100644 --- a/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java +++ b/ccm-cms/src/main/java/org/librecms/assets/BinaryAsset.java @@ -38,10 +38,12 @@ import javax.persistence.Table; import org.hibernate.envers.Audited; import org.hibernate.envers.NotAudited; import org.libreccm.core.UnexpectedErrorException; +import org.libreccm.imexport.BlobJsonDeserializer; +import org.libreccm.imexport.BlobJsonSerializer; import org.libreccm.jpa.utils.MimeTypeConverter; import org.libreccm.l10n.LocalizedString; -import org.libreccm.ui.admin.imexport.MimeTypeJsonDeserializer; -import org.libreccm.ui.admin.imexport.MimeTypeJsonSerializer; +import org.libreccm.imexport.MimeTypeJsonDeserializer; +import org.libreccm.imexport.MimeTypeJsonSerializer; import org.librecms.contentsection.privileges.AssetPrivileges; import java.io.InputStream; @@ -161,6 +163,8 @@ public class BinaryAsset extends Asset implements Serializable { @Lob @Basic(fetch = FetchType.LAZY) @NotAudited // Workaround until bug in Hibernate is resolved: https://hibernate.atlassian.net/browse/HHH-14725 + @JsonSerialize(using = BlobJsonSerializer.class) + @JsonDeserialize(using = BlobJsonDeserializer.class) private Blob data; @Column(name = "DATA_SIZE") diff --git a/ccm-core/src/main/java/org/libreccm/imexport/BlobJsonDeserializer.java b/ccm-core/src/main/java/org/libreccm/imexport/BlobJsonDeserializer.java new file mode 100644 index 000000000..955b7e2ab --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/imexport/BlobJsonDeserializer.java @@ -0,0 +1,127 @@ +package org.libreccm.imexport; + +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.DeserializationContext; +import com.fasterxml.jackson.databind.JsonDeserializer; +import org.hibernate.engine.jdbc.BlobProxy; + +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.Blob; + +import static java.lang.System.out; + +/** + * + * @author Jens Pelzetter + */ +public class BlobJsonDeserializer extends JsonDeserializer { + + @Override + public Blob deserialize( + final JsonParser parser, + final DeserializationContext ctxt + ) throws IOException, JsonProcessingException { + final Path tmpFilePath = Files.createTempFile("upload", "import"); + try(OutputStream outputStream = Files.newOutputStream(tmpFilePath)) { + parser.readBinaryValue(outputStream); + final Blob data = BlobProxy.generateProxy( + new UploadInputStream(tmpFilePath), + -1 + ); + + return data; + } + } + + private class UploadInputStream extends InputStream { + + private final Path tmpFilePath; + + private InputStream inputStream; + + public UploadInputStream(final Path tmpFilePath) { + this.tmpFilePath = tmpFilePath; + } + + @Override + public int available() throws IOException { + openNewInputStreamIfNecessary(); + return inputStream.available(); + } + + @Override + public void close() throws IOException { + if (inputStream != null) { + inputStream.close(); + inputStream = null; + } + } + + @Override + public void mark(final int readLimit) { + try { + openNewInputStreamIfNecessary(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + inputStream.mark(readLimit); + } + + @Override + public boolean markSupported() { + try { + openNewInputStreamIfNecessary(); + } catch (IOException ex) { + throw new RuntimeException(ex); + } + return inputStream.markSupported(); + } + + @Override + public int read() throws IOException { + openNewInputStreamIfNecessary(); + return inputStream.read(); + } + + @Override + public int read(final byte[] data) throws IOException { + openNewInputStreamIfNecessary(); + return inputStream.read(data); + } + + @Override + public int read(final byte[] data, final int offset, final int length) + throws IOException { + openNewInputStreamIfNecessary(); + return inputStream.read(data, offset, length); + } + + @Override + public void reset() throws IOException { + if (inputStream == null) { + openNewInputStreamIfNecessary(); + } else { + inputStream.reset(); + } + } + + @Override + public long skip(long nBytes) throws IOException { + openNewInputStreamIfNecessary(); + return inputStream.skip(nBytes); + } + + private void openNewInputStreamIfNecessary() throws IOException { + if (inputStream == null) { + inputStream = Files.newInputStream(tmpFilePath); + } + } + + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/imexport/BlobJsonSerializer.java b/ccm-core/src/main/java/org/libreccm/imexport/BlobJsonSerializer.java new file mode 100644 index 000000000..3c75ef4cf --- /dev/null +++ b/ccm-core/src/main/java/org/libreccm/imexport/BlobJsonSerializer.java @@ -0,0 +1,31 @@ +package org.libreccm.imexport; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.databind.JsonSerializer; +import com.fasterxml.jackson.databind.SerializerProvider; + +import java.io.IOException; +import java.sql.Blob; +import java.sql.SQLException; + +/** + * + * @author Jens Pelzetter + */ +public class BlobJsonSerializer extends JsonSerializer { + + @Override + public void serialize( + final Blob value, + final JsonGenerator generator, + final SerializerProvider serializers + ) throws IOException { + try { + generator.writeFieldName("data"); + generator.writeBinary(value.getBinaryStream(), -1); + } catch (SQLException ex) { + throw new IOException(ex); + } + } + +} diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/MimeTypeJsonDeserializer.java b/ccm-core/src/main/java/org/libreccm/imexport/MimeTypeJsonDeserializer.java similarity index 92% rename from ccm-core/src/main/java/org/libreccm/ui/admin/imexport/MimeTypeJsonDeserializer.java rename to ccm-core/src/main/java/org/libreccm/imexport/MimeTypeJsonDeserializer.java index 807c575f0..f64fc3f47 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/MimeTypeJsonDeserializer.java +++ b/ccm-core/src/main/java/org/libreccm/imexport/MimeTypeJsonDeserializer.java @@ -1,10 +1,9 @@ -package org.libreccm.ui.admin.imexport; +package org.libreccm.imexport; import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; -import com.fasterxml.jackson.databind.JsonNode; import java.io.IOException; diff --git a/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/MimeTypeJsonSerializer.java b/ccm-core/src/main/java/org/libreccm/imexport/MimeTypeJsonSerializer.java similarity index 94% rename from ccm-core/src/main/java/org/libreccm/ui/admin/imexport/MimeTypeJsonSerializer.java rename to ccm-core/src/main/java/org/libreccm/imexport/MimeTypeJsonSerializer.java index 81e588d06..14891789f 100644 --- a/ccm-core/src/main/java/org/libreccm/ui/admin/imexport/MimeTypeJsonSerializer.java +++ b/ccm-core/src/main/java/org/libreccm/imexport/MimeTypeJsonSerializer.java @@ -1,4 +1,4 @@ -package org.libreccm.ui.admin.imexport; +package org.libreccm.imexport; import com.fasterxml.jackson.core.JsonGenerator; import com.fasterxml.jackson.databind.JsonSerializer;