/**
* Copyright (c) 2010-2016 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.openhab.binding.lcn.internal;
import org.openhab.core.binding.AbstractActiveBinding;
import org.openhab.core.binding.BindingProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Active service used by the LCN openHAB binding.
* <p>
* It is based on "AbstractActiveService" and {@link AbstractActiveBinding.BindingActiveService}
* without the refresh-interval polling.
*
* @author Tobias J�ttner
*/
class LcnBindingActiveService implements Runnable {
/** Logger for this class. */
private static final Logger logger = LoggerFactory.getLogger(LcnBindingActiveService.class);
/** The (refresh-)thread name. */
private static final String THREAD_NAME = "LCN Refresh Service";
/** Must be implemented by the owner. */
interface Callback {
/**
* Main worker method of the binding to call periodically.
*/
void execute();
/**
* Checks whether any of the {@link BindingProvider}s provides a binding.
*
* @return true if any of the {@link BindingProvider}s provides a binding
*/
boolean bindingsExists();
}
/** The callback to the owner. */
private final Callback callback;
/** true if the binding is configured properly (all necessary data is available). */
private boolean properlyConfigured = false;
/** Indicates that the background thread should shutdown after the current execution cycle. */
protected volatile boolean threadTreminate = false;
/** The instance of the worker or null if there is no thread active at the moment. */
private Thread thread;
/**
* Constructs an active service with the given callback.
*
* @param callback the callback to the owner
*/
LcnBindingActiveService(Callback callback) {
this.callback = callback;
}
/**
* Gets the current running-state.
*
* @return true if this active service is running
*/
boolean isRunning() {
return this.thread != null ? this.thread.isAlive() : false;
}
/** Starts the worker thread if it is not running yet. */
void start() {
if (!this.properlyConfigured) {
logger.trace("{} won't be started because it isn't yet properly configured.", THREAD_NAME);
return;
}
this.threadTreminate = false;
if (!this.isRunning()) {
this.thread = new Thread(this, THREAD_NAME);
this.thread.setDaemon(true);
this.thread.start();
} else {
logger.trace("{} is already started > calling start() changed nothing.", THREAD_NAME);
}
}
/** Tells the worker thread to stop as soon as possible. */
void stop() {
this.threadTreminate = true;
}
/**
* Used to define whether this binding is fully configured so it can be activated and used.
* Note that the active service will be started automatically if true is passed.
*
* @param properlyConfigured the configuration state
*/
void setProperlyConfigured(boolean properlyConfigured) {
this.properlyConfigured = properlyConfigured;
if (this.properlyConfigured && !this.isRunning()) {
this.start();
} else if (!this.properlyConfigured && this.isRunning()) {
this.stop();
}
}
/** Main method of the thread. */
@Override
public void run() {
logger.info(THREAD_NAME + " has been started");
while (!this.threadTreminate) {
try {
this.callback.execute();
} catch (RuntimeException ex) {
logger.error("Error while executing background thread " + THREAD_NAME, ex);
}
}
this.thread = null;
logger.info(THREAD_NAME + " has been shut down");
}
}