package com.im.imjutil.util;
import com.im.imjutil.exception.ValidationException;
/**
* Classe responsavel por executar um objeto que implemente {@link Runnable}
* como uma {@link Thread}, podendo controlar a continuidade da execucao
* e o tempo de espera entre execucoes. Por padrao, ela executa em unica
* iteracao e nao possui um tempo de espera.
*
* @author Felipe Zappala
*/
public class Runner implements Runnable {
/** Thread interna para execucao desta classe */
private Thread thread;
/** Objeto a ser executado */
private Runnable runnable;
/** Determina se a thread interna esta rodando ou nao */
private boolean running;
/** Determina se a execucao sera continua ou nao*/
private boolean continuous;
/** Determina o tempo de espera por execucao */
private long sleep;
/** Determina se o tempo de espera sera depois da execucao */
private boolean sleepAfter;
/** Determina se o tempo de espera sera antes da execucao */
private boolean sleepBefore;
/** Determina o numero maximo de vezes de execucao */
private long maxSteps;
/** Deternima o passo corrente de execucao */
private long step;
/**
* Construtor padrao do {@link Runner}
*
* @param runnable Objeto {@link Runnable} a ser executado.
* @throws ValidationException Caso o objeto passado for {@code nulo}.
*/
public Runner(Runnable runnable) {
if (runnable == null) {
throw new ValidationException("Runnable nao definido");
}
this.runnable = runnable;
this.continuous = false;
this.running = false;
this.sleep = 0;
this.sleepAfter = false;
this.sleepBefore = true;
this.maxSteps = 0;
}
/**
* Implementa a logica de execucao do objeto {@link Runnable}.
*/
@Override
public final void run() {
try {
do {
++step;
if (sleepBefore && sleep > 0) {
Thread.sleep(sleep);
}
runnable.run();
if (sleepAfter && sleep > 0) {
Thread.sleep(sleep);
}
if (!continuous) {
break;
}
if (maxSteps > 0 && step >= maxSteps) {
break;
}
} while (running);
running = false;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/**
* Inicia a {@link Thread} de execucao do {@link Runner} atual.
*
* @throws IllegalStateException caso o runner ja estiver executando
*/
public synchronized void start() {
if (running) {
this.stop();
throw new IllegalStateException("O runner ja esta executando");
}
this.thread = new Thread(this);
this.running = true;
this.thread.start();
}
/**
* Finaliza a {@link Thread} de execucao do {@link Runner} atual.
*/
public void stop() {
this.thread = null;
this.running = false;
}
/**
* Obtem o tempo de espera por execucao.
*
* @return O tempo de espera em milisegundos.
*/
public long getSleep() {
return sleep;
}
/**
* Configura o tempo de espera por execucao.
*
* @param sleep O tempo de espera em milisegundos.
*/
public void setSleep(long sleep) {
this.sleep = sleep;
}
/**
* Configura o mode de execucao como continuo, ou seja, executando
* varias vezes o {@link Runnable}, ate o runner ser finalizado usando
* {@link #stop()}.
*/
public void setContinuous() {
this.continuous = true;
}
/**
* Configura o mode de execucao como nao continuo, ou seja, executando
* somente uma vezes o {@link Runnable}.
*/
public void setDiscontinuous() {
this.continuous = false;
}
/**
* Verifica se a {@link Thread} interna ainda esta executando.
*
* @return Verdadeiro caso ainda esteja rodando.
*/
public boolean isRunning() {
return running;
}
/**
* Verifica se a espera sera depois da execucao.
*
* @return Verdadeiro caso a espera for depois da execucao.
*/
public boolean isSleepAfter() {
return sleepAfter;
}
/**
* Configura a espera para depois da execucao.
*/
public void setSleepAfter() {
this.sleepAfter = true;
this.sleepBefore = false;
}
/**
* Verifica se a espera sera antes da execucao.
*
* @return Verdadeiro caso a espera for antes da execucao.
*/
public boolean isSleepBefore() {
return sleepBefore;
}
/**
* Configura a espera para antes da execucao.
*/
public void setSleepBefore() {
this.sleepBefore = true;
this.sleepAfter = false;
}
/**
* Obtem o numero maximo de vezes de execucao.
*
* @return O numero maximo de vezes de execucao.
*/
public long getMaxSteps() {
return maxSteps;
}
/**
* Obtem o numero do passo corrente de execucao.
*
* @return O numero corrente da execucao.
*/
public long getCurrentStep() {
return step;
}
/**
* Configura o numero maximo de vezes de execucao.
* Caso o valor for menor ou igual a zero, o parametro sera ignorado.
*
* @param maxSteps O numero maximo de vezes de execucao.
*/
public void setMaxSteps(long maxSteps) {
this.maxSteps = maxSteps;
this.setContinuous();
}
}