Package org.jbpm.env.session.timer

Source Code of org.jbpm.env.session.timer.StandardTimerSession

/**
* 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.Hashtable;
import java.util.Map;
import java.util.TimerTask;
import java.util.Map.Entry;
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.Job;
import org.jbpm.env.session.Timer;
import org.jbpm.env.session.TimerSession;
import org.jbpm.jobexecutor.JobExecutor;
import org.jbpm.jobexecutor.JobSession;
import org.jbpm.pvm.Activity;
import org.jbpm.pvm.impl.ObjectReference;
import org.jbpm.tx.StandardTransaction;
import org.jbpm.tx.Transaction;
import org.jbpm.util.Listener;

/**
* Timers created with this service are committed at the end of the transaction,
* so their execution will be late if the delay is shorter than the transaction.
* In that case, they will be executed at the end of the transaction.
*
* @author Pascal Verdage
*/
public class StandardTimerSession implements TimerSession {
  private static final Logger log = Logger.getLogger(TimerSession.class.getName());
 
  private static class Pair<T1,T2> {
    private T1 first;
    private T2 second;

    public Pair(T1 first, T2 second) {
      this.first = first;
      this.second = second;
    }
   
    public T1 first() {
      return first;
    }
   
    public T2 second() {
      return second;
    }

  }
  private static class NotificationInfo extends Pair<Date,Long> {
    private NotificationInfo(Date date, long repeatDelay) {
      super(date, repeatDelay);
    }
  }

  /* A JobNotificationTask should be in scheduledTimers or toBeScheduledTimers */
  /* contains the JobExecutor notifications that will be scheduled
   * when the transaction ends */
  protected static Map<Long, NotificationInfo> toBeScheduledTimers =
    new Hashtable<Long,NotificationInfo>();
  protected static Map<Long,NotificationTask> scheduledTimers =
    new HashMap<Long,NotificationTask>();
  /* timers to signal the JobExecutor are sent when the transaction is commited */
  protected static java.util.Timer javaTimer = new java.util.Timer();
 
  /* we need to save the environment factory because there is
   * no open environment when the listener is notified;
   * but we keep this internal */
  private EnvironmentFactory environmentFactory;
 
  private static class NotificationTask extends TimerTask {
    private EnvironmentFactory environmentFactory;

    private NotificationTask(EnvironmentFactory environmentFactory) {
      this.environmentFactory = environmentFactory;
    }
   
    @Override
    public void run() {
      log.finer("Sending notification to JobExecutor");
      if (Environment.getCurrent() == null) {
        environmentFactory.openEnvironment();
        Environment.getCurrent().get(JobExecutor.class).jobWasAdded();
        Environment.getCurrent().close();
      } else {
        throw new PvmException("No environment should be open in this thread");
      }
    }
  }

  //this method is called by the binding
  public void start() {
    environmentFactory = Environment.getCurrent().getEnvironmentFactory();
    // notify the job executor after the transaction is completed
    Listener jobExecutorNotifier = new Listener() {
      public void event(Object source, String eventName, Object info) {
        if ( (Transaction.EVENT_AFTERCOMPLETION.equals(eventName))
            && (StandardTransaction.STATE_COMMITTED.equals(info)) ) {

          log.finer("creating " + toBeScheduledTimers.size() +
              " notifications for timers");
          for (Entry<Long, NotificationInfo> entry:
            toBeScheduledTimers.entrySet()) {
            NotificationTask task =
              new NotificationTask(environmentFactory);

            scheduledTimers.put(entry.getKey(), task);
            if (entry.getValue().second() > 0) {
              javaTimer.schedule(task,
                  entry.getValue().first(),
                  entry.getValue().second());
            } else {
              javaTimer.schedule(task, entry.getValue().first());
            }
          }
          toBeScheduledTimers.clear();
        }
      }
    };
    Environment.getCurrent().get(Transaction.class)
    .addListener(jobExecutorNotifier);
  }

  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");
  }

  public void schedule(Timer timer) {
    validScheduling(timer);
    log.fine("scheduling " + timer.getActivityReference() +
        " for " + timer.getEligibleDate() +
        " with repeat every " + timer.getRepeat());

    // then persist the job
    Environment.getCurrent().get(JobSession.class).save(timer);

    // we prepare the JobExecutor notification
    long delay = 0;
    if (timer.getRepeat() != null) {
      BusinessCalendar businessCalendar = new BusinessCalendar();
      Duration duration = new Duration(timer.getRepeat());
      delay = businessCalendar.add(new Date(0), duration).getTime();
    }

    toBeScheduledTimers.put(timer.getDbid(),
        new NotificationInfo(timer.getEligibleDate(), delay));
  }

  public boolean cancel(Timer timer) {
    boolean result = false;
    if (timer != null) {
      //remove JobExecutor notification
      NotificationTask notificationTask =
        scheduledTimers.remove(timer.getDbid());
      if (notificationTask != null)
        result = notificationTask.cancel();

      //remove timer
      log.fine("canceling " + timer);
      if (toBeScheduledTimers.remove(timer.getDbid()) != null)
        result = true;
      Environment.getCurrent().get(JobSession.class).delete(timer);
    }
    return result;
  }

  private Timer getNextTask() {
    return Environment.getCurrent()
    .get(JobSession.class).findNextTimer();
  }

  public ObjectReference<Activity> getNextScheduledActivity() {
    ObjectReference<Activity> result = null;
    Timer timer = getNextTask();
    if (timer != null)
      result = timer.getActivityReference();
    return result;
  }

  public long getNextScheduledActivityTime() {
    long result = -1;
    Timer timer = getNextTask();
    if (timer != null && timer.getEligibleDate() != null)
      result =
        timer.getEligibleDate().getTime() -
        System.currentTimeMillis();
    return result;
  }

  public Collection<ObjectReference<Activity>> getScheduledActivities() {
    Collection<ObjectReference<Activity>> result =
      new ArrayList<ObjectReference<Activity>>();
    Collection<Timer> timers =
      Environment.getCurrent().get(JobSession.class)
      .findAllTimers();
    for (Timer timer : timers)
      result.add(timer.getActivityReference());
    return result;
  }

  public ObjectReference<Activity> getScheduledActivity(long id) {
    ObjectReference<Activity> result = null;
    Job job =
      Environment.getCurrent().get(JobSession.class).get(id);
    Timer timer = null;
    if (job instanceof Timer) {
      timer = (Timer) job;
    }

    if (timer != null)
      result = timer.getActivityReference();

    return result;
  }

  public void initialize() {
    log.info("Re-initialize TimerService");
    // the timers were persisted. We have to schedule notifications
    Collection<Timer> timers =
      Environment.getCurrent().get(JobSession.class)
      .findAllTimers();
    BusinessCalendar businessCalendar = new BusinessCalendar();
    for (Timer timer : timers) {
      Duration duration = new Duration(timer.getRepeat());
      long delay = businessCalendar.add(new Date(0), duration).getTime();
      NotificationInfo notificationInfo =
        new NotificationInfo(timer.getEligibleDate(), delay);

      toBeScheduledTimers.put(timer.getDbid(), notificationInfo);
    }
  }

}
TOP

Related Classes of org.jbpm.env.session.timer.StandardTimerSession

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.