This repository has been archived on 2020-08-02. You can view files and clone it, but cannot push or open issues or pull requests.
e-commerce/web_backend/src/main/java/org/hso/ecommerce/controller/cronjob/CronjobController.java

202 lines
7.7 KiB
Java

package org.hso.ecommerce.controller.cronjob;
import org.hso.ecommerce.entities.cron.BackgroundJob;
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository;
import org.hso.ecommerce.repos.booking.BookingRepository;
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository;
import org.hso.ecommerce.repos.dashboard.DashboardSummaryRepository;
import org.hso.ecommerce.repos.shop.ArticleRepository;
import org.hso.ecommerce.repos.shop.CustomerOrderRepository;
import org.hso.ecommerce.repos.supplier.ArticleOfferRepository;
import org.hso.ecommerce.repos.supplier.SupplierOrderRepository;
import org.hso.ecommerce.repos.supplier.SupplierRepository;
import org.hso.ecommerce.repos.warehouse.WarehouseBookingPositionSlotEntryRepository;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.PostConstruct;
import java.sql.Timestamp;
import java.util.*;
import java.util.Map.Entry;
@Component
@RequestMapping("intern/cronjobs")
class CronjobController {
private static final Logger log = LoggerFactory.getLogger(CronjobController.class);
private Map<String, ICronjob> cronjobs;
@Autowired
private final BackgroundJobRepository cronjobRepository = null;
@Autowired
final ArticleRepository articleRepository = null;
@Autowired
final ArticleOfferRepository articleOfferRepository = null;
@Autowired
final CustomerOrderRepository customerOrderRepository = null;
@Autowired
final BookingRepository bookingRepository = null;
@Autowired
final BookingAccountEntryRepository bookingAccountEntryRepository = null;
@Autowired
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null;
@Autowired
final DashboardSummaryRepository dashboardSummaryRepository = null;
@Autowired
final SupplierRepository supplierRepository = null;
@Autowired
final SupplierOrderRepository supplierOrderRepository = null;
@Autowired
final Reorder reorderJob = null;
@Autowired
final DashboardCronjob dashboardCronjob = null;
@Autowired
final AutoSupplierPayment autoSupplierPaymentJob = null;
@PostConstruct
public void init() {
cronjobs = getCronjobs();
}
private Map<String, ICronjob> getCronjobs() {
HashMap<String, ICronjob> map = new HashMap<>();
// Register all existing cronjobs
map.put(BackgroundJob.JOB_REORDER, reorderJob);
map.put(BackgroundJob.JOB_DASHBOARD, dashboardCronjob);
map.put(BackgroundJob.JOB_SUPPLIER_AUTO_PAYMENT, autoSupplierPaymentJob);
return Collections.unmodifiableMap(map);
}
private ScheduledCronjob getNextCronjob() {
Calendar currentTime = new GregorianCalendar();
Iterable<BackgroundJob> jobs = cronjobRepository.findAll();
HashMap<String, BackgroundJob> alreadyExecuted = new HashMap<>();
for (BackgroundJob job : jobs) {
alreadyExecuted.put(job.jobName, job);
}
ScheduledCronjob earliestJob = null;
for (Entry<String, ICronjob> entry : cronjobs.entrySet()) {
ScheduledCronjob resultingJob;
BackgroundJob dbEntry = alreadyExecuted.get(entry.getKey());
if (dbEntry != null) {
Calendar previousExecution = new GregorianCalendar();
previousExecution.setTimeInMillis(dbEntry.lastExecution.getTime());
Calendar followingSchedule = entry.getValue().nextExecution((Calendar) previousExecution.clone());
Calendar lastSchedule = entry.getValue().previousExecution((Calendar) currentTime.clone());
if (lastSchedule.getTimeInMillis() > followingSchedule.getTimeInMillis()) {
// This happens, if more than one execution was missed.
// In this case, run the job only once.
followingSchedule = lastSchedule;
}
resultingJob = new ScheduledCronjob(followingSchedule, entry.getValue(), dbEntry);
} else {
// This cronjob has never been executed before.
Calendar lastScheduleTime = entry.getValue().previousExecution((Calendar) currentTime.clone());
BackgroundJob model = new BackgroundJob();
model.jobName = entry.getKey();
resultingJob = new ScheduledCronjob(lastScheduleTime, entry.getValue(), model);
}
// Look for the job with earliest executionTime - it will run next
if (earliestJob == null
|| resultingJob.executionTime.getTimeInMillis() < earliestJob.executionTime.getTimeInMillis()) {
earliestJob = resultingJob;
}
}
return earliestJob;
}
private void runCronjobExecutionLoop() {
Thread.currentThread().setName("Cronjob");
try {
while (true) {
ScheduledCronjob nextJob = getNextCronjob();
if (nextJob == null) {
// In case there are no cronjobs
return;
}
long waitingTime = nextJob.executionTime.getTimeInMillis() - System.currentTimeMillis();
if (waitingTime > 0) {
Thread.sleep(waitingTime);
}
try {
nextJob.cronjob.executeAt(nextJob.executionTime, this);
} catch (Throwable t) {
log.error("Failed to execute cronjob " + nextJob.cronjob.getClass() + ":");
t.printStackTrace();
}
nextJob.model.lastExecution = new Timestamp(nextJob.executionTime.getTimeInMillis());
cronjobRepository.save(nextJob.model);
}
} catch (InterruptedException e) {
log.error("The cronjob execution thread has been interrupted");
}
}
@PostConstruct
public void onPostConstruct() {
new Thread(this::runCronjobExecutionLoop).start();
}
class ManualCronjob {
public final String identifier;
public final String visibleName;
public ManualCronjob(String identifier, String visibleName) {
this.identifier = identifier;
this.visibleName = visibleName;
}
}
private List<ManualCronjob> listAllCronjobs() {
ArrayList<ManualCronjob> entries = new ArrayList<>();
for (Entry<String, ICronjob> job : cronjobs.entrySet()) {
entries.add(new ManualCronjob(job.getKey(), job.getValue().getDisplayName()));
}
return entries;
}
@GetMapping("/")
public String cronjobOverview(Model model) {
model.addAttribute("jobs", listAllCronjobs());
return "intern/cronjobs/index";
}
@PostMapping("/run/{identifier}")
public String runCronjob(Model model, @PathVariable("identifier") String identifier) {
ICronjob jobToExecute = cronjobs.get(identifier);
if (jobToExecute != null) {
jobToExecute.executeAt(new GregorianCalendar(), this);
model.addAttribute("info",
String.format("Der Cronjob \"%s\" wurde ausgeführt.", jobToExecute.getDisplayName()));
} else {
model.addAttribute("error", "Der Cronjob konnte nicht gefunden werden.");
}
model.addAttribute("jobs", listAllCronjobs());
return "intern/cronjobs/index";
}
}