blob: 471f0bde4024a1b15fbb15a233193471f1fb051e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.ace.scheduler;
import org.osgi.service.cm.ConfigurationException;
/**
* Wrapper class for collecting a <code>Runnable</code> and its corresponding <code>recipe</code>(s).
* Will schedule the task when both a schedule and a <code>Runnable</code> are available.<br>
*/
public class SchedulerTask {
private final String m_name;
private Runnable m_task;
private String m_description;
private Object m_configurationRecipe;
private Object m_taskRecipe;
private boolean m_recipeOverride;
private Object m_currentRecipe;
private Executer m_executer;
/**
* Creates instance of this class.
* @param name The name of the runnable task.
*/
SchedulerTask(String name) {
if (name == null) {
throw new IllegalArgumentException("A SchedulerTask's name cannot be null.");
}
m_name = name;
}
public String getName() {
return m_name;
}
public String getDescription() {
return m_description;
}
public Runnable getTask() {
return m_task;
}
/**
* Returns the currently most suited recipe, if any. This function not returning
* <code>null</code> does not mean that the task is scheduled (it may still be missing
* a <code>Runnable</code>).
*/
public Object getCurrentRecipe() {
return m_currentRecipe;
}
/**
* Indicates whether this task is actually scheduled, and thus will run at some time
* in the future, unless the schedule is set to <code>null</code>, or the <code>Runnable</code>
* is removed.
*/
public boolean isScheduled() {
return m_executer != null;
}
/**
* States a new set of properties for this task.
* @param task A runnable to run for this task.
* @param description A description of the task.
* @param taskRecipe Optionally, a recipe for running this task.
* @param recipeOverride Indicates whether or not the <code>recipe</code> passed in prevails over
* any recipe provided by the <code>Scheduler</code>'s configuration.
* @throws ConfigurationException When <code>recipe</code> is not <code>null</code>, and cannot
* be decoded into a recipe.
*/
public void updateTask(Runnable task, String description, Object taskRecipe, boolean recipeOverride) throws ConfigurationException {
checkRecipe(taskRecipe);
m_task = task;
m_description = description;
m_taskRecipe = taskRecipe;
m_recipeOverride = recipeOverride;
}
/**
* States a new recipe as coming from a configuration.
* @param recipe Optionally, a recipe for running this task.
* @throws ConfigurationException When <code>recipe</code> is not <code>null</code>, and cannot
* be decoded into a recipe.
*/
public void updateConfigurationRecipe(Object recipe) throws ConfigurationException {
checkRecipe(recipe);
m_configurationRecipe = recipe;
}
public void stop() {
if (m_executer != null) {
m_executer.stop();
m_executer = null;
}
}
public boolean process() {
Object recipe = findRecipe();
if ((recipe != null) && (m_task != null)) {
if (!recipe.equals(m_currentRecipe) && (m_executer != null)) {
m_executer.stop();
m_executer = null;
}
if (m_executer == null) {
m_executer = new Executer(m_task);
m_executer.start(parseScheduleRecipe(recipe));
}
}
else {
// there is nothing to do, since there is no recipe or task
stop();
}
m_currentRecipe = recipe;
return ((recipe != null) || (m_task != null));
}
/**
* Finds the most suitable recipe for the given task, using both the properties published
* with the task, and the scheduler service's properties.
* @return An <code>Object</code> representing the scheduler recipe, if any. If no suitable recipe can be found,
* <code>null</code> will be returned.
*/
private Object findRecipe() {
if (m_recipeOverride) {
if (m_taskRecipe != null) {
return m_taskRecipe;
}
else if (m_configurationRecipe != null) {
return m_configurationRecipe;
}
}
else {
if (m_configurationRecipe != null) {
return m_configurationRecipe;
}
else if (m_taskRecipe != null) {
return m_taskRecipe;
}
}
return null;
}
/**
* Decodes an Object into a schedule.
* @param recipe An object representing a recipe.
* @return A decoded representation of the recipe.
*/
private long parseScheduleRecipe(Object recipe) {
// For now assume just the number of milliseconds is in the string, we may want to do a
// more 'cron-like' scheduling in the future
return Long.valueOf(recipe.toString()).longValue();
}
/**
* Helper method that checks whether a recipe is valid.
* @throws ConfigurationException When <code>recipe</code> is not <code>null</code>, and cannot
* be decoded into a recipe.
*/
private void checkRecipe(Object recipe) throws ConfigurationException {
if (recipe != null) {
try {
parseScheduleRecipe(recipe);
}
catch (NumberFormatException nfe) {
throw new ConfigurationException(m_name, "Could not parse scheduling recipe for task", nfe);
}
}
}
}