/*
* #%L
* Wisdom-Framework
* %%
* Copyright (C) 2013 - 2014 Wisdom Framework
* %%
* Licensed 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.
* #L%
*/
package org.wisdom.executors.scheduler;
import org.apache.felix.ipojo.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wisdom.api.annotations.scheduler.Every;
import org.wisdom.api.concurrent.ManagedScheduledExecutorService;
import org.wisdom.api.concurrent.ManagedScheduledFutureTask;
import org.wisdom.api.scheduler.Scheduled;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* Manage scheduled job using the system scheduler.
*/
@Component(immediate = true)
@Instantiate
public class WisdomTaskScheduler {
private static final Logger LOGGER = LoggerFactory.getLogger(WisdomTaskScheduler.class);
@Requires(filter = "(name=" + ManagedScheduledExecutorService.SYSTEM + ")", proxy = false)
ManagedScheduledExecutorService scheduler;
List<Job> jobs = new ArrayList<>();
/**
* @return the logger.
*/
protected static Logger getLogger() {
return LOGGER;
}
/**
* Binds a new {@link Scheduled} object. All jobs defined in this objects are submitted to the system scheduler.
*
* @param scheduled the scheduled object
*/
@Bind(aggregate = true, optional = true)
public synchronized void bindScheduled(Scheduled scheduled) {
LOGGER.info("Scheduled service bound ({}) - analyzing jobs", scheduled);
List<Job> extracted = extractJobsFromScheduled(scheduled);
for (Job job : extracted) {
LOGGER.info("Job extracted from {} : {}", scheduled, job.method().getName());
ManagedScheduledFutureTask task = scheduler.scheduleAtFixedRate(job.function(),
job.period(), job.period(), job.unit());
job.submitted(task);
}
jobs.addAll(extracted);
}
/**
* Invalidate method.
* The system dispatcher has been shutdown, cancelling all submitted tasks.
*/
@Invalidate
public synchronized void invalidate() {
for (Job job : jobs) {
LOGGER.info("Cancelling periodic task {}#{} on invalidation", job.scheduled().getClass().getName(),
job.method().getName());
job.task().cancel(true);
job.submitted(null);
}
}
/**
* Validate method.
* Re-submit all jobs, if there are not submitted yet.
*/
@Validate
public synchronized void validate() {
for (Job job : jobs) {
if (job.task() == null) {
ManagedScheduledFutureTask task = scheduler.scheduleAtFixedRate(job.function(),
job.period(), job.period(), job.unit());
job.submitted(task);
}
}
}
/**
* Unbinds a scheduled service. All jobs created from this scheduled object are cancelled.
*
* @param scheduled the scheduled service
*/
@Unbind
public synchronized void unbindScheduled(Scheduled scheduled) {
for (Job job : jobs.toArray(new Job[jobs.size()])) {
if (job.scheduled().equals(scheduled)) {
LOGGER.info("Cancelling periodic task {}#{}", job.scheduled().getClass().getName(),
job.method().getName());
job.task().cancel(true);
jobs.remove(job);
}
}
}
/**
* Extracts the {@link Job} from a {@link Scheduled} service. If creates an instance of {@link Job} for each
* method annotated with {@link Every} contained in the {@link Scheduled} class.
*
* @param scheduled the scheduled object
* @return the list of job
*/
public static List<Job> extractJobsFromScheduled(Scheduled scheduled) {
Method[] methods = scheduled.getClass().getMethods();
List<Job> listOfJobs = new ArrayList<>();
for (Method method : methods) {
Every every = method.getAnnotation(Every.class);
if (every != null) {
try {
listOfJobs.add(new Job(scheduled, method, every));
} catch (IllegalArgumentException e) {
LOGGER.error("Cannot parse the period '{}' from scheduled method {}.{}", every.value(),
scheduled.getClass().getName(), method.getName(), e);
}
}
}
return listOfJobs;
}
}