package rmblworx.tools.timey;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import rmblworx.tools.timey.event.AlarmExpiredEvent;
import rmblworx.tools.timey.event.AlarmsModifiedEvent;
import rmblworx.tools.timey.event.TimeyEvent;
import rmblworx.tools.timey.event.TimeyEventDispatcher;
import rmblworx.tools.timey.event.TimeyEventListener;
import rmblworx.tools.timey.persistence.service.IAlarmService;
import rmblworx.tools.timey.vo.AlarmDescriptor;
/*
* Copyright 2014-2015 Christian Raue
* MIT License http://opensource.org/licenses/mit-license.php
*/
/**
* Diese Thread-sichere Implementierung setzt einen Countdown-Zähler um. Zeitnahme findet in Millisekunden statt.
*
* @author mmatthies
*/
class AlarmRunnable implements Runnable, ApplicationContextAware, TimeyEventListener {
/**
* Referenz auf die AlarmClient-Implementierung.
*/
private AlarmClient alarmClient;
/**
* Referenz auf den Alarmservice.
*/
private IAlarmService alarmService;
/**
* Liste mit allen Alarmzeitpunkten.
*/
private List<AlarmDescriptor> allAlarms;
/**
* Referenz auf die Events-verteilende Implementierung.
*/
private TimeyEventDispatcher eventDispatcher;
/**
* Von dieser Timerimplementierung verwendete Lock-Mechanismus.
*/
private final Lock lock = new ReentrantLock();
/**
* Merker. Kennzeichnet ob es neue oder modifizierte Alarme gibt. Beeinflusst das DB-Abfrageverhalten.
*/
private boolean newOrModifiedAlarmsAvailable = false;
/**
* Spring-Anwendungskontext.
*/
private ApplicationContext springContext;
/**
*/
public AlarmRunnable() {
}
/**
* Prueft ob ein Alarm zeitlich eingetreten ist.
*
* @return das den Alarm beschreibende Werteobjekt.
*/
private AlarmDescriptor detectAlarm() {
final long currentTimeMillis = System.currentTimeMillis();
AlarmDescriptor result = null;
for (final AlarmDescriptor alarm : this.allAlarms) {
if (alarm.getIsActive()) {
if (alarm.getAlarmtime().getMilliSeconds() <= currentTimeMillis) {
result = alarm;
break;
}
}
}
return result;
}
@Override
public void handleEvent(final TimeyEvent timeyEvent) {
if (timeyEvent instanceof AlarmsModifiedEvent) {
this.newOrModifiedAlarmsAvailable = true;
}
}
@Override
public void run() {
Thread.currentThread().setName("timey-Alarm");
this.lock.lock();
try {
// alarme aus der db
if (this.allAlarms == null || this.newOrModifiedAlarmsAvailable) {
this.allAlarms = this.alarmService.getAll();
this.newOrModifiedAlarmsAvailable = false;
}
// alarme abgleichen mit aktueller Systemzeit
final AlarmDescriptor result = this.detectAlarm();
if (result != null) {
// wenn erreicht event feuern sonst weiter abgleichen
this.alarmClient.initAlarmSetStateOfAlarmCommand(result, false);
this.alarmClient.initAlarmSetStateInAlarmDescriptorCommand(result, false);
this.eventDispatcher.dispatchEvent(new AlarmExpiredEvent(result));
}
} finally {
this.lock.unlock();
}
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext) throws BeansException {
this.springContext = applicationContext;
this.eventDispatcher = (TimeyEventDispatcher) this.springContext.getBean("timeyEventDispatcher");
this.eventDispatcher.addEventListener(this);
this.alarmService = (IAlarmService) this.springContext.getBean("alarmService");
this.alarmClient = (AlarmClient) this.springContext.getBean("alarmClient");
}
}