/* * Copyright 2010 Research Studios Austria Forschungsgesellschaft mBH * * This file is part of easyrec. * * easyrec is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * easyrec is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with easyrec. If not, see <http://www.gnu.org/licenses/>. */ package org.easyrec.service.web; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.easyrec.model.core.web.Operator; import org.easyrec.model.core.web.RemoteTenant; import org.easyrec.model.plugin.NamedConfiguration; import org.easyrec.model.plugin.archive.ArchivePseudoConfiguration; import org.easyrec.model.plugin.archive.ArchivePseudoGenerator; import org.easyrec.model.web.EasyRecSettings; import org.easyrec.model.web.Queue; import org.easyrec.plugin.configuration.GeneratorContainer; import org.easyrec.service.core.TenantService; import org.easyrec.store.dao.plugin.LogEntryDAO; import org.easyrec.store.dao.web.OperatorDAO; import org.easyrec.store.dao.web.RemoteTenantDAO; import org.springframework.beans.factory.DisposableBean; import org.springframework.beans.factory.InitializingBean; import java.util.HashMap; import java.util.List; import java.util.Properties; /** * This class schedules plugins for each tenant. * <p/> * TODO update javadoc * All tenants, that have an active plugin scheduler flag are added * to the plugin TaskList. The PluginTaskList is a HashMap that contains * the tenant id as key and a PluginTask as value. * <p/> * A PluginTask adds a tenant to the execution queue at its execution time. * <p/> * The queue holds a list of all tenants that are waiting to be scheduled. * After a tenant is processed by the plugins, he is removed from the queue. * * @author phlavac */ public class PluginScheduler implements InitializingBean, DisposableBean { // TODO: move to vocabulary? private final static int SCHEDULER_PAUSE = 30 * 1000; private final Log logger = LogFactory.getLog(getClass()); private RemoteTenantDAO remoteTenantDAO; private OperatorDAO operatorDAO; private HashMap<Integer, PluginTimerTask> pluginTimerTasks; private LogEntryDAO logEntryDAO; private Queue queue; private TenantService tenantService; private RemoteTenantService remoteTenantService; private EasyRecSettings easyrecSettings; private GeneratorContainer generatorContainer; private Scheduler scheduler; public PluginScheduler() { queue = new Queue(); } /** * Init PluginScheduler timertasks for all Tenants. * * @throws java.lang.Exception */ @Override public void afterPropertiesSet() throws Exception { if (easyrecSettings.isGenerator()) { initTasks(); logEntryDAO.endAllEntries(); scheduler = new Scheduler(queue); scheduler.start(); logger.info("Plugin Scheduler started."); } } /** * Shut down scheduler * * @throws Exception */ @Override public void destroy() throws Exception { Thread interruptThread = scheduler; scheduler = null; interruptThread.interrupt(); for (PluginTimerTask task : pluginTimerTasks.values()) { task.destroy(); //noinspection UnusedAssignment task = null; } pluginTimerTasks.clear(); logger.info("PluginScheduler shut down."); } /** * Add a PluginTimerTask to a Tenant * * @param remoteTenant RemoteTenant */ public void addTask(RemoteTenant remoteTenant) { if (pluginTimerTasks != null) { pluginTimerTasks.put(remoteTenant.getId(), new PluginTimerTask(remoteTenant, queue)); } } /** * Update a tenant's PluginTimerTask * * @param remoteTenant RemoteTenant */ public void updateTask(RemoteTenant remoteTenant) { boolean tenantInTaskList = false; if (pluginTimerTasks != null) { PluginTimerTask pluginTimerTask = pluginTimerTasks.get(remoteTenant.getId()); if (pluginTimerTask != null) { tenantInTaskList = true; pluginTimerTask.destroy(); pluginTimerTasks.remove(remoteTenant.getId()); } if (remoteTenant.isSchedulerEnabled()) { pluginTimerTasks.put(remoteTenant.getId(), new PluginTimerTask(remoteTenant, queue)); if (!tenantInTaskList) { logger.info("'" + remoteTenant.getOperatorId() + " - " + remoteTenant.getStringId() + "' added to PluginTask List"); } } else { if (tenantInTaskList) { logger.info("'" + remoteTenant.getOperatorId() + " - " + remoteTenant.getStringId() + "' removed from PluginTask List"); } } } } /** * Stops a tenant's PluginTimerTask * * @param remoteTenant RemoteTenant */ public void stopTask(RemoteTenant remoteTenant) { if (pluginTimerTasks != null) { PluginTimerTask pluginTimerTask = pluginTimerTasks.get(remoteTenant.getId()); if (pluginTimerTask != null) { pluginTimerTask.destroy(); pluginTimerTasks.remove(remoteTenant.getId()); } logger.info("'" + remoteTenant.getOperatorId() + " - " + remoteTenant.getStringId() + "' removed from PluginTimerTask"); } } public void initTasks() { pluginTimerTasks = new HashMap<Integer, PluginTimerTask>(); List<Operator> operators = operatorDAO.getOperators(0, Integer.MAX_VALUE); for (Operator operator : operators) { List<RemoteTenant> tenants = remoteTenantDAO.getTenantsFromOperator(operator.getOperatorId()); for (RemoteTenant r : tenants) { if (r.isSchedulerEnabled()) { addTask(r); logger.info("'" + r.getOperatorId() + " - " + r.getStringId() + "' added to PluginTask List"); } } } } /** * Iterates through all tenants and adds or removes a tenant */ private void updateTasks() { List<Operator> operators = operatorDAO.getOperators(0, Integer.MAX_VALUE); for (Operator operator : operators) { List<RemoteTenant> tenants = remoteTenantDAO.getTenantsFromOperator(operator.getOperatorId()); for (RemoteTenant r : tenants) { updateTask(r); } } } private class Scheduler extends Thread { private final Log logger = LogFactory.getLog(getClass()); Queue queue; RemoteTenant remoteTenant; Scheduler(Queue queue) { this.queue = queue; } // look if tenants are waiting in queue. If so process plugins for every tenant in queue. @Override public void run() { Thread thisThread = Thread.currentThread(); while (!thisThread.isInterrupted() && scheduler == thisThread) { updateTasks(); if (queue.isEmpty()) { try { sleep(SCHEDULER_PAUSE); logger.debug("pausing plugin scheduler for " + SCHEDULER_PAUSE + "ms."); } catch (InterruptedException ex) { logger.debug("pausing plugin scheduler failed", ex); Thread.currentThread().interrupt(); } } else { remoteTenant = queue.poll(); final Properties tenantConfig = tenantService.getTenantConfig(remoteTenant.getId()); if (tenantConfig == null) { logger.warn("could not get tenant configuration, aborting"); return; } if ("true".equals(tenantConfig.getProperty(RemoteTenant.AUTO_ARCHIVER_ENABLED))) { String daysString = tenantConfig.getProperty(RemoteTenant.AUTO_ARCHIVER_TIME_RANGE); final int days = Integer.parseInt(daysString); ArchivePseudoConfiguration configuration = new ArchivePseudoConfiguration(days); configuration.setAssociationType("ARCHIVE"); NamedConfiguration namedConfiguration = new NamedConfiguration(remoteTenant.getId(), 0, ArchivePseudoGenerator.ID, "Archive", configuration, true); logger.info("Archiving actions older than " + days + " day(s)"); generatorContainer.runGenerator(namedConfiguration); } logger.info("starting generator plugin for tenant: " + remoteTenant.getOperatorId() + ":" + remoteTenant.getStringId()); generatorContainer.runGeneratorsForTenant(remoteTenant.getId()); /////////////////////////////////////// // TODO: insert logic here to trigger plugin generators // TODO: send call to REST-API to mostview ALL Time to get results cached // Problem: how to get ContextPath the needs to present to build backtracking URL? remoteTenantService.updateTenantStatistics(remoteTenant.getId()); } } logger.debug("PluginScheduler stopped. "); } } public void setOperatorDAO(OperatorDAO operatorDAO) { this.operatorDAO = operatorDAO; } public void setRemoteTenantDAO(RemoteTenantDAO remoteTenantDAO) { this.remoteTenantDAO = remoteTenantDAO; } public void setLogEntryDAO(LogEntryDAO logEntryDAO) { this.logEntryDAO = logEntryDAO; } public void setTenantService(TenantService tenantService) { this.tenantService = tenantService; } public void setRemoteTenantService(RemoteTenantService remoteTenantService) { this.remoteTenantService = remoteTenantService; } public void setEasyrecSettings(EasyRecSettings easyrecSettings) { this.easyrecSettings = easyrecSettings; } public void setGeneratorContainer(GeneratorContainer generatorContainer) { this.generatorContainer = generatorContainer; } }