Enable creating an API using Spring Web #5
@ -6,7 +6,7 @@ import se.su.dsv.scipro.file.FileDescription;
|
|||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
class PrintingMailer implements Mailer {
|
public class PrintingMailer implements Mailer {
|
||||||
@Override
|
@Override
|
||||||
public MailResult mail(final String fromName, final String fromEmail, final String[] recipients, final String subject, final String message, final FileDescription attachment) {
|
public MailResult mail(final String fromName, final String fromEmail, final String[] recipients, final String subject, final String message, final FileDescription attachment) {
|
||||||
return new MailResult() {
|
return new MailResult() {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
package se.su.dsv.scipro.match;
|
package se.su.dsv.scipro.match;
|
||||||
|
|
||||||
class AllowAllIdeaCreationJudge implements IdeaCreationJudge {
|
public class AllowAllIdeaCreationJudge implements IdeaCreationJudge {
|
||||||
@Override
|
@Override
|
||||||
public Decision ruling(Idea idea) {
|
public Decision ruling(Idea idea) {
|
||||||
return Decision.allowed();
|
return Decision.allowed();
|
||||||
|
@ -22,8 +22,7 @@ public abstract class AbstractWorker implements Worker {
|
|||||||
private WorkerData wd = null;
|
private WorkerData wd = null;
|
||||||
private Date lastSuccessfulRun = new Date(0);
|
private Date lastSuccessfulRun = new Date(0);
|
||||||
private boolean successfulWorker = true;
|
private boolean successfulWorker = true;
|
||||||
private Provider<EntityManager> emProvider;
|
private WorkerTransactionManager txManager;
|
||||||
private EntityTransaction transaction;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Subclasses must be annotated with @Component or similar annotation in order for autowiring of dependencies to work
|
* Subclasses must be annotated with @Component or similar annotation in order for autowiring of dependencies to work
|
||||||
@ -37,16 +36,13 @@ public abstract class AbstractWorker implements Worker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public void setTxManager(Provider<EntityManager> em) {
|
public void setTxManager(WorkerTransactionManager txManager) {
|
||||||
this.emProvider = em;
|
this.txManager = txManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
EntityManager em = emProvider.get();
|
|
||||||
try {
|
try {
|
||||||
transaction = em.getTransaction();
|
|
||||||
|
|
||||||
wd = workerDataService.getWorkerDataByName(getName());
|
wd = workerDataService.getWorkerDataByName(getName());
|
||||||
if (wd != null) {
|
if (wd != null) {
|
||||||
lastSuccessfulRun = wd.getLastSuccessfulRun();
|
lastSuccessfulRun = wd.getLastSuccessfulRun();
|
||||||
@ -72,9 +68,7 @@ public abstract class AbstractWorker implements Worker {
|
|||||||
setSuccessfulWorker(false);
|
setSuccessfulWorker(false);
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
if (transaction.isActive() && em.isOpen()) {
|
txManager.rollbackIfActive();
|
||||||
transaction.rollback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// in case a job crashes or clears the cache (so the entity is detached)
|
// in case a job crashes or clears the cache (so the entity is detached)
|
||||||
@ -87,9 +81,7 @@ public abstract class AbstractWorker implements Worker {
|
|||||||
saveWorkerData();
|
saveWorkerData();
|
||||||
|
|
||||||
} finally {
|
} finally {
|
||||||
if (transaction.isActive() && em.isOpen()) {
|
txManager.rollbackIfActive();
|
||||||
transaction.rollback();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -139,15 +131,15 @@ public abstract class AbstractWorker implements Worker {
|
|||||||
protected abstract void doWork();
|
protected abstract void doWork();
|
||||||
|
|
||||||
protected void beginTransaction() {
|
protected void beginTransaction() {
|
||||||
transaction.begin();
|
txManager.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void commitTransaction() {
|
protected void commitTransaction() {
|
||||||
transaction.commit();
|
txManager.commit();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void rollbackTransaction() {
|
protected void rollbackTransaction() {
|
||||||
transaction.rollback();
|
txManager.rollback();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,9 @@ public class WorkerModule extends AbstractModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void configure() {
|
protected void configure() {
|
||||||
Multibinder.newSetBinder(binder(), Lifecycle.class).addBinding().to(SchedulerImpl.class);
|
//Multibinder.newSetBinder(binder(), Lifecycle.class).addBinding().to(SchedulerImpl.class);
|
||||||
bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS));
|
bind(ScheduledExecutorService.class).toInstance(Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS));
|
||||||
bind(Scheduler.class).to(SchedulerImpl.class).in(Scopes.SINGLETON);
|
//bind(Scheduler.class).to(SchedulerImpl.class).in(Scopes.SINGLETON);
|
||||||
bind(TemporaryWorkerScheduler.class).asEagerSingleton();
|
bind(TemporaryWorkerScheduler.class).asEagerSingleton();
|
||||||
bind(WorkerDataService.class).to(WorkerDataServiceImpl.class);
|
bind(WorkerDataService.class).to(WorkerDataServiceImpl.class);
|
||||||
bind(ThesisUploadDeadlineWorker.class);
|
bind(ThesisUploadDeadlineWorker.class);
|
||||||
|
@ -0,0 +1,20 @@
|
|||||||
|
package se.su.dsv.scipro.workerthreads;
|
||||||
|
|
||||||
|
public interface WorkerTransactionManager {
|
||||||
|
void rollbackIfActive();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException if a transaction is already active
|
||||||
|
*/
|
||||||
|
void begin();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException if a transaction is not active
|
||||||
|
*/
|
||||||
|
void commit();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @throws IllegalStateException if a transaction is not active
|
||||||
|
*/
|
||||||
|
void rollback();
|
||||||
|
}
|
@ -1,10 +1,6 @@
|
|||||||
package se.su.dsv.scipro.integration.daisy.workers;
|
package se.su.dsv.scipro.integration.daisy.workers;
|
||||||
|
|
||||||
import com.google.common.eventbus.EventBus;
|
import com.google.common.eventbus.EventBus;
|
||||||
import com.google.inject.persist.UnitOfWork;
|
|
||||||
import com.google.inject.util.Providers;
|
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@ -23,6 +19,7 @@ import se.su.dsv.scipro.system.User;
|
|||||||
import se.su.dsv.scipro.system.UserService;
|
import se.su.dsv.scipro.system.UserService;
|
||||||
import se.su.dsv.scipro.workerthreads.WorkerData;
|
import se.su.dsv.scipro.workerthreads.WorkerData;
|
||||||
import se.su.dsv.scipro.workerthreads.WorkerDataService;
|
import se.su.dsv.scipro.workerthreads.WorkerDataService;
|
||||||
|
import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
@ -47,21 +44,16 @@ public class GradingCompletedMilestoneActivatorTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private EventBus eventBus;
|
private EventBus eventBus;
|
||||||
@Mock
|
@Mock
|
||||||
private UnitOfWork unitOfWork;
|
private WorkerTransactionManager workerTransactionManager;
|
||||||
@Mock
|
|
||||||
private EntityManager entityManager;
|
|
||||||
@Mock
|
|
||||||
private EntityTransaction entityTransaction;
|
|
||||||
@Mock
|
@Mock
|
||||||
private WorkerDataService workerDataService;
|
private WorkerDataService workerDataService;
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
gradingCompletedMilestoneActivator = new GradingCompletedMilestoneActivator(projectService, daisyAPI, eventBus, userService);
|
gradingCompletedMilestoneActivator = new GradingCompletedMilestoneActivator(projectService, daisyAPI, eventBus, userService);
|
||||||
gradingCompletedMilestoneActivator.setTxManager(Providers.of(entityManager));
|
gradingCompletedMilestoneActivator.setTxManager(workerTransactionManager);
|
||||||
gradingCompletedMilestoneActivator.setWorkerDataService(workerDataService);
|
gradingCompletedMilestoneActivator.setWorkerDataService(workerDataService);
|
||||||
when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
|
when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
|
||||||
when(entityManager.getTransaction()).thenReturn(entityTransaction);
|
|
||||||
|
|
||||||
project.setId(3493L);
|
project.setId(3493L);
|
||||||
project.setIdentifier(234);
|
project.setIdentifier(234);
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
package se.su.dsv.scipro.integration.daisy.workers;
|
package se.su.dsv.scipro.integration.daisy.workers;
|
||||||
|
|
||||||
import com.google.inject.persist.UnitOfWork;
|
|
||||||
import com.google.inject.util.Providers;
|
|
||||||
import com.querydsl.core.types.Predicate;
|
import com.querydsl.core.types.Predicate;
|
||||||
import jakarta.persistence.EntityManager;
|
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@ -26,6 +22,7 @@ import se.su.dsv.scipro.system.Unit;
|
|||||||
import se.su.dsv.scipro.system.User;
|
import se.su.dsv.scipro.system.User;
|
||||||
import se.su.dsv.scipro.workerthreads.WorkerData;
|
import se.su.dsv.scipro.workerthreads.WorkerData;
|
||||||
import se.su.dsv.scipro.workerthreads.WorkerDataService;
|
import se.su.dsv.scipro.workerthreads.WorkerDataService;
|
||||||
|
import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
|
||||||
|
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
@ -45,10 +42,8 @@ public class ProjectExporterTest {
|
|||||||
private @Mock ExporterFacade exporterFacade;
|
private @Mock ExporterFacade exporterFacade;
|
||||||
private @Mock DaisyAPI daisyAPI;
|
private @Mock DaisyAPI daisyAPI;
|
||||||
private @Mock ExternalExporter externalExporter;
|
private @Mock ExternalExporter externalExporter;
|
||||||
private @Mock EntityManager entityManager;
|
private @Mock WorkerTransactionManager workerTransactionManager;
|
||||||
private @Mock EntityTransaction entityTransaction;
|
|
||||||
private @Mock WorkerDataService workerDataService;
|
private @Mock WorkerDataService workerDataService;
|
||||||
private @Mock UnitOfWork unitOfWork;
|
|
||||||
private @Mock FinalSeminarService finalSeminarService;
|
private @Mock FinalSeminarService finalSeminarService;
|
||||||
private @Mock FinalThesisService finalThesisService;
|
private @Mock FinalThesisService finalThesisService;
|
||||||
|
|
||||||
@ -61,10 +56,9 @@ public class ProjectExporterTest {
|
|||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
projectExporter = new ProjectExporter(projectRepo, exporterFacade, daisyAPI, externalExporter, finalSeminarService, finalThesisService);
|
projectExporter = new ProjectExporter(projectRepo, exporterFacade, daisyAPI, externalExporter, finalSeminarService, finalThesisService);
|
||||||
projectExporter.setTxManager(Providers.of(entityManager));
|
projectExporter.setTxManager(workerTransactionManager);
|
||||||
projectExporter.setWorkerDataService(workerDataService);
|
projectExporter.setWorkerDataService(workerDataService);
|
||||||
when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
|
when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
|
||||||
when(entityManager.getTransaction()).thenReturn(entityTransaction);
|
|
||||||
|
|
||||||
Unit unit = new Unit();
|
Unit unit = new Unit();
|
||||||
unit.setIdentifier(239478);
|
unit.setIdentifier(239478);
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
package se.su.dsv.scipro.integration.daisy.workers;
|
package se.su.dsv.scipro.integration.daisy.workers;
|
||||||
|
|
||||||
import com.google.inject.persist.UnitOfWork;
|
|
||||||
import com.google.inject.util.Providers;
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
@ -18,8 +16,8 @@ import se.su.dsv.scipro.project.QProject;
|
|||||||
import se.su.dsv.scipro.workerthreads.WorkerData;
|
import se.su.dsv.scipro.workerthreads.WorkerData;
|
||||||
import se.su.dsv.scipro.workerthreads.WorkerDataService;
|
import se.su.dsv.scipro.workerthreads.WorkerDataService;
|
||||||
|
|
||||||
import jakarta.persistence.EntityManager;
|
import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
|
||||||
import jakarta.persistence.EntityTransaction;
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -38,9 +36,7 @@ public class ProjectFinalizerTest {
|
|||||||
|
|
||||||
private @Mock DaisyAPI daisyAPI;
|
private @Mock DaisyAPI daisyAPI;
|
||||||
private @Mock ProjectService projectService;
|
private @Mock ProjectService projectService;
|
||||||
private @Mock UnitOfWork unitOfWork;
|
private @Mock WorkerTransactionManager workerTransactionManager;
|
||||||
private @Mock EntityManager entityManager;
|
|
||||||
private @Mock EntityTransaction entityTransaction;
|
|
||||||
private @Mock WorkerDataService workerDataService;
|
private @Mock WorkerDataService workerDataService;
|
||||||
private @Mock ThesisApprovedHistoryService thesisApprovedHistoryService;
|
private @Mock ThesisApprovedHistoryService thesisApprovedHistoryService;
|
||||||
|
|
||||||
@ -48,10 +44,9 @@ public class ProjectFinalizerTest {
|
|||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setup() {
|
public void setup() {
|
||||||
projectFinalizer = new ProjectFinalizer(projectService, daisyAPI, thesisApprovedHistoryService);
|
projectFinalizer = new ProjectFinalizer(projectService, daisyAPI, thesisApprovedHistoryService);
|
||||||
projectFinalizer.setTxManager(Providers.of(entityManager));
|
projectFinalizer.setTxManager(workerTransactionManager);
|
||||||
projectFinalizer.setWorkerDataService(workerDataService);
|
projectFinalizer.setWorkerDataService(workerDataService);
|
||||||
when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
|
when(workerDataService.save(any(WorkerData.class))).thenReturn(new WorkerData());
|
||||||
when(entityManager.getTransaction()).thenReturn(entityTransaction);
|
|
||||||
|
|
||||||
project.setId(3493L);
|
project.setId(3493L);
|
||||||
project.setIdentifier(234);
|
project.setIdentifier(234);
|
||||||
|
@ -21,8 +21,6 @@ import se.su.dsv.scipro.sukat.LDAP;
|
|||||||
import se.su.dsv.scipro.sukat.Sukat;
|
import se.su.dsv.scipro.sukat.Sukat;
|
||||||
|
|
||||||
import java.time.Clock;
|
import java.time.Clock;
|
||||||
import java.util.concurrent.Executors;
|
|
||||||
import java.util.concurrent.ScheduledExecutorService;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@ComponentScan(
|
@ComponentScan(
|
||||||
@ -34,13 +32,6 @@ import java.util.concurrent.ScheduledExecutorService;
|
|||||||
".*GradingServiceImpl"
|
".*GradingServiceImpl"
|
||||||
}))
|
}))
|
||||||
public class CoreConfig {
|
public class CoreConfig {
|
||||||
private static final int NUMBER_OF_WORKER_THREADS = 4;
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ScheduledExecutorService scheduledExecutorService() {
|
|
||||||
return Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public EventBus eventBus() {
|
public EventBus eventBus() {
|
||||||
return new EventBus();
|
return new EventBus();
|
||||||
|
45
war/src/main/java/se/su/dsv/scipro/war/MailConfig.java
Normal file
45
war/src/main/java/se/su/dsv/scipro/war/MailConfig.java
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
package se.su.dsv.scipro.war;
|
||||||
|
|
||||||
|
import jakarta.mail.Session;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import se.su.dsv.scipro.data.facade.MailFacade;
|
||||||
|
import se.su.dsv.scipro.file.FileService;
|
||||||
|
import se.su.dsv.scipro.generalsystemsettings.GeneralSystemSettingsService;
|
||||||
|
import se.su.dsv.scipro.mail.Mail;
|
||||||
|
import se.su.dsv.scipro.mail.Mailer;
|
||||||
|
import se.su.dsv.scipro.mail.PrintingMailer;
|
||||||
|
import se.su.dsv.scipro.mail.RedirectingMailer;
|
||||||
|
import se.su.dsv.scipro.profiles.CurrentProfile;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class MailConfig {
|
||||||
|
@Bean
|
||||||
|
public MailFacade mailFacade() {
|
||||||
|
return new MailFacade();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Mailer mailer(
|
||||||
|
CurrentProfile currentProfile,
|
||||||
|
Session session,
|
||||||
|
FileService fileDescriptionService)
|
||||||
|
{
|
||||||
|
return switch (currentProfile.getCurrentProfile()) {
|
||||||
|
case DEV -> new PrintingMailer();
|
||||||
|
case PROD -> new Mail(session, fileDescriptionService);
|
||||||
|
case TEST -> new RedirectingMailer(session, "scipro-mailtest@dsv.su.se", fileDescriptionService);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public Session session(GeneralSystemSettingsService generalSystemSettings) {
|
||||||
|
String smtpHost = generalSystemSettings.getGeneralSystemSettingsInstance().getSmtpServer();
|
||||||
|
Properties properties = new Properties();
|
||||||
|
properties.setProperty("mail.smtp.host", smtpHost);
|
||||||
|
properties.setProperty("mail.smtp.sendpartial", Boolean.toString(true));
|
||||||
|
return Session.getDefaultInstance(properties);
|
||||||
|
}
|
||||||
|
}
|
@ -37,7 +37,7 @@ import java.util.Set;
|
|||||||
|
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EntityScan("se.su.dsv.scipro")
|
@EntityScan("se.su.dsv.scipro")
|
||||||
@Import({CoreConfig.class, ApiConfig.class})
|
@Import({CoreConfig.class, ApiConfig.class, WorkerConfig.class, MailConfig.class})
|
||||||
public class Main extends SpringBootServletInitializer implements ServletContainerInitializer {
|
public class Main extends SpringBootServletInitializer implements ServletContainerInitializer {
|
||||||
@Override
|
@Override
|
||||||
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
|
public void onStartup(Set<Class<?>> c, ServletContext ctx) throws ServletException {
|
||||||
|
@ -0,0 +1,50 @@
|
|||||||
|
package se.su.dsv.scipro.war;
|
||||||
|
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import org.springframework.transaction.TransactionDefinition;
|
||||||
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
|
||||||
|
|
||||||
|
public class SpringManagedWorkerTransactions implements WorkerTransactionManager {
|
||||||
|
private final PlatformTransactionManager platformTransactionManager;
|
||||||
|
|
||||||
|
private TransactionStatus activeTransaction;
|
||||||
|
|
||||||
|
public SpringManagedWorkerTransactions(PlatformTransactionManager platformTransactionManager) {
|
||||||
|
this.platformTransactionManager = platformTransactionManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollbackIfActive() {
|
||||||
|
if (this.activeTransaction != null) {
|
||||||
|
platformTransactionManager.rollback(this.activeTransaction);
|
||||||
|
this.activeTransaction = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void begin() {
|
||||||
|
if (this.activeTransaction != null) {
|
||||||
|
throw new IllegalStateException("A transaction is already active");
|
||||||
|
}
|
||||||
|
this.activeTransaction = platformTransactionManager.getTransaction(TransactionDefinition.withDefaults());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void commit() {
|
||||||
|
if (this.activeTransaction == null) {
|
||||||
|
throw new IllegalStateException("A transaction is not active");
|
||||||
|
}
|
||||||
|
platformTransactionManager.commit(this.activeTransaction);
|
||||||
|
this.activeTransaction = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void rollback() {
|
||||||
|
if (this.activeTransaction == null) {
|
||||||
|
throw new IllegalStateException("A transaction is not active");
|
||||||
|
}
|
||||||
|
platformTransactionManager.rollback(this.activeTransaction);
|
||||||
|
this.activeTransaction = null;
|
||||||
|
}
|
||||||
|
}
|
94
war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java
Normal file
94
war/src/main/java/se/su/dsv/scipro/war/WorkerConfig.java
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
package se.su.dsv.scipro.war;
|
||||||
|
|
||||||
|
import jakarta.inject.Provider;
|
||||||
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.ComponentScan;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.context.annotation.FilterType;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
import se.su.dsv.scipro.file.FileService;
|
||||||
|
import se.su.dsv.scipro.mail.MailEventWorker;
|
||||||
|
import se.su.dsv.scipro.match.AllowAllIdeaCreationJudge;
|
||||||
|
import se.su.dsv.scipro.match.IdeaCreationJudge;
|
||||||
|
import se.su.dsv.scipro.plagiarism.PlagiarismRequestRepository;
|
||||||
|
import se.su.dsv.scipro.plagiarism.PlagiarismSubmitter;
|
||||||
|
import se.su.dsv.scipro.plagiarism.urkund.StatusPollingWorker;
|
||||||
|
import se.su.dsv.scipro.plagiarism.urkund.UrkundService;
|
||||||
|
import se.su.dsv.scipro.plagiarism.urkund.UrkundSettings;
|
||||||
|
import se.su.dsv.scipro.plagiarism.urkund.UrkundSettingsRepository;
|
||||||
|
import se.su.dsv.scipro.projectpartner.RemoveFulfilledPartnerAdsWorker;
|
||||||
|
import se.su.dsv.scipro.reviewing.ReviewerDecisionReminderWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.GradeFinalSeminarParticipantReminderWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.IdeaExportWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.ManualMatchRemindWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.NotificationCompilationWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.Scheduler;
|
||||||
|
import se.su.dsv.scipro.workerthreads.TemporaryWorkerScheduler;
|
||||||
|
import se.su.dsv.scipro.workerthreads.ThesisUploadDeadlineWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.ThesisUploadReminderWorker;
|
||||||
|
import se.su.dsv.scipro.workerthreads.WorkerTransactionManager;
|
||||||
|
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
@ComponentScan(
|
||||||
|
basePackages = "se.su.dsv.scipro",
|
||||||
|
includeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*Worker$"),
|
||||||
|
excludeFilters = @ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*[Dd]aisy.*")
|
||||||
|
)
|
||||||
|
public class WorkerConfig {
|
||||||
|
private static final int NUMBER_OF_WORKER_THREADS = 4;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ScheduledExecutorService scheduledExecutorService() {
|
||||||
|
return Executors.newScheduledThreadPool(NUMBER_OF_WORKER_THREADS);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public TemporaryWorkerScheduler temporaryWorkerScheduler(
|
||||||
|
Scheduler scheduler,
|
||||||
|
Provider<MailEventWorker> mailEventWorker,
|
||||||
|
Provider<NotificationCompilationWorker> notificationCompilationWorker,
|
||||||
|
Provider<IdeaExportWorker> ideaExportWorker,
|
||||||
|
Provider<ThesisUploadReminderWorker> thesisUploadReminderWorker,
|
||||||
|
Provider<ThesisUploadDeadlineWorker> thesisUploadDeadlineWorker,
|
||||||
|
Provider<ManualMatchRemindWorker> manualMatchRemindWorkerProvider,
|
||||||
|
Provider<ReviewerDecisionReminderWorker> reviewerDecisionReminderWorker,
|
||||||
|
Provider<PlagiarismSubmitter> plagiarismSubmitter,
|
||||||
|
Provider<StatusPollingWorker> urkundPoller,
|
||||||
|
Provider<RemoveFulfilledPartnerAdsWorker> removeFulfilledPartnerAds,
|
||||||
|
Provider<GradeFinalSeminarParticipantReminderWorker> gradeFinalSeminarParticipantReminderWorkerProvider)
|
||||||
|
{
|
||||||
|
return new TemporaryWorkerScheduler(scheduler, mailEventWorker, notificationCompilationWorker, ideaExportWorker, thesisUploadReminderWorker, thesisUploadDeadlineWorker, manualMatchRemindWorkerProvider, reviewerDecisionReminderWorker, plagiarismSubmitter, urkundPoller, removeFulfilledPartnerAds, gradeFinalSeminarParticipantReminderWorkerProvider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@ConditionalOnMissingBean(IdeaCreationJudge.class)
|
||||||
|
public IdeaCreationJudge ideaCreationJudge() {
|
||||||
|
return new AllowAllIdeaCreationJudge();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public PlagiarismSubmitter plagiarismSubmitter(
|
||||||
|
Provider<UrkundSettings> urkundSettings,
|
||||||
|
PlagiarismRequestRepository plagiarismRequestRepository,
|
||||||
|
UrkundService urkundService,
|
||||||
|
FileService fileService)
|
||||||
|
{
|
||||||
|
return new PlagiarismSubmitter(urkundSettings, plagiarismRequestRepository, urkundService, fileService);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public UrkundSettings urkundSettings(UrkundSettingsRepository urkundSettingsRepository) {
|
||||||
|
return urkundSettingsRepository.getSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Scope("prototype")
|
||||||
|
public WorkerTransactionManager workerTransactionManager(PlatformTransactionManager platformTransactionManager) {
|
||||||
|
return new SpringManagedWorkerTransactions(platformTransactionManager);
|
||||||
|
}
|
||||||
|
}
|
@ -1,12 +1,24 @@
|
|||||||
package se.su.dsv.scipro.workerthreads;
|
package se.su.dsv.scipro.workerthreads;
|
||||||
|
|
||||||
|
import jakarta.persistence.EntityManager;
|
||||||
|
import jakarta.persistence.EntityManagerFactory;
|
||||||
|
import jakarta.servlet.FilterChain;
|
||||||
ansv7779 marked this conversation as resolved
Outdated
|
|||||||
|
import jakarta.servlet.ServletException;
|
||||||
|
import jakarta.servlet.ServletRequest;
|
||||||
|
import jakarta.servlet.ServletResponse;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.orm.jpa.EntityManagerFactoryUtils;
|
||||||
|
import org.springframework.orm.jpa.EntityManagerHolder;
|
||||||
|
import org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter;
|
||||||
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import se.su.dsv.scipro.system.Lifecycle;
|
import se.su.dsv.scipro.system.Lifecycle;
|
||||||
|
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.inject.Provider;
|
import jakarta.inject.Provider;
|
||||||
import jakarta.inject.Singleton;
|
import jakarta.inject.Singleton;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
@ -19,13 +31,15 @@ public class SchedulerImpl implements Lifecycle, Scheduler {
|
|||||||
private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerImpl.class);
|
private static final Logger LOGGER = LoggerFactory.getLogger(SchedulerImpl.class);
|
||||||
|
|
||||||
private final ScheduledExecutorService scheduledExecutorService;
|
private final ScheduledExecutorService scheduledExecutorService;
|
||||||
|
private final EntityManagerFactory emf;
|
||||||
|
|
||||||
private final Set<Task> tasks = new TreeSet<>(new Task.ByDescriptionComparator());
|
private final Set<Task> tasks = new TreeSet<>(new Task.ByDescriptionComparator());
|
||||||
private final Set<Task> runningWorkers = Collections.synchronizedSet(new HashSet<>());
|
private final Set<Task> runningWorkers = Collections.synchronizedSet(new HashSet<>());
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
public SchedulerImpl(ScheduledExecutorService scheduledExecutorService) {
|
public SchedulerImpl(ScheduledExecutorService scheduledExecutorService, EntityManagerFactory emf) {
|
||||||
this.scheduledExecutorService = scheduledExecutorService;
|
this.scheduledExecutorService = scheduledExecutorService;
|
||||||
|
this.emf = emf;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -43,6 +57,14 @@ public class SchedulerImpl implements Lifecycle, Scheduler {
|
|||||||
private Runnable tracked(final Task task) {
|
private Runnable tracked(final Task task) {
|
||||||
return () -> {
|
return () -> {
|
||||||
try {
|
try {
|
||||||
|
// Since we're not in a web request when running a scheduled job, Spring's OpenEntityManagerInView
|
||||||
|
// filter is not active. Therefore, we need to manually bind a new EntityManager to the current thread
|
||||||
|
// to be shared by all DAOs. If we do not, we will get problems with detached entity passed to persist
|
||||||
|
// since every read and write from the database will be in a new EntityManager.
|
||||||
|
EntityManager em = emf.createEntityManager();
|
||||||
|
EntityManagerHolder emHolder = new EntityManagerHolder(em);
|
||||||
|
TransactionSynchronizationManager.bindResource(emf, emHolder);
|
||||||
|
|
||||||
runningWorkers.add(task);
|
runningWorkers.add(task);
|
||||||
task.execute();
|
task.execute();
|
||||||
}
|
}
|
||||||
@ -51,6 +73,11 @@ public class SchedulerImpl implements Lifecycle, Scheduler {
|
|||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
runningWorkers.remove(task);
|
runningWorkers.remove(task);
|
||||||
|
|
||||||
|
// Clean up the shared EntityManager
|
||||||
|
EntityManagerHolder emHolder = (EntityManagerHolder)
|
||||||
|
TransactionSynchronizationManager.unbindResource(emf);
|
||||||
|
EntityManagerFactoryUtils.closeEntityManager(emHolder.getEntityManager());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user
Clean up unused imports