/*
* Copyright 2015-Present Entando Inc. (http://www.entando.com) All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.entando.entando.plugins.jpfileattribute.aps.system.file;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.entando.entando.aps.system.services.storage.IStorageManager;
import org.entando.entando.plugins.jpfileattribute.aps.system.entity.model.FileAttribute;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.agiletec.aps.system.common.AbstractService;
import com.agiletec.aps.system.common.FieldSearchFilter;
import com.agiletec.aps.system.common.entity.model.IApsEntity;
import com.agiletec.aps.system.common.entity.model.attribute.AttributeInterface;
import com.agiletec.aps.system.common.util.EntityAttributeIterator;
import com.agiletec.aps.system.exception.ApsSystemException;
/**
* @author E.Santoboni
*/
@Aspect
public class FilePersistenceManager extends AbstractService implements IFilePersistenceManager {
private static final Logger _logger = LoggerFactory.getLogger(FilePersistenceManager.class);
@Override
public void init() throws Exception {
_logger.debug("{} ready", this.getClass().getName());
}
@AfterReturning(pointcut = "execution(* com.agiletec.aps.system.common.entity.AbstractEntityDAO.addEntity(..)) && args(entity,..)")
public void addEntity(Object entity) {
this.updateEntityFiles((IApsEntity) entity);
}
@AfterReturning(pointcut = "execution(* com.agiletec.aps.system.common.entity.AbstractEntityDAO.updateEntity(..)) && args(entity,..)")
public void updateEntity(Object entity) {
this.updateEntityFiles((IApsEntity) entity);
}
private void updateEntityFiles(IApsEntity apsEntity) {
try {
List<Integer> ids = this.getFilesByEntity(apsEntity);
this.getFilePersistenceDAO().updateEntityFiles(apsEntity.getId(), ids);
} catch (Throwable t) {
_logger.error("Error updating files by entity {}", apsEntity.getId(), t);
}
}
@AfterReturning(pointcut = "execution(* com.agiletec.aps.system.common.entity.AbstractEntityDAO.deleteEntity(..)) && args(entityId,..)")
public void deleteEntity(Object entityId) {
try {
FieldSearchFilter filter = new FieldSearchFilter("entityid", entityId.toString(), false);
FieldSearchFilter[] filters = {filter};
List<String> ids = this.getFilePersistenceDAO().searchId(filters);
if (null != ids && !ids.isEmpty()) {
for (int i = 0; i < ids.size(); i++) {
String idString = ids.get(i);
this.deleteFile(Integer.parseInt(idString));
}
}
} catch (Throwable t) {
_logger.error("Error deleting files by entity {}", entityId, t);
}
}
private List<Integer> getFilesByEntity(IApsEntity entity) {
List<Integer> ids = new ArrayList<Integer>();
if (null == entity) {
return ids;
}
EntityAttributeIterator attributeIter = new EntityAttributeIterator(entity);
while (attributeIter.hasNext()) {
AttributeInterface currAttribute = (AttributeInterface) attributeIter.next();
if (currAttribute instanceof FileAttribute) {
FileAttribute fileAttribute = (FileAttribute) currAttribute;
if (null != fileAttribute.getAttachedFile()) {
ids.add(fileAttribute.getAttachedFile().getId());
}
}
}
return ids;
}
@Override
public synchronized int addFile(AttachedFile file) throws ApsSystemException {
int id = -1;
String path = null;
try {
id = this.getFilePersistenceDAO().extractNexId();
file.setId(id);
this.getFilePersistenceDAO().addFile(file);
path = this.getFilePath(file);
InputStream is = new ByteArrayInputStream(file.getBase64());
this.getStorageManager().saveFile(path, true, is);
} catch (Throwable t) {
if (null != path) {
this.getStorageManager().deleteFile(path, true);
}
this.getFilePersistenceDAO().deleteFile(id);
_logger.error("Error adding a file", t);
throw new ApsSystemException("Error adding a file", t);
}
return id;
}
protected String getFilePath(AttachedFile file) {
StringBuilder urlPath = new StringBuilder();
urlPath.append(this.getFolder()).append(File.separator).append(file.getId()).append(File.separator);
urlPath.append(file.getFilename());
return urlPath.toString();
}
@Override
public AttachedFile loadFile(Integer id) throws ApsSystemException {
AttachedFile attachedFile = null;
try {
attachedFile = this.getFilePersistenceDAO().loadFile(id);
if (null != attachedFile) {
String path = this.getFilePath(attachedFile);
InputStream is = this.getStorageManager().getStream(path, true);
if (null != is) {
attachedFile.setBase64(this.streamToByteArray(is));
}
}
} catch (Throwable t) {
_logger.error("Error loading file with id {}", id, t);
throw new ApsSystemException("Error loading file with id " + id, t);
}
return attachedFile;
}
private byte[] streamToByteArray(InputStream is) throws Throwable {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] buf = new byte[1024];
try {
for (int readNum; (readNum = is.read(buf)) != -1;) {
bos.write(buf, 0, readNum);
}
} catch (IOException ex) {
_logger.error("Error creating byte array", ex);
throw new ApsSystemException("Error creating byte array", ex);
}
return bos.toByteArray();
}
@Override
public void deleteFile(Integer id) throws ApsSystemException {
try {
AttachedFile attachedFile = this.getFilePersistenceDAO().loadFile(id);
if (null != attachedFile) {
String path = this.getFilePath(attachedFile);
this.getStorageManager().deleteFile(path, true);
}
} catch (Throwable t) {
_logger.error("Error deleting file with id {}", id, t);
throw new ApsSystemException("Error deleting file with id " + id, t);
}
}
protected String getFolder() {
if (null == this._folder) {
return DEFAULT_FOLDER;
}
return _folder;
}
public void setFolder(String folder) {
if (!folder.endsWith("/")) {
folder += "/";
}
this._folder = folder;
}
protected IStorageManager getStorageManager() {
return _storageManager;
}
public void setStorageManager(IStorageManager storageManager) {
this._storageManager = storageManager;
}
protected IFilePersistenceDAO getFilePersistenceDAO() {
return _filePersistenceDAO;
}
public void setFilePersistenceDAO(IFilePersistenceDAO filePersistenceDAO) {
this._filePersistenceDAO = filePersistenceDAO;
}
private String _folder;
private IStorageManager _storageManager;
private IFilePersistenceDAO _filePersistenceDAO;
private static final String DEFAULT_FOLDER = "plugins/jpfileattribute/";
}