All Downloads are FREE. Search and download functionalities are using the official Maven repository.

it.sauronsoftware.cron4j.TaskExecutor Maven / Gradle / Ivy

/*
 * cron4j - A pure Java cron-like scheduler
 * 
 * Copyright (C) 2007-2010 Carlo Pelliccia (www.sauronsoftware.it)
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version
 * 2.1, as published by the Free Software Foundation.
 *
 * This program 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 Lesser General Public License 2.1 for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License version 2.1 along with this program.
 * If not, see .
 */
package it.sauronsoftware.cron4j;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * 

* Represents a task executor, which is something similar to threads. *

*

* Each time a task is launched, a new executor is spawned, executing and * watching the task *

*

* Alive task executors can be retrieved with the * {@link Scheduler#getExecutingTasks()} method, and they expose method to * control the ongoing execution. *

* * @see Scheduler#getExecutingTasks() * @author Carlo Pelliccia * @since 2.0 */ public class TaskExecutor { /** * The scheduler whose this executor belongs to. */ private Scheduler scheduler; /** * The executed task. */ private Task task; /** * A task execution context. */ private MyContext context; /** * A unique ID for this executor (used also as a lock object). */ private String guid = GUIDGenerator.generate(); /** * An alternative to this (inner classes need it). */ private TaskExecutor myself = this; /** * A list of {@link TaskExecutorListener} instances. */ private ArrayList listeners = new ArrayList(); /** * A time stamp reporting the start time of this thread. */ private long startTime = -1; /** * The thread actually executing the task. */ private Thread thread; /** * Is this executor paused now? */ private boolean paused = false; /** * Has been this executor stopped? */ private boolean stopped = false; /** * A lock object, for synchronization purposes. */ private Object lock = new Object(); /** * Builds the executor. * * @param scheduler * The scheduler whose this executor belongs to. * @param task * The task that has to be executed. */ TaskExecutor(Scheduler scheduler, Task task) { this.scheduler = scheduler; this.task = task; this.context = new MyContext(); } /** * Adds a listener to the executor. * * @param listener * The listener. */ public void addTaskExecutorListener(TaskExecutorListener listener) { synchronized (listeners) { listeners.add(listener); } } /** * Removes a listener from the executor. * * @param listener * The listener. */ public void removeTaskExecutorListener(TaskExecutorListener listener) { synchronized (listeners) { listeners.remove(listener); } } /** * Returns an array containing any {@link TaskExecutorListener} previously * registered with the * {@link TaskExecutor#addTaskExecutorListener(TaskExecutorListener)} * method. * * @return An array containing any {@link TaskExecutorListener} previously * registered with the * {@link TaskExecutor#addTaskExecutorListener(TaskExecutorListener)} * method. */ public TaskExecutorListener[] getTaskExecutorListeners() { synchronized (listeners) { int size = listeners.size(); TaskExecutorListener[] ret = new TaskExecutorListener[size]; for (int i = 0; i < size; i++) { ret[i] = (TaskExecutorListener) listeners.get(i); } return ret; } } /** * Returns a GUID for this executor. * * @return A GUID for this executor. */ public String getGuid() { return guid; } /** * Returns the {@link Scheduler} instance whose this executor belongs to. * * @return The scheduler. */ public Scheduler getScheduler() { return scheduler; } /** * Returns the representation of the executed task. * * @return The executing/executed task. */ public Task getTask() { return task; } /** * Returns a time stamp reporting the start time of this executor, or a * value less than 0 if this executor has not been yet started. * * @return A time stamp reporting the start time of this executor, or a * value less than 0 if this executor has not been yet started. */ public long getStartTime() { return startTime; } /** * Checks whether this executor supports pausing. * * @return true if this executor supports pausing. */ public boolean canBePaused() { return task.canBePaused(); } /** * Checks whether this executor supports stopping. * * @return true if this executor supports stopping. */ public boolean canBeStopped() { return task.canBeStopped(); } /** * Checks whether this executor provides completeness tracking informations. * * @return true if this executor provides completeness tracking * informations. */ public boolean supportsCompletenessTracking() { return task.supportsCompletenessTracking(); } /** * Checks whether this executor provides status tracking messages. * * @return true if this executor provides status tracking messages. */ public boolean supportsStatusTracking() { return task.supportsStatusTracking(); } /** * Starts executing the task (spawns a secondary thread). * * @param daemon * true to spawn a daemon thread; false otherwise. */ void start(boolean daemon) { synchronized (lock) { startTime = System.currentTimeMillis(); String name = "cron4j::scheduler[" + scheduler.getGuid() + "]::executor[" + guid + "]"; thread = new Thread(new Runner()); thread.setDaemon(daemon); thread.setName(name); thread.start(); } } /** * Pauses the ongoing execution. * * @throws UnsupportedOperationException * The operation is not supported if * {@link TaskExecutor#canBePaused()} returns false. */ public void pause() throws UnsupportedOperationException { if (!canBePaused()) { throw new UnsupportedOperationException("Pause not supported"); } synchronized (lock) { if (thread != null && !paused) { notifyExecutionPausing(); paused = true; } } } /** * Resumes the execution after it has been paused. */ public void resume() { synchronized (lock) { if (thread != null && paused) { notifyExecutionResuming(); paused = false; lock.notifyAll(); } } } /** * Stops the ongoing execution. * * @throws UnsupportedOperationException * The operation is not supported if * {@link TaskExecutor#canBeStopped()} returns false. */ public void stop() throws UnsupportedOperationException { if (!canBeStopped()) { throw new UnsupportedOperationException("Stop not supported"); } boolean joinit = false; synchronized (lock) { if (thread != null && !stopped) { stopped = true; if (paused) { resume(); } notifyExecutionStopping(); thread.interrupt(); joinit = true; } } if (joinit) { do { try { thread.join(); break; } catch (InterruptedException e) { continue; } } while (true); thread = null; } } /** * Waits for this executor to die. * * @throws InterruptedException * If any thread has interrupted the current thread. The * interrupted status of the current thread is cleared when this * exception is thrown. */ public void join() throws InterruptedException { if (thread != null) { thread.join(); } } /** * Tests if this executor is alive. An executor is alive if it has been * started and has not yet died. * * @return true if this executor is alive; false otherwise. */ public boolean isAlive() { if (thread != null) { return thread.isAlive(); } else { return false; } } /** * Returns the current status message. * * @return The current status message. * @throws UnsupportedOperationException * The operation is not supported if * {@link TaskExecutor#supportsStatusTracking()} returns * false. */ public String getStatusMessage() throws UnsupportedOperationException { if (!supportsStatusTracking()) { throw new UnsupportedOperationException( "Status tracking not supported"); } return context.getStatusMessage(); } /** * Returns the current completeness value, which is a value between 0 and 1. * * @return The current completeness value, which is a value between 0 and 1. * @throws UnsupportedOperationException * The operation is not supported if * {@link TaskExecutor#supportsCompletenessTracking()} returns * false. */ public double getCompleteness() throws UnsupportedOperationException { if (!supportsCompletenessTracking()) { throw new UnsupportedOperationException( "Completeness tracking not supported"); } return context.getCompleteness(); } /** * Tests whether this executor has been paused. * * @return true if this executor is paused; false otherwise. */ public boolean isPaused() { return paused; } /** * Tests whether this executor has been stopped. * * @return true if this executor is stopped; false otherwise. */ public boolean isStopped() { return stopped; } /** * Notify registered listeners the execution has been paused. */ private void notifyExecutionPausing() { synchronized (listeners) { for (Iterator i = listeners.iterator(); i.hasNext();) { TaskExecutorListener l = (TaskExecutorListener) i.next(); l.executionPausing(this); } } } /** * Notify registered listeners the execution has been resumed. * */ private void notifyExecutionResuming() { synchronized (listeners) { for (Iterator i = listeners.iterator(); i.hasNext();) { TaskExecutorListener l = (TaskExecutorListener) i.next(); l.executionResuming(this); } } } /** * Notify registered listeners the executor is stopping. */ private void notifyExecutionStopping() { synchronized (listeners) { for (Iterator i = listeners.iterator(); i.hasNext();) { TaskExecutorListener l = (TaskExecutorListener) i.next(); l.executionStopping(this); } } } /** * Notify registered listeners the execution has been terminated. * * @param exception * If the execution has been terminated due to an error, this is * the encountered exception; otherwise the parameter is null. */ private void notifyExecutionTerminated(Throwable exception) { synchronized (listeners) { for (Iterator i = listeners.iterator(); i.hasNext();) { TaskExecutorListener l = (TaskExecutorListener) i.next(); l.executionTerminated(this, exception); } } } /** * Notify registered listeners the execution status message has changed. * * @param statusMessage * The new status message. */ private void notifyStatusMessageChanged(String statusMessage) { synchronized (listeners) { for (Iterator i = listeners.iterator(); i.hasNext();) { TaskExecutorListener l = (TaskExecutorListener) i.next(); l.statusMessageChanged(this, statusMessage); } } } /** * Notify registered listeners the execution completeness value has changed. * * @param completenessValue * The new completeness value. */ private void notifyCompletenessValueChanged(double completenessValue) { synchronized (listeners) { for (Iterator i = listeners.iterator(); i.hasNext();) { TaskExecutorListener l = (TaskExecutorListener) i.next(); l.completenessValueChanged(this, completenessValue); } } } /** * Inner Runnable class. */ private class Runner implements Runnable { /** * It implements {@link Thread#run()}, executing the wrapped task. */ public void run() { Throwable error = null; startTime = System.currentTimeMillis(); try { // Notify. scheduler.notifyTaskLaunching(myself); // Task execution. task.execute(context); // Succeeded. scheduler.notifyTaskSucceeded(myself); } catch (Throwable exception) { // Failed. error = exception; scheduler.notifyTaskFailed(myself, exception); } finally { // Notify. notifyExecutionTerminated(error); scheduler.notifyExecutorCompleted(myself); } } } /** * Inner TaskExecutionHelper implementation. */ private class MyContext implements TaskExecutionContext { /** * Status message. */ private String message = ""; /** * Completeness value. */ private double completeness = 0D; public Scheduler getScheduler() { return scheduler; } public TaskExecutor getTaskExecutor() { return myself; } public boolean isStopped() { return stopped; } public void pauseIfRequested() { synchronized (lock) { if (paused) { try { lock.wait(); } catch (InterruptedException e) { ; } } } } public void setCompleteness(double completeness) { if (completeness >= 0D && completeness <= 1D) { this.completeness = completeness; notifyCompletenessValueChanged(completeness); } } public void setStatusMessage(String message) { this.message = message != null ? message : ""; notifyStatusMessageChanged(message); } /** * Returns the current status message. * * @return The current status message. */ public String getStatusMessage() { return message; } /** * Returns the current completeness value, which is a value between 0 * and 1. * * @return The current completeness value, which is a value between 0 * and 1. */ public double getCompleteness() { return completeness; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy