All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.activiti.engine.impl.calendar.DurationHelper Maven / Gradle / Ivy

There is a newer version: 7.1.0.M6
Show newest version
/*
 * 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 org.activiti.engine.impl.calendar;

import java.util.Arrays;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.Duration;

import org.activiti.engine.ActivitiIllegalArgumentException;
import org.activiti.engine.impl.util.TimeZoneUtil;
import org.activiti.engine.runtime.ClockReader;
import org.joda.time.DateTimeZone;
import org.joda.time.format.ISODateTimeFormat;

/**
 * helper class for parsing ISO8601 duration format (also recurring) and computing next timer date
 */
public class DurationHelper {

  private Calendar start;
  private Calendar end;
  private Duration period;
  private boolean isRepeat;
  private int times;
  private int maxIterations = -1;
  private boolean repeatWithNoBounds;

  private DatatypeFactory datatypeFactory;

  public Calendar getStart() {
    return start;
  }

  public Calendar getEnd() {
    return end;
  }

  public Duration getPeriod() {
    return period;
  }

  public boolean isRepeat() {
    return isRepeat;
  }

  public int getTimes() {
    return times;
  }

  protected ClockReader clockReader;

  public DurationHelper(String expressionS, int maxIterations, ClockReader clockReader) throws Exception {
    this.clockReader = clockReader;
    this.maxIterations = maxIterations;
    List expression = Arrays.asList(expressionS.split("/"));
    datatypeFactory = DatatypeFactory.newInstance();

    if (expression.size() > 3 || expression.isEmpty()) {
      throw new ActivitiIllegalArgumentException("Cannot parse duration");
    }
    if (expression.get(0).startsWith("R")) {
      isRepeat = true;
      times = expression.get(0).length() == 1 ? Integer.MAX_VALUE-1 : Integer.parseInt(expression.get(0).substring(1));
      
      if (expression.get(0).equals("R")) { // R without params
      	repeatWithNoBounds = true;
      }
      
      expression = expression.subList(1, expression.size());
    }

    if (isDuration(expression.get(0))) {
      period = parsePeriod(expression.get(0));
      end = expression.size() == 1 ? null : parseDate(expression.get(1));
    } else {
      start = parseDate(expression.get(0));
      if (isDuration(expression.get(1)))  {
        period = parsePeriod(expression.get(1));
      } else {
        end = parseDate(expression.get(1));
        period = datatypeFactory.newDuration(end.getTimeInMillis() - start.getTimeInMillis());
      }
    }
    if (start == null) {
      start = clockReader.getCurrentCalendar();
    }

  }

  public DurationHelper(String expressionS, ClockReader clockReader) throws Exception {
    this(expressionS, -1, clockReader);
  }

  public Calendar getCalendarAfter() {
    return getCalendarAfter(clockReader.getCurrentCalendar());
  }

  public Calendar getCalendarAfter(Calendar time) {
    if (isRepeat) {
      return getDateAfterRepeat(time);
    }
    // TODO: is this correct?
    if (end != null) {
      return end;
    }
    return add(start, period);
  }

  public Boolean isValidDate(Date newTimer) {
    return end == null || end.getTime().after(newTimer) || end.getTime().equals(newTimer);
  }

  public Date getDateAfter() {
    Calendar date = getCalendarAfter();

    return date == null ? null : date.getTime();
  }

  private Calendar getDateAfterRepeat(Calendar date) {
  	Calendar current = TimeZoneUtil.convertToTimeZone(start, date.getTimeZone());
  	
  	if (repeatWithNoBounds) {
  		
      while(current.before(date) || current.equals(date)) { // As long as current date is not past the engine date, we keep looping
      	Calendar newTime = add(current, period);
        if (newTime.equals(current) || newTime.before(current)) {
        	break;
        }
        current = newTime;
      }
      
  		
  	} else {
  		
	    int maxLoops = times;
	    if (maxIterations > 0) {
	      maxLoops = maxIterations - times;
	    }
	    for (int i = 0; i < maxLoops+1 && !current.after(date); i++) {
	      current = add(current, period);
	    }
	
  	}
  	return current.before(date) ? date : TimeZoneUtil.convertToTimeZone(current, clockReader.getCurrentTimeZone());
  	
  }

  protected Calendar add(Calendar date, Duration duration) {
    Calendar calendar = (Calendar) date.clone();

    // duration.addTo does not account for daylight saving time (xerces),
    // reversing order of addition fixes the problem
    calendar.add(Calendar.SECOND, duration.getSeconds() * duration.getSign());
    calendar.add(Calendar.MINUTE, duration.getMinutes() * duration.getSign());
    calendar.add(Calendar.HOUR, duration.getHours() * duration.getSign());
    calendar.add(Calendar.DAY_OF_MONTH, duration.getDays() * duration.getSign());
    calendar.add(Calendar.MONTH, duration.getMonths() * duration.getSign());
    calendar.add(Calendar.YEAR, duration.getYears() * duration.getSign());

    return calendar;
  }

  protected Calendar parseDate(String date) throws Exception {
    return ISODateTimeFormat.dateTimeParser().withZone(DateTimeZone.forTimeZone(clockReader.getCurrentTimeZone())).parseDateTime(date).toCalendar(null);
  }

  protected Duration parsePeriod(String period) throws Exception {
    return datatypeFactory.newDuration(period);
  }

  protected boolean isDuration(String time) {
    return time.startsWith("P");
  }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy