/* 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.riotfamily.media.model;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.DiscriminatorValue;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Transient;
import javax.persistence.UniqueConstraint;
import org.hibernate.annotations.Cache;
import org.hibernate.annotations.CacheConcurrencyStrategy;
import org.riotfamily.common.hibernate.ActiveRecordBeanSupport;
import org.riotfamily.common.util.FormatUtils;
import org.riotfamily.common.util.Generics;
import org.riotfamily.common.util.HashUtils;
import org.riotfamily.core.security.AccessController;
import org.riotfamily.core.security.auth.RiotUser;
import org.riotfamily.media.meta.MediaService;
import org.springframework.util.Assert;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;
/**
* @author Felix Gnass [fgnass at neteye dot de]
* @since 7.0
*/
@Entity
@Table(name="riot_files",
uniqueConstraints={
@UniqueConstraint(columnNames={"uri"})
}
)
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorValue("file")
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region="media")
public class RiotFile extends ActiveRecordBeanSupport {
protected MediaService mediaService;
private String uri;
private String fileName;
private String contentType;
private long size;
private String md5;
private String owner;
private Date creationDate;
private Map<String, RiotFile> variants;
private transient boolean emptyFileCreated;
private transient String bucket;
public RiotFile() {
}
public RiotFile(String bucket) {
this.bucket = bucket;
}
public RiotFile(File file) throws IOException {
setFile(file);
}
public RiotFile(MultipartFile multipartFile) throws IOException {
setMultipartFile(multipartFile);
}
public RiotFile(InputStream in, String fileName) throws IOException {
setInputStream(in, fileName);
}
public RiotFile(byte[] bytes, String fileName) throws IOException {
setBytes(bytes, fileName);
}
public RiotFile(RiotFile riotFile) throws IOException {
this(riotFile, true);
}
public RiotFile(RiotFile riotFile, boolean copyVariants) throws IOException {
this.fileName = riotFile.getFileName();
this.uri = mediaService.store(new FileInputStream(riotFile.getFile()), fileName, riotFile.getBucket());
this.contentType = riotFile.getContentType();
this.size = riotFile.getSize();
this.md5 = riotFile.getMd5();
this.owner = riotFile.getOwner();
this.creationDate = riotFile.getCreationDate();
if (copyVariants) {
Map<String, RiotFile> otherVariants = riotFile.getVariants();
if (otherVariants != null) {
this.variants = Generics.newHashMap();
for (Entry<String, RiotFile> entry : otherVariants.entrySet()) {
RiotFile variant = entry.getValue();
if (variant != null) {
addVariant(entry.getKey(), variant.copy(true));
}
}
}
}
}
public void setMediaService(MediaService mediaService) {
this.mediaService = mediaService;
}
public RiotFile copy(boolean copyVariants) throws IOException {
return new RiotFile(this, copyVariants);
}
@Transient
public void setMultipartFile(MultipartFile multipartFile) throws IOException {
fileName = multipartFile.getOriginalFilename();
size = multipartFile.getSize();
contentType = multipartFile.getContentType();
initCreationInfo();
uri = mediaService.store(multipartFile.getInputStream(), fileName, bucket);
md5 = HashUtils.md5(multipartFile.getInputStream());
inspect(getFile());
}
@Transient
public void setFile(File file) throws IOException {
fileName = file.getName();
size = file.length();
contentType = mediaService.getContentType(file);
initCreationInfo();
uri = mediaService.store(new FileInputStream(file), fileName, bucket);
md5 = HashUtils.md5(new FileInputStream(file));
inspect(file);
}
@Transient
public void setInputStream(InputStream in, String fileName) throws IOException {
File f = createEmptyFile(fileName);
FileCopyUtils.copy(in, new FileOutputStream(f));
contentType = mediaService.getContentType(f);
updateMetaData();
}
@Transient
public void setBytes(byte[] bytes, String fileName) throws IOException {
File f = createEmptyFile(fileName);
FileCopyUtils.copy(bytes, f);
contentType = mediaService.getContentType(f);
updateMetaData();
}
public File createEmptyFile(String name) throws IOException {
fileName = name;
uri = mediaService.store(null, name, bucket);
emptyFileCreated = true;
initCreationInfo();
return getFile();
}
public void updateMetaData() throws IOException {
Assert.state(emptyFileCreated == true, "updateMetaData() must only be "
+ "called after createEmptyFile() has been invoked");
size = getFile().length();
md5 = HashUtils.md5(getInputStream());
inspect(getFile());
}
private void initCreationInfo() {
creationDate = new Date();
RiotUser user = AccessController.getCurrentUser();
if (user != null) {
owner = user.getUserId();
}
}
protected void inspect(File file) throws IOException {
}
public String getUri() {
return this.uri;
}
public void setUri(String uri) {
this.uri = uri;
}
@Transient
public File getFile() {
return mediaService.retrieve(uri);
}
public void deleteFile() {
mediaService.delete(uri);
}
@Transient
public InputStream getInputStream() throws FileNotFoundException {
return new FileInputStream(getFile());
}
public String getFileName() {
return this.fileName;
}
public void setFileName(String fileName) {
this.fileName = fileName;
}
public String getContentType() {
return this.contentType;
}
public void setContentType(String contentType) {
this.contentType = contentType;
}
@Column(name="`size`")
public long getSize() {
return this.size;
}
public void setSize(long size) {
this.size = size;
}
@Transient
public String getFormatedSize() {
return FormatUtils.formatByteSize(size);
}
public String getOwner() {
return this.owner;
}
public void setOwner(String uploadedBy) {
this.owner = uploadedBy;
}
public Date getCreationDate() {
return this.creationDate;
}
public void setCreationDate(Date creationDate) {
this.creationDate = creationDate;
}
public String getMd5() {
return this.md5;
}
public void setMd5(String md5) {
this.md5 = md5;
}
@OneToMany(cascade=CascadeType.ALL)
@JoinTable(name="riot_file_variants")
@Cache(usage=CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region="media")
public Map<String, RiotFile> getVariants() {
return this.variants;
}
public void setVariants(Map<String, RiotFile> variants) {
this.variants = variants;
}
public void addVariant(String name, RiotFile variant) {
if (variants == null) {
variants = new HashMap<String, RiotFile>();
}
variants.put(name, variant);
}
public RiotFile get(String name) {
if (variants == null) {
return null;
}
return variants.get(name);
}
@Transient
protected String getBucket() {
return bucket;
}
@Override
public int hashCode() {
if (uri != null) {
return uri.hashCode();
}
return 0;
}
@Override
public boolean equals(Object obj) {
if (uri != null && obj instanceof RiotFile) {
RiotFile other = (RiotFile) obj;
return uri.equals(other.getUri());
}
return super.equals(obj);
}
// ----------------------------------------------------------------------
// Active record methods
// ----------------------------------------------------------------------
public static RiotFile loadByUri(String uri) {
return query(RiotFile.class, "from {} where uri = ?", uri).load();
}
public static RiotFile loadByMd5(String md5) {
return query(RiotFile.class, "from {} where md5 = ?", md5).load();
}
}