/**
* Copyright (C) 2007 Bull S. A. S.
* Bull, Rue Jean Jaures, B.P.68, 78340, Les Clayes-sous-Bois
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation
* version 2.1 of the License.
* This library 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 for more details.
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
* Floor, Boston, MA 02110-1301, USA.
**/
package org.jbpm.env.session.timer;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.TimerTask;
import java.util.logging.Logger;
import org.jbpm.PvmException;
import org.jbpm.cal.BusinessCalendar;
import org.jbpm.cal.Duration;
import org.jbpm.env.Environment;
import org.jbpm.env.EnvironmentFactory;
import org.jbpm.env.session.Timer;
import org.jbpm.env.session.TimerSession;
import org.jbpm.pvm.Activity;
import org.jbpm.pvm.impl.ObjectReference;
import org.jbpm.tx.Transaction;
/**
* @author Pascal Verdage
*/
/*
* The timerService has one JDK timer and schedule tasks
*/
public class MemoryTimerSession implements TimerSession {
private static final Logger log = Logger.getLogger(TimerSession.class.getName());
private java.util.Timer javaTimer;
Transaction transaction;
protected static long counter = 0;
//task.id is the key
protected static Map<Long, ExecutionTask> scheduledJobs =
new HashMap<Long,ExecutionTask>();
private static class ExecutionTask extends TimerTask {
protected Timer timer;
protected boolean repeat = false;
protected long id;
protected EnvironmentFactory environmentFactory;
public ExecutionTask(Timer timer) {
this.id = timer.getDbid();
this.timer = timer;
if (Environment.getCurrent() == null) {
throw new PvmException("Task scheduling must occur in a valid environment");
}
environmentFactory =
Environment.getCurrent().getEnvironmentFactory();
}
public void setRepeat() {
repeat = true;
}
public ObjectReference<Activity> getActivityReference(){
return timer.getActivityReference();
}
@Override
public void run() {
try {
Activity activity = timer.getActivityReference().get();
if (activity != null) {
Environment tmpEnvironment = null;
try {
if (Environment.getCurrent() == null) {
tmpEnvironment =
environmentFactory.openEnvironment();
}
activity.execute(timer.getExecution());
} finally {
if (tmpEnvironment != null)
tmpEnvironment.close();
}
} else {
throw new PvmException("Unable to get the activity for the task");
}
} catch (Exception e) {
throw new PvmException(e);
} finally {
if (!repeat) {
scheduledJobs.remove(id);
}
}
}
}
public MemoryTimerSession() {
super();
javaTimer = new java.util.Timer();
}
protected static void validScheduling(Timer timer) {
if (timer == null)
throw new IllegalArgumentException("null timer scheduled");
if (timer.getActivityReference() == null)
throw new IllegalArgumentException("null activity scheduled");
if (timer.getEligibleDate() == null)
throw new IllegalArgumentException("timer scheduled at null date");
if (timer.getEligibleDate().getTime() < 0)
throw new IllegalArgumentException("timer scheduled with a negative date");
}
/*
* Create an ExecutionTask and schedule it
*/
public void schedule(Timer timer) {
validScheduling(timer);
log.fine("scheduling " + timer.getActivityReference() +
" for " + timer.getEligibleDate() +
" with repeat every " + timer.getRepeat());
long id = timer.getDbid();
if (id == 0) {
id = ++counter;
timer.setDbid(id);
}
ExecutionTask task = new ExecutionTask(timer);
long repeatDelay = 0;
if (timer.getRepeat() != null) {
BusinessCalendar businessCalendar = new BusinessCalendar();
Duration duration = new Duration(timer.getRepeat());
repeatDelay = businessCalendar.add(new Date(0), duration).getTime();
}
try {
Date eligibleDate = timer.getEligibleDate();
if (repeatDelay > 0) {
task.setRepeat();
javaTimer.schedule(task, eligibleDate, repeatDelay);
} else {
javaTimer.schedule(task, eligibleDate);
}
} catch (IllegalStateException e) {
throw new PvmException(e.getMessage(), e);
}
scheduledJobs.put(id, task);
}
public boolean cancel(Timer timer) {
log.fine("canceling timer " + timer);
ExecutionTask task = scheduledJobs.remove(timer.getDbid());
if (task != null)
task.cancel();
return task != null;
}
public ObjectReference<Activity> getNextScheduledActivity() {
long minimum = Long.MAX_VALUE;
ObjectReference<Activity>result = null;
for (ExecutionTask task : scheduledJobs.values()) {
if (task.scheduledExecutionTime() < minimum) {
minimum = task.scheduledExecutionTime();
result = task.getActivityReference();
}
}
return result;
}
public long getNextScheduledActivityTime() {
long minimum = Long.MAX_VALUE;
for (ExecutionTask task : scheduledJobs.values()) {
if (task.scheduledExecutionTime() < minimum) {
minimum = task.scheduledExecutionTime();
}
}
if (minimum == Long.MAX_VALUE)
return -1;
else
return minimum - System.currentTimeMillis();
}
public Collection<ObjectReference<Activity>> getScheduledActivities() {
Collection<ObjectReference<Activity>> result =
new ArrayList<ObjectReference<Activity>>();
for (ExecutionTask task : scheduledJobs.values()) {
result.add(task.getActivityReference());
}
return result;
}
public ObjectReference<Activity> getScheduledActivity(long id) {
ObjectReference<Activity> result = null;
ExecutionTask task = scheduledJobs.get(id);
if (task != null)
result = task.getActivityReference();
return result;
}
public void initialize() {
// Nothing to do. We can't retrieve any data
// with in-memory utilization
}
}