/** * Copyright (c) 2014-2017 by the respective copyright holders. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.config.Config; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.manager.ConnectionManager; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.sensorJob.SensorJob; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.serverConnection.DsAPI; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.Device; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.structure.devices.deviceParameters.DSID; import org.eclipse.smarthome.core.common.ThreadPoolManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * The {@link AbstractSensorJobExecutor} provides the working process to execute implementations of {@link SensorJobs}'s * in the time interval set at the {@link Config}. * <p> * The following methods can be overridden by subclasses to implement a execution priority: * <ul> * <li>{@link #addLowPriorityJob(SensorJob)}</li> * <li>{@link #addMediumPriorityJob(SensorJob)}</li> * <li>{@link #addHighPriorityJob(SensorJob)}</li> * </ul> * </p> * * @author Michael Ochel - Initial contribution * @author Matthias Siegele - Initial contribution * */ public abstract class AbstractSensorJobExecutor { private Logger logger = LoggerFactory.getLogger(AbstractSensorJobExecutor.class); private final ScheduledExecutorService scheduler = ThreadPoolManager.getScheduledPool(Config.THREADPOOL_NAME); private Map<DSID, ScheduledFuture<?>> pollingSchedulers = null; private DsAPI dSAPI; protected Config config; private ConnectionManager connectionManager; private List<CircuitScheduler> circuitSchedulerList = new LinkedList<CircuitScheduler>(); private class ExecutorRunnable implements Runnable { private CircuitScheduler circuit; public ExecutorRunnable(CircuitScheduler circuit) { this.circuit = circuit; } @Override public void run() { SensorJob sensorJob = circuit.getNextSensorJob(); if (sensorJob != null && connectionManager.checkConnection()) { sensorJob.execute(dSAPI, connectionManager.getSessionToken()); } if (circuit.noMoreJobs()) { logger.debug("no more jobs... stop circuit schedduler with id = " + circuit.getMeterDSID().toString()); pollingSchedulers.get(circuit.getMeterDSID()).cancel(true); } } }; public AbstractSensorJobExecutor(ConnectionManager connectionManager) { this.connectionManager = connectionManager; config = connectionManager.getConfig(); this.dSAPI = connectionManager.getDigitalSTROMAPI(); } /** * Stops all circuit schedulers. */ public synchronized void shutdown() { if (pollingSchedulers != null) { for (ScheduledFuture<?> scheduledExecutor : pollingSchedulers.values()) { scheduledExecutor.cancel(true); } pollingSchedulers = null; logger.debug("stop all circuit schedulers."); } } /** * Starts all circuit schedulers. */ public synchronized void startExecutor() { logger.debug("start all circuit schedulers."); if (pollingSchedulers == null) { pollingSchedulers = new HashMap<DSID, ScheduledFuture<?>>(); } if (circuitSchedulerList != null && !circuitSchedulerList.isEmpty()) { for (CircuitScheduler circuit : circuitSchedulerList) { startSchedduler(circuit); } } } private void startSchedduler(CircuitScheduler circuit) { if (pollingSchedulers != null) { if (pollingSchedulers.get(circuit.getMeterDSID()) == null || pollingSchedulers.get(circuit.getMeterDSID()).isCancelled()) { pollingSchedulers.put(circuit.getMeterDSID(), scheduler.scheduleAtFixedRate(new ExecutorRunnable(circuit), circuit.getNextExecutionDelay(), config.getSensorReadingWaitTime(), TimeUnit.MILLISECONDS)); } } } /** * Adds a high priority {@link SensorJob}. * * @param sensorJob */ protected void addHighPriorityJob(SensorJob sensorJob) { // TODO: can be Overridden to implement a priority addSensorJobToCircuitScheduler(sensorJob); } /** * Adds a medium priority {@link SensorJob}. * * @param sensorJob */ protected void addMediumPriorityJob(SensorJob sensorJob) { // TODO: can be Overridden to implement a priority addSensorJobToCircuitScheduler(sensorJob); } /** * Adds a low priority {@link SensorJob}. * * @param sensorJob */ protected void addLowPriorityJob(SensorJob sensorJob) { // TODO: can be Overridden to implement a priority addSensorJobToCircuitScheduler(sensorJob); } /** * Adds the given {@link SensorJob}. * * @param sensorJob */ protected void addSensorJobToCircuitScheduler(SensorJob sensorJob) { synchronized (this.circuitSchedulerList) { CircuitScheduler circuit = getCircuitScheduler(sensorJob.getMeterDSID()); if (circuit != null) { circuit.addSensorJob(sensorJob); } else { circuit = new CircuitScheduler(sensorJob, config); this.circuitSchedulerList.add(circuit); } startSchedduler(circuit); } } private CircuitScheduler getCircuitScheduler(DSID dsid) { for (CircuitScheduler circuit : this.circuitSchedulerList) { if (circuit.getMeterDSID().equals(dsid)) { return circuit; } } return null; } /** * Removes all SensorJobs of a specific {@link device}. * * @param device */ public void removeSensorJobs(Device device) { if (device != null) { CircuitScheduler circuit = getCircuitScheduler(device.getMeterDSID()); if (circuit != null) { circuit.removeSensorJob(device.getDSID()); } } } }