com.almende.eve.scheduler.ClockSchedulerFactory Maven / Gradle / Ivy
package com.almende.eve.scheduler;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.UUID;
import java.util.logging.Logger;
import org.joda.time.DateTime;
import com.almende.eve.agent.Agent;
import com.almende.eve.agent.AgentFactory;
import com.almende.eve.agent.annotation.Sender;
import com.almende.eve.clock.Clock;
import com.almende.eve.clock.RunnableClock;
import com.almende.eve.rpc.RequestParams;
import com.almende.eve.rpc.jsonrpc.JSONRequest;
import com.almende.eve.rpc.jsonrpc.jackson.JOM;
public class ClockSchedulerFactory implements SchedulerFactory {
Map schedulers = new HashMap();
AgentFactory agentFactory = null;
/**
* This constructor is called when constructed by the AgentFactory
*
* @param agentFactory
* @param params
*/
public ClockSchedulerFactory(AgentFactory agentFactory,
Map params) {
this(agentFactory, "");
}
public ClockSchedulerFactory(AgentFactory agentFactory, String id) {
this.agentFactory = agentFactory;
}
@Override
public Scheduler getScheduler(String agentId) {
synchronized (schedulers) {
if (schedulers.containsKey(agentId)) return schedulers.get(agentId);
Scheduler scheduler;
try {
scheduler = new ClockScheduler(agentId, agentFactory);
schedulers.put(agentId, scheduler);
return scheduler;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
@Override
public void destroyScheduler(String agentId) {
synchronized (schedulers) {
schedulers.remove(agentId);
}
}
}
class ClockScheduler implements Scheduler, Runnable {
static final Logger logger = Logger.getLogger("ClockScheduler");
final Agent myAgent;
final Clock myClock;
public ClockScheduler(String agentId, AgentFactory factory)
throws Exception {
myAgent = factory.getAgent(agentId);
if (myAgent == null) {
Logger.getLogger("ClockScheduler").severe(
"Error: Agent not found:" + agentId);
throw new Exception(
"Trying to getScheduler() on a not existing agent:"
+ agentId);
}
myClock = new RunnableClock();
run();
}
@SuppressWarnings("unchecked")
public TaskEntry getFirstTask() {
TreeSet timeline = (TreeSet) myAgent.getState()
.get("_taskList");
if (timeline != null && !timeline.isEmpty()) {
TaskEntry task = timeline.first();
while (task != null && task.active) {
task = timeline.higher(task);
}
return task;
}
return null;
}
public void putTask(TaskEntry task) {
putTask(task, false);
}
@SuppressWarnings("unchecked")
public void putTask(TaskEntry task, boolean onlyIfExists) {
Set oldTimeline = (TreeSet) myAgent
.getState().get("_taskList");
Set timeline = null;
boolean found = false;
if (oldTimeline != null) {
timeline = new TreeSet();
TaskEntry[] arr = oldTimeline.toArray(new TaskEntry[0]);
for (TaskEntry entry : arr) {
if (!entry.taskId.equals(task.taskId)) {
timeline.add(entry);
} else {
found = true;
timeline.add(task);
}
}
}
if (!found && !onlyIfExists) {
if (timeline == null) timeline = new TreeSet();
timeline.add(task);
}
if (!myAgent.getState().putIfUnchanged("_taskList", (Serializable)timeline,
(Serializable) oldTimeline)) {
logger.severe("need to retry putTask...");
putTask(task, onlyIfExists); // recursive retry....
return;
}
}
@SuppressWarnings("unchecked")
@Override
public void cancelTask(String id) {
TreeSet oldTimeline = (TreeSet) myAgent
.getState().get("_taskList");
TreeSet timeline = null;
if (oldTimeline != null) {
timeline = new TreeSet();
TaskEntry[] arr = oldTimeline.toArray(new TaskEntry[0]);
for (TaskEntry entry : arr) {
if (!entry.taskId.equals(id)) {
timeline.add(entry);
}
}
}
if (!myAgent.getState().putIfUnchanged("_taskList", timeline,
oldTimeline)) {
logger.severe("need to retry cancelTask...");
cancelTask(id); // recursive retry....
return;
}
}
public void runTask(final TaskEntry task) {
// logger.warning("Running "+task.taskId+" at "+DateTime.now().toString()+" Due: "+task.due.toString());
if (task.interval <= 0) {
cancelTask(task.taskId); // Remove from list
} else {
if (!task.sequential) {
task.due = DateTime.now().plus(task.interval);
} else {
task.active = true;
}
putTask(task, true);
}
myClock.runInPool(new Runnable() {
@Override
public void run() {
try {
RequestParams params = new RequestParams();
String senderUrl = "local://" + myAgent.getId();
params.put(Sender.class, senderUrl);
myAgent.getAgentFactory().receive(myAgent.getId(),
task.request, params);
if (task.interval > 0 && task.sequential) {
task.due = DateTime.now().plus(task.interval);
task.active = false;
putTask(task, true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
});
}
@Override
public String createTask(JSONRequest request, long delay) {
return createTask(request, delay, false, false);
}
@Override
public String createTask(JSONRequest request, long delay, boolean interval,
boolean sequential) {
TaskEntry task = new TaskEntry(DateTime.now().plus(delay), request,
(interval ? delay : 0), sequential);
if (delay <= 0) {
runTask(task);
} else {
putTask(task);
run();
}
return task.taskId;
}
@SuppressWarnings("unchecked")
@Override
public Set getTasks() {
Set result = new HashSet();
TreeSet timeline = (TreeSet) myAgent.getState()
.get("_taskList");
if (timeline == null) return result;
for (TaskEntry entry : timeline) {
result.add(entry.taskId);
}
return result;
}
@Override
public void run() {
TaskEntry task = getFirstTask();
if (task != null) {
if (task.due.isBeforeNow()) {
runTask(task);
run();// recursive call next task
return;
}
myClock.requestTrigger(myAgent.getId(), task.due, this);
}
}
@Override
public String toString() {
@SuppressWarnings("unchecked")
TreeSet timeline = (TreeSet) myAgent.getState()
.get("_taskList");
return (timeline != null) ? timeline.toString() : "[]";
}
}
class TaskEntry implements Comparable, Serializable {
private static final long serialVersionUID = -2402975617148459433L;
// TODO, make JSONRequest.equals() state something about real equal tasks,
// use it as deduplication!
String taskId;
JSONRequest request;
DateTime due;
long interval = 0;
boolean sequential = true;
boolean active = false;
public TaskEntry(DateTime due, JSONRequest request, long interval,
boolean sequential) {
taskId = UUID.randomUUID().toString();
this.request = request;
this.due = due;
this.interval = interval;
this.sequential = sequential;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof TaskEntry)) return false;
TaskEntry other = (TaskEntry) o;
return taskId.equals(other.taskId);
}
@Override
public int hashCode() {
return taskId.hashCode();
}
@Override
public int compareTo(TaskEntry o) {
if (equals(o)) return 0;
if (due.equals(o.due)) return 0;
return due.compareTo(o.due);
}
public String getTaskId() {
return taskId;
}
public JSONRequest getRequest() {
return request;
}
public String getDue() {
return due.toString();
}
@Override
public String toString() {
try {
return JOM.getInstance().writeValueAsString(this);
} catch (Exception e) {
e.printStackTrace();
return "{\"taskId\":" + taskId + ",\"due\":" + due + "}";
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy