/** * 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.Comparator; import java.util.Iterator; import java.util.PriorityQueue; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.config.Config; import org.eclipse.smarthome.binding.digitalstrom.internal.lib.sensorJobExecutor.sensorJob.SensorJob; 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.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This {@link CircuitScheduler} represents a circuit in the digitalSTROM-System and manages the priorities and * execution times for the {@link SensorJob}s on this circuit. * * @author Michael Ochel - Initial contribution * @author Matthias Siegele - Initial contribution */ public class CircuitScheduler { private Logger logger = LoggerFactory.getLogger(CircuitScheduler.class); private class SensorJobComparator implements Comparator<SensorJob> { @Override public int compare(SensorJob job1, SensorJob job2) { return ((Long) job1.getInitalisationTime()).compareTo(job2.getInitalisationTime()); } } private final DSID meterDSID; private long nextExecutionTime = System.currentTimeMillis(); private PriorityQueue<SensorJob> sensorJobQueue = new PriorityQueue<SensorJob>(10, new SensorJobComparator()); private Config config; /** * Creates a new {@link CircuitScheduler}. * * @param meterDSID * @param config */ public CircuitScheduler(DSID meterDSID, Config config) { if (meterDSID == null) { throw new IllegalArgumentException("The meterDSID must not be null!"); } this.meterDSID = meterDSID; this.config = config; } /** * Creates a new {@link CircuitScheduler} and add the first {@link SensorJob} to this {@link CircuitScheduler}. * * @param sensorJob * @param config */ public CircuitScheduler(SensorJob sensorJob, Config config) { this.meterDSID = sensorJob.getMeterDSID(); this.sensorJobQueue.add(sensorJob); this.config = config; logger.debug("create circuitScheduler: " + this.getMeterDSID() + " and add sensorJob: " + sensorJob.getDSID().toString()); } /** * Returns the meterDSID of the dS-Meter in which the {@link SensorJob}s will be executed. * * @return meterDSID */ public DSID getMeterDSID() { return this.meterDSID; } /** * Adds a new SensorJob to this {@link CircuitScheduler}, if no {@link SensorJob} with a higher priority exists. * * @param sensorJob */ public void addSensorJob(SensorJob sensorJob) { synchronized (sensorJobQueue) { if (!this.sensorJobQueue.contains(sensorJob)) { sensorJobQueue.add(sensorJob); logger.debug("Add sensorJob: " + sensorJob.toString() + "to circuitScheduler: " + this.getMeterDSID()); } else if (checkSensorJobPrio(sensorJob)) { logger.debug("add sensorJob: " + sensorJob.toString() + "with higher priority to circuitScheduler: " + this.getMeterDSID()); } else { logger.debug("sensorJob: " + sensorJob.getDSID().toString() + " allready exist with a higher priority"); } } } private boolean checkSensorJobPrio(SensorJob sensorJob) { synchronized (sensorJobQueue) { for (Iterator<SensorJob> iter = sensorJobQueue.iterator(); iter.hasNext();) { SensorJob existSensorJob = iter.next(); if (existSensorJob.equals(sensorJob)) { if (existSensorJob != null && sensorJob.getInitalisationTime() < existSensorJob.getInitalisationTime()) { iter.remove(); sensorJobQueue.add(sensorJob); return true; } } } } return false; } /** * Returns the next {@link SensorJob} which can be executed or null, if there are no more {@link SensorJob} to * execute or the wait time between the {@link SensorJob}s executions has not expired yet. * * @return next SensorJob or null */ public SensorJob getNextSensorJob() { synchronized (sensorJobQueue) { if (sensorJobQueue.peek() != null && this.nextExecutionTime <= System.currentTimeMillis()) { nextExecutionTime = System.currentTimeMillis() + config.getSensorReadingWaitTime(); return sensorJobQueue.poll(); } else { return null; } } } /** * Returns the time when the next {@link SensorJob} can be executed. * * @return next SesnorJob execution time */ public Long getNextExecutionTime() { return this.nextExecutionTime; } /** * Returns the delay when the next {@link SensorJob} can be executed. * * @return next SesnorJob execution delay */ public Long getNextExecutionDelay() { long delay = this.nextExecutionTime - System.currentTimeMillis(); return delay > 0 ? delay : 0; } /** * Removes all {@link SensorJob} of a specific {@link Device} with the given {@link DSID}. * * @param dSID of the device */ public void removeSensorJob(DSID dSID) { synchronized (sensorJobQueue) { for (Iterator<SensorJob> iter = sensorJobQueue.iterator(); iter.hasNext();) { SensorJob job = iter.next(); if (job.getDSID().equals(dSID)) { iter.remove(); } } logger.debug("Remove SensorJobs from device with dSID {}." + dSID); } } /** * Returns true, if there are no more {@link SensorJob}s to execute, otherwise false. * * @return no more SensorJobs? (true | false) */ public boolean noMoreJobs() { synchronized (sensorJobQueue) { return this.sensorJobQueue.isEmpty(); } } }