package won.bot.framework.manager.impl;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextClosedEvent;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.Trigger;
import won.bot.framework.bot.Bot;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
/**
* Spring context aware bot registry that adds all beans of type Bot defined in the application context.
*
* If the checkWorkDoneTrigger is not null, all bots will regularly be checked if all work is done. If so, the
* spring context will be shut down.
*/
public class SpringAwareBotManagerImpl extends BotManagerImpl implements ApplicationContextAware, DisposableBean, ApplicationListener
{
private ApplicationContext applicationContext;
private Trigger checkWorkDoneTrigger = null;
@Autowired
private TaskScheduler taskScheduler;
private boolean shutdownApplicationContextIfWorkDone = false;
@Override
public void onApplicationEvent(final ApplicationEvent event)
{
logger.debug("processing application event {}", event);
if (event instanceof ContextRefreshedEvent){
logger.info("context started or refreshed: searching for bots in spring context");
try {
findAndRegisterBots();
} catch (Exception e) {
logger.warn("Error registering bots", e);
}
} else if (event instanceof ContextClosedEvent) {
try {
destroy();
} catch (Exception e) {
logger.warn("Error destroying bot manager "+this, e);
}
}
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Override
public void destroy() throws Exception
{
logger.info("shutting down bot manager");
synchronized (getMonitor()){
List<Bot> bots = getBots();
Bot bot;
for(Iterator<Bot> it = bots.iterator(); it.hasNext(); ){
bot = it.next();
if(bot.getLifecyclePhase().isActive()){
try {
bot.shutdown();
} catch (Exception e) {
logger.warn("could not shut down bot {}", bot, e);
}
}
it.remove();
}
}
logger.info("bot manager shutdown complete");
}
private void findAndRegisterBots() throws Exception {
logger.info("starting up bot manager");
synchronized (getMonitor()) {
findBotsInContextAndInitialize();
}
registerCheckWorkDoneTrigger();
logger.info("bot manager startup complete");
}
public void setCheckWorkDoneTrigger(final Trigger checkWorkDoneTrigger)
{
this.checkWorkDoneTrigger = checkWorkDoneTrigger;
}
public void setTaskScheduler(final TaskScheduler taskScheduler)
{
this.taskScheduler = taskScheduler;
}
public boolean isShutdownApplicationContextIfWorkDone() {
return shutdownApplicationContextIfWorkDone;
}
public void setShutdownApplicationContextIfWorkDone(final boolean shutdownApplicationContextIfWorkDone) {
this.shutdownApplicationContextIfWorkDone = shutdownApplicationContextIfWorkDone;
}
private void registerCheckWorkDoneTrigger()
{
if (this.checkWorkDoneTrigger == null){
logger.info("no trigger set on SpringAwareBotManagerImpl, not checking bots' workDone status");
return;
}
this.taskScheduler.schedule(new Runnable(){
@Override
public void run()
{
boolean workDone = isWorkDone();
if (! shutdownApplicationContextIfWorkDone){
logger.debug("botmanager will not shutdown spring context when work is done. (workDone:{})",workDone );
} else {
logger.debug("botmanager will shutdown spring context when work is done. (workDone:{})",workDone );
if (workDone) SpringApplication.exit(applicationContext);
}
}
}, checkWorkDoneTrigger);
}
private void findBotsInContextAndInitialize()
{
Map<String, Bot> bots = this.applicationContext.getBeansOfType(Bot.class);
for (Bot bot: bots.values()) {
try {
addBot(bot);
} catch (Exception e){
logger.warn("could not initialize bot {}", bot, e);
}
}
}
}