/*******************************************************************************
* Copyright 2013 Michael Marconi
*
* 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.
******************************************************************************/
package oncue.scheduler;
import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import oncue.backingstore.BackingStore;
import oncue.common.comparators.JobComparator;
import oncue.common.messages.Job;
import akka.event.LoggingAdapter;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Sets;
/**
* An encapsulated job queue of unscheduled {@linkplain Job}s that relies on a backing store for
* persistence.
*/
public class UnscheduledJobs {
// The persistent backing store
private final BackingStore backingStore;
private final LoggingAdapter log;
// The prioritised queue of unscheduled jobs
private SortedSet<Job> unscheduledJobs = new TreeSet<>(new JobComparator());
/**
* @param backingStore is an instance of {@linkplain BackingStore}
*/
public UnscheduledJobs(BackingStore backingStore, LoggingAdapter log,
Comparator<Job> jobComparator) {
this.unscheduledJobs = new TreeSet<>(jobComparator);
this.backingStore = backingStore;
this.log = log;
restoreJobs();
}
/**
* Add a job to the queue
*/
public void addJob(Job job) {
backingStore.addUnscheduledJob(job);
unscheduledJobs.add(job);
}
/**
* @return the number of jobs in the queue
*/
public int getSize() {
return unscheduledJobs.size();
}
/**
* @return the set of worker types that enqueued jobs require to process
*/
public Set<String> getWorkerTypes() {
Set<String> workerTypes = new HashSet<>();
Iterator<Job> itrJobs = unscheduledJobs.iterator();
while (itrJobs.hasNext()) {
Job job = itrJobs.next();
workerTypes.add(job.getWorkerType());
}
return workerTypes;
}
/**
* @return true if there are no more unscheduled jobs
*/
public boolean isEmpty() {
return unscheduledJobs.isEmpty();
}
/**
* Determine if there are unscheduled jobs for the specified worker type.
*/
public boolean isWorkAvailable(Set<String> workerTypes) {
Iterator<Job> itrJobs = unscheduledJobs.iterator();
while (itrJobs.hasNext()) {
Job job = itrJobs.next();
if (workerTypes.contains(job.getWorkerType()))
return true;
}
return false;
}
/**
* @return a thread-safe iterator over the unscheduled jobs.
*/
public Iterator<Job> iterator() {
return unscheduledJobs.iterator();
}
/**
* Remove a job from anywhere in the queue
*
* @return a boolean, indicating if the removal was successful
*/
public boolean removeJobById(final long jobId) {
boolean removed = Iterables.removeIf(unscheduledJobs, new Predicate<Job>() {
@Override
public boolean apply(Job input) {
return input.getId() == jobId;
}
});
if (removed)
backingStore.removeUnscheduledJobById(jobId);
return removed;
}
/**
* Remove a list of jobs from anywhere in the queue
*
* @return a boolean, indicating if the removal was successful
*/
public boolean removeJobs(List<Job> jobs) {
final Set<Long> jobIds = Sets.newHashSet(Iterators.transform(jobs.iterator(),
new Function<Job, Long>() {
@Override
public Long apply(Job input) {
return input.getId();
}
}));
boolean removed = Iterables.removeIf(unscheduledJobs, new Predicate<Job>() {
@Override
public boolean apply(Job input) {
return jobIds.contains(input.getId());
}
});
if (backingStore != null && removed)
for (Job job : jobs) {
backingStore.removeUnscheduledJobById(job.getId());
}
return removed;
}
/**
* Restore any scheduled and unscheduled jobs from the backing store
*/
private void restoreJobs() {
List<Job> restoredJobs = backingStore.restoreJobs();
if (restoredJobs != null && !restoredJobs.isEmpty())
log.info("Restoring {} jobs from the backing store", restoredJobs.size());
unscheduledJobs.addAll(restoredJobs);
}
}