AttachmentAspect.java
/*
* Copyright 2020 Global Crop Diversity Trust
*
* 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.gringlobal.component.repository;
import java.io.IOException;
import java.nio.file.Path;
import java.nio.file.Paths;
import javax.persistence.EntityManager;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.genesys.filerepository.InvalidRepositoryPathException;
import org.genesys.filerepository.NoSuchRepositoryFileException;
import org.genesys.filerepository.ReferencedRepositoryFileException;
import org.genesys.filerepository.model.RepositoryFile;
import org.genesys.filerepository.model.RepositoryImage;
import org.genesys.filerepository.persistence.RepositoryFilePersistence;
import org.genesys.filerepository.service.RepositoryService;
import org.gringlobal.model.IAttachment;
import org.hibernate.Hibernate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
/**
* Remove attachments from the repository
*
* @author Matija Obreza
* @author Maxym Borodenko
*/
@Aspect
@Component
@Slf4j
public class AttachmentAspect {
@Autowired
private RepositoryService repositoryService;
@Autowired
private EntityManager entityManager;
@Autowired
private RepositoryFilePersistence repositoryFilePersistence;
/**
* Update file reference of any {@link IAttachment} entity on save.
*
* @param joinPoint the join point
* @param attachment the attachment
* @return the object
* @throws Throwable the throwable
*/
@Around(value = "(execution(* org.springframework.data.repository.*.save(..)) || execution(* org.springframework.data.repository.*.saveAndFlush(..)) || execution(* org.springframework.data.jpa.repository.*.save(..))) && args(attachment)")
public Object aroundAttachmentSave(final ProceedingJoinPoint joinPoint, final IAttachment attachment) throws Throwable {
log.trace("One attachment is being saved");
try {
assignRepositoryFileRef(attachment);
} catch (final Throwable e) {
log.error("Failed to set reference to repository file: {}", e.getMessage(), e);
}
return joinPoint.proceed();
}
/**
* Around attachments save checks if IAttachment types are being persisted and updates the file references.
*
* @param joinPoint the join point
* @param genericCollection the generic collection
* @return the method result
*/
@Around(value = "execution(* org.springframework.data.repository.*.saveAll(..)) && args(genericCollection)")
public Object aroundAttachmentsSave(final ProceedingJoinPoint joinPoint, final Iterable<?> genericCollection) throws Throwable {
// System.err.println("AttachmentAspect saveAll");
if (genericCollection != null) {
log.trace("Checking if attachments are being saved: {}", genericCollection);
try {
for (Object element : genericCollection) {
if (element instanceof IAttachment) {
assignRepositoryFileRef((IAttachment) element);
}
}
} catch (final Throwable e) {
log.error("Failed to set reference to repository file: {}", e.getMessage(), e);
}
}
return joinPoint.proceed();
}
private void assignRepositoryFileRef(IAttachment attachment) {
if (attachment == null) {
return;
} else if (attachment.getRepositoryFile() != null) {
return;
}
Path attachedFile = Paths.get("/", attachment.getVirtualPath());
try {
RepositoryFile repositoryFile = repositoryService.getFile(attachedFile.getParent(), attachedFile.getFileName().toString());
attachment.setRepositoryFile(repositoryFile);
log.info("Repository file {} added to attachment", attachedFile);
} catch (NoSuchRepositoryFileException | InvalidRepositoryPathException e) {
log.warn("Non-existent file path {}: {}", attachedFile, e.getMessage());
} catch (Throwable e) {
log.error("Could not assign repository file {}: {}", attachedFile, e.getMessage(), e);
}
}
/**
* Remove repository file when {@link IAttachment} is deleted.
*
* @param joinPoint the join point
* @param attachment the attachment
* @return the object
* @throws Throwable the throwable
*/
@Around(value = "(execution(* org.springframework.data.repository.*.delete(..)) || execution(* org.springframework.data.jpa.repository.*.delete(..))) && args(attachment)")
public Object aroundAttachmentDelete(final ProceedingJoinPoint joinPoint, final IAttachment attachment) throws Throwable {
Object result = joinPoint.proceed();
log.trace("One attachment is being deleted");
try {
removeAttachment(attachment);
} catch (final IOException e) {
log.error("Failed to remove repository file: {}", e.getMessage(), e);
}
return result;
}
/**
* Remove repository file if an {@link IAttachment} is removed.
*
* @param joinPoint the join point
* @param genericCollection the generic collection
* @return the object
* @throws Throwable the throwable
*/
@Around(value = "(execution(* org.springframework.data.repository.*.deleteAll(..)) || execution(* org.springframework.data.repository.*.deleteAllInBatch(..)) || execution(* org.springframework.data.jpa.repository.*.deleteAll(..)) || execution(* org.springframework.data.jpa.repository.*.deleteAllInBatch(..))) && args(genericCollection)")
public Object aroundAttachmentsDelete(final ProceedingJoinPoint joinPoint, final Iterable<?> genericCollection) throws Throwable {
Object result = joinPoint.proceed();
if (genericCollection != null) {
log.trace("Checking if attachments are being deleted: {}", genericCollection);
for (Object element : genericCollection) {
if (element instanceof IAttachment) {
try {
removeAttachment((IAttachment) element);
} catch (final IOException e) {
log.error("Failed to remove repository file: {}", e.getMessage(), e);
}
}
}
}
return result;
}
/**
* Remove attachment from file repository
*
* @param attachment the attachment to remove
* @throws IOException
*/
private void removeAttachment(IAttachment attachment) throws IOException {
if (attachment == null) {
return;
}
Path attachedFile = Paths.get("/", attachment.getVirtualPath());
entityManager.flush(); // Delete *Attach entity
try {
log.debug("Need to remove {}", attachedFile);
RepositoryFile repositoryFile = (RepositoryFile) Hibernate.unproxy(repositoryFilePersistence.findByUuid(attachment.getRepositoryFile().getUuid()));
if (repositoryFile instanceof RepositoryImage) {
repositoryService.removeFileIfPossible((RepositoryImage) repositoryFile);
} else {
repositoryService.removeFileIfPossible(repositoryFile);
}
log.debug("Removed {} from repository", repositoryFile);
} catch (NoSuchRepositoryFileException e) {
log.info("Can't remove file from path because it's no longer available {}: {}", attachedFile, e.getMessage());
} catch (ReferencedRepositoryFileException e) {
log.info("Can't remove file from path because it's referenced by another entity {}: {}", attachedFile, e.getMessage());
}
}
}