@Service
public class DocumentServiceScheduler {
private final Path storageArchitasPath;
@Autowired
private DocumentService documentService;
public DocumentServiceScheduler(final DocumentConfiguration documentConfiguration) {
this.storageArchitasPath = documentConfiguration.storageArchitasPath();
}
@Scheduled(cron = "${document.scan.timer}")
public void scanDocumentsTask() {
this.scanDocuments();
}
public void scanDocuments() {
final List<DocumentProcessDetail> report = new ArrayList<>();
FileCoreUtils.loadPathFilesInDirectory(this.storageArchitasPath).forEach(fileName -> report.add(this.documentService.processDocument(fileName)));
if (!report.isEmpty()) {
final DataSource excelReport = FileCoreUtils.writeReportAsExcel(report);
this.documentService.sendReportByEmail(excelReport);
}
}
}
Business Class
@Service
public class DocumentServiceImpl implements DocumentService {
private static Logger logger = LoggerFactory.getLogger(DocumentServiceImpl.class);
private static String DOCUMENT_SEPARATOR = "#";
private final Path storageArchitasPath;
private final Path storageSystemPath;
private final DocumentRepository documentRepository;
private final DocumentTypeRepository documentTypeRepository;
public DocumentServiceImpl(final DocumentRepository documentRepository, final DocumentTypeRepository documentTypeRepository, final DocumentConfiguration documentConfiguration) {
this.documentRepository = documentRepository;
this.documentTypeRepository = documentTypeRepository;
this.storageArchitasPath = documentConfiguration.storageArchitasPath();
this.storageSystemPath = documentConfiguration.storageSystemPath();
}
@Override
@Transactional
public DocumentProcessDetail processDocument(final Path fileName) {
final Date uploadDate = new Date();
try {
final String[] splitFileName = fileName.getFileName().toString().split(DOCUMENT_SEPARATOR);
String brokerId = splitFileName[0].trim();
final StringBuilder error = this.validateDocumentFormat(splitFileName);
if (error.length() != 0) {
FileUtils.forceDelete(this.storageArchitasPath.resolve(fileName).toFile());
return new DocumentProcessDetail(fileName.toString(), uploadDate, "Failure", error.toString());
}
if (splitFileName.length == 2) {
if (this.deleteDocument(splitFileName)) {
return new DocumentProcessDetail(fileName.toString(), uploadDate, "Success", null);
}
FileUtils.forceDelete(this.storageArchitasPath.resolve(fileName).toFile());
error.append("Couldn't delete file, not found in database");
return new DocumentProcessDetail(fileName.toString(), uploadDate, "Failure", error.toString());
}
final String type = splitFileName[1].toUpperCase().trim();
final String language = splitFileName[2].toUpperCase().trim();
final String filename = splitFileName[3].trim();
final String uuid = UUID.randomUUID().toString();
final String newFileName = uuid + "." + FilenameUtils.getExtension(fileName.toString());
final Path destination = this.generateStorageSystemPath(brokerId, newFileName);
brokerId = brokerId.equalsIgnoreCase("all") ? null : brokerId;
final Optional<DocumentTypeDB> documentTypeDB = this.documentTypeRepository.findById(DocumentType.valueOf(type.toUpperCase()));
final DocumentDB document = new DocumentDB(filename, brokerId, documentTypeDB.get(), uploadDate, DocumentLanguage.valueOf(language), uuid);
this.documentRepository.save(document);
FileCoreUtils.moveFile(this.storageArchitasPath.resolve(fileName), destination);
throw new Exception();
//return new DocumentProcessDetail(uuid, fileName.toString(), uploadDate, "Success", null);
} catch (final Exception e) {
try {
FileUtils.forceDelete(this.storageArchitasPath.resolve(fileName).toFile());
} catch (final IOException e1) {
logger.error("An unexpected error while deleting file: " + e.getStackTrace());
}
//TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
throw new RuntimeException();
//return new DocumentProcessDetail(fileName.toString(), uploadDate, "failure", "An unexpected error occurred: " + e.getStackTrace());
}
}
}
Repository class
@Repository
public interface DocumentRepository extends JpaRepository<DocumentDB, Long>,
DocumentRepositoryCustom {
DocumentDB findByDocumentReference(String reference);
}
Using mysql 5.7
The problem here is that Transactional is not being triggered... I throw a RuntimeException and it saves my item in database anyway... I tried to programmatically force rollback, but it also gets ignored...
TransactionAspectSupport.currentTransactionStatus().setRollbackOnly()
I also added @EnableTransactionManagement
also does not work and I got this message in console
==========================
CONDITION EVALUATION DELTA
==========================
Positive matches:
-----------------
None
Negative matches:
-----------------
TransactionAutoConfiguration.EnableTransactionManagementConfiguration:
Did not match:
- @ConditionalOnMissingBean (types: org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration; SearchStrategy: all) found beans of type 'org.springframework.transaction.annotation.AbstractTransactionManagementConfiguration' org.springframework.transaction.annotation.ProxyTransactionManagementConfiguration (OnBeanCondition)
TransactionAutoConfiguration.EnableTransactionManagementConfiguration.CglibAutoProxyConfiguration:
Did not match:
- Ancestor org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration$EnableTransactionManagementConfiguration did not match (ConditionEvaluationReport.AncestorsMatchedCondition)
Matched:
- @ConditionalOnProperty (spring.aop.proxy-target-class=true) matched (OnPropertyCondition)
Exclusions:
-----------
None
Unconditional classes:
----------------------
None
How can I force transaction rollback when an Exception occurs?
EDIT
@Transactional
public void testDoc() {
final DocumentDB document = new DocumentDB("test", this.brokerId, new DocumentTypeDB(DocumentType.valueOf("TAX_FORMS")), new Date(), DocumentLanguage.valueOf("FRENCH"), "000");
System.out.println("documentRepository.save called... start");
this.documentRepository.save(document);
System.out.println("documentRepository.save called... end");
}
Transaction behavior
2021-08-18 15:32:26.486 INFO 7976 --- [ main] o.s.t.c.transaction.TransactionContext : Began transaction (1) for test context [DefaultTestContext@7be58f16 testClass = DocumentServiceImplTest, testInstance = be.architas.broker.portal.core.service.DocumentServiceImplTest@553f1d75, testMethod = testDoc@DocumentServiceImplTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@242aa8d9 testClass = DocumentServiceImplTest, locations = '{}', classes = '{class be.architas.broker.portal.core.BrokerPortalImplTestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1e4d3ce5, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@379614be, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@14fa86ae, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@398dada8, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4066c471, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@65466a6a], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]; transaction manager [org.springframework.orm.jpa.JpaTransactionManager@4ebd0b52]; rollback [true]
documentRepository.save called... start
2021-08-18 15:32:26.651 TRACE 7976 --- [ main] o.s.t.i.TransactionInterceptor : Getting transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
Hibernate:
select
documentty_.ID,
documentty_.IS_OFFICIAL as is_offic2_1_,
documentty_.RETENTION as retentio3_1_
from
DOCUMENT_TYPE documentty_
where
documentty_.ID=?
Hibernate:
insert
into
DOCUMENT
(BROKER_ID, DOCUMENT_REFERENCE, LANGUAGE, NAME, TYPE_ID, UPLOAD_DATE)
values
(?, ?, ?, ?, ?, ?)
2021-08-18 15:32:26.757 TRACE 7976 --- [ main] o.s.t.i.TransactionInterceptor : Completing transaction for [org.springframework.data.jpa.repository.support.SimpleJpaRepository.save]
documentRepository.save called... end
2021-08-18 15:32:26.771 INFO 7976 --- [ main] o.s.t.c.transaction.TransactionContext : Rolled back transaction for test: [DefaultTestContext@7be58f16 testClass = DocumentServiceImplTest, testInstance = be.architas.broker.portal.core.service.DocumentServiceImplTest@553f1d75, testMethod = testDoc@DocumentServiceImplTest, testException = [null], mergedContextConfiguration = [MergedContextConfiguration@242aa8d9 testClass = DocumentServiceImplTest, locations = '{}', classes = '{class be.architas.broker.portal.core.BrokerPortalImplTestConfig}', contextInitializerClasses = '[]', activeProfiles = '{}', propertySourceLocations = '{}', propertySourceProperties = '{org.springframework.boot.test.context.SpringBootTestContextBootstrapper=true}', contextCustomizers = set[org.springframework.boot.test.context.filter.ExcludeFilterContextCustomizer@1e4d3ce5, org.springframework.boot.test.json.DuplicateJsonObjectContextCustomizerFactory$DuplicateJsonObjectContextCustomizer@379614be, org.springframework.boot.test.mock.mockito.MockitoContextCustomizer@0, org.springframework.boot.test.web.client.TestRestTemplateContextCustomizer@14fa86ae, org.springframework.boot.test.autoconfigure.actuate.metrics.MetricsExportContextCustomizerFactory$DisableMetricExportContextCustomizer@398dada8, org.springframework.boot.test.autoconfigure.properties.PropertyMappingContextCustomizer@0, org.springframework.boot.test.autoconfigure.web.servlet.WebDriverContextCustomizerFactory$Customizer@4066c471, org.springframework.boot.test.context.SpringBootTestArgs@1, org.springframework.boot.test.context.SpringBootTestWebEnvironment@65466a6a], contextLoader = 'org.springframework.boot.test.context.SpringBootContextLoader', parent = [null]], attributes = map['org.springframework.test.context.event.ApplicationEventsTestExecutionListener.recordApplicationEvents' -> false]]
It rolled back, but the repository apparently has its own transaction, which did the job then closes, is that the issue?