2020-05-15 13:47:54 +02:00
package org.hso.ecommerce.controller.cronjob ;
import org.hso.ecommerce.entities.cron.BackgroundJob ;
2020-05-25 17:08:15 +02:00
import org.hso.ecommerce.repos.booking.BookingAccountEntryRepository ;
import org.hso.ecommerce.repos.booking.BookingRepository ;
2020-05-15 13:47:54 +02:00
import org.hso.ecommerce.repos.cronjob.BackgroundJobRepository ;
2020-06-15 17:47:55 +02:00
import org.hso.ecommerce.repos.dashboard.DashboardSummaryRepository ;
2020-05-25 17:08:15 +02:00
import org.hso.ecommerce.repos.shop.ArticleRepository ;
2020-06-01 20:24:59 +02:00
import org.hso.ecommerce.repos.shop.CustomerOrderRepository ;
2020-05-25 17:08:15 +02:00
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 ;
2020-05-15 13:47:54 +02:00
import org.slf4j.Logger ;
import org.slf4j.LoggerFactory ;
import org.springframework.beans.factory.annotation.Autowired ;
import org.springframework.stereotype.Component ;
2020-06-15 16:23:42 +02:00
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 ;
2020-05-15 13:47:54 +02:00
2020-06-15 17:47:55 +02:00
import javax.annotation.PostConstruct ;
import java.sql.Timestamp ;
import java.util.* ;
import java.util.Map.Entry ;
2020-05-15 13:47:54 +02:00
@Component
2020-06-15 16:23:42 +02:00
@RequestMapping ( " intern/cronjobs " )
2020-05-15 13:47:54 +02:00
class CronjobController {
private static final Logger log = LoggerFactory . getLogger ( CronjobController . class ) ;
2020-06-21 15:50:27 +02:00
private Map < String , ICronjob > cronjobs ;
2020-05-15 13:47:54 +02:00
@Autowired
private final BackgroundJobRepository cronjobRepository = null ;
2020-05-25 17:08:15 +02:00
@Autowired
final ArticleRepository articleRepository = null ;
@Autowired
final ArticleOfferRepository articleOfferRepository = null ;
@Autowired
2020-06-01 20:24:59 +02:00
final CustomerOrderRepository customerOrderRepository = null ;
2020-05-25 17:08:15 +02:00
@Autowired
final BookingRepository bookingRepository = null ;
@Autowired
final BookingAccountEntryRepository bookingAccountEntryRepository = null ;
@Autowired
final WarehouseBookingPositionSlotEntryRepository warehouseBookingPositionSlotEntryRepository = null ;
2020-06-15 17:47:55 +02:00
@Autowired
final DashboardSummaryRepository dashboardSummaryRepository = null ;
2020-05-25 17:08:15 +02:00
@Autowired
final SupplierRepository supplierRepository = null ;
@Autowired
final SupplierOrderRepository supplierOrderRepository = null ;
2020-06-15 17:47:55 +02:00
@Autowired
2020-06-21 15:50:27 +02:00
final Reorder reorderJob = null ;
@Autowired
final DashboardCronjob dashboardCronjob = null ;
@Autowired
2020-06-21 19:01:25 +02:00
final AutoSupplierPayment autoSupplierPaymentJob = null ;
2020-06-21 15:50:27 +02:00
@PostConstruct
public void init ( ) {
cronjobs = getCronjobs ( ) ;
}
2020-06-15 17:47:55 +02:00
2020-06-21 15:50:27 +02:00
private Map < String , ICronjob > getCronjobs ( ) {
2020-05-15 13:47:54 +02:00
HashMap < String , ICronjob > map = new HashMap < > ( ) ;
// Register all existing cronjobs
2020-06-21 15:50:27 +02:00
map . put ( BackgroundJob . JOB_REORDER , reorderJob ) ;
map . put ( BackgroundJob . JOB_DASHBOARD , dashboardCronjob ) ;
2020-06-21 19:01:25 +02:00
map . put ( BackgroundJob . JOB_SUPPLIER_AUTO_PAYMENT , autoSupplierPaymentJob ) ;
2020-05-15 13:47:54 +02:00
return Collections . unmodifiableMap ( map ) ;
}
private ScheduledCronjob getNextCronjob ( ) {
Calendar currentTime = new GregorianCalendar ( ) ;
2020-05-25 17:08:15 +02:00
Iterable < BackgroundJob > jobs = cronjobRepository . findAll ( ) ;
2020-05-15 13:47:54 +02:00
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 ) ;
}
2020-05-25 17:08:15 +02:00
try {
nextJob . cronjob . executeAt ( nextJob . executionTime , this ) ;
} catch ( Throwable t ) {
log . error ( " Failed to execute cronjob " + nextJob . cronjob . getClass ( ) + " : " ) ;
t . printStackTrace ( ) ;
}
2020-05-15 13:47:54 +02:00
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 ( ) ;
}
2020-06-15 16:23:42 +02:00
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 " ;
}
2020-05-15 13:47:54 +02:00
}