/* * JBoss, Home of Professional Open Source * Copyright 2005, JBoss Inc., and individual contributors as indicated * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * This 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; either version 2.1 of * the License, or (at your option) any later version. * * This software 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 software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.jbpm.pvm.internal.cal; import java.io.Serializable; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.regex.Pattern; import org.jbpm.api.Execution; import org.jbpm.api.JbpmException; import org.jbpm.pvm.internal.el.Expression; import org.jbpm.pvm.internal.env.EnvironmentImpl; import org.jbpm.pvm.internal.util.Clock; /** * represents a time duration. * * <p>With the constructor {link {@link #Duration(String)} you can create a * Duration from a text representation. The syntax is as follows * </p> * * <pre> * duration = part [',' part | 'and' part]* * part = number ['business'] unit * number = (0..9)+ * unit = (y|year|years|month|months|w|week|weeks|d|day|days|h|hour|hours|min|minute|minutes|s|sec|second|seconds|milli|millis|millisecond|milliseconds) * </pre> * * <p>Duration is immutable. * </p> * * @author Huisheng Xu */ public class Duration implements Serializable { private static final long serialVersionUID = 1L; boolean isBusinessTime; protected int millis; protected int seconds; protected int minutes; protected int hours; protected int days; protected int weeks; protected int months; protected int years; private final static String dateFormat = "yyyy-MM-dd HH:mm:ss"; private static final Pattern dateDurationPattern = Pattern.compile("\\s*(#\\{.+\\})\\s*" + "(?:(\\+|-)\\s*(\\d+\\s+(?:business\\s+)?\\w+))?\\s*"); private static final Pattern durationPattern = Pattern.compile("\\s*(\\d+\\s+(?:business\\s+)?" + "\\w+)\\s*"); /** constructor for persistence. note that this type is to be immutable. */ protected Duration() { } /** parses the duration from a text * * duration = part [',' part | 'and' part]* * part = number ['business'] unit * number = (0..9)+ * unit = (y|year|years|month|months|w|week|weeks|d|day|days|h|hour|hours|min|minute|minutes|s|sec|second|seconds|milli|millis|millisecond|milliseconds) * * @throws JbpmException if the parsing is unsuccessful */ public Duration(String text) { if (text==null) throw new JbpmException("text is null"); for (String part: splitInParts(text)) { parsePart(part); } isBusinessTime = text.indexOf("business")!=-1; } public static boolean isValidExpression(String durationExpression) { try { new Duration(durationExpression); } catch (JbpmException e) { return false; } return true; } public static Date calculateDueDate(String durationExpression) { Date duedate = null; if (durationExpression != null) { Date baseDate; String durationString = null; char durationSeparator = '+'; // needs to be initialized if (durationExpression.startsWith("#")) { String baseDateEL = durationExpression.substring(0, durationExpression.indexOf("}") + 1); Object result = Expression.create(baseDateEL).evaluate(); if (result instanceof Date) { baseDate = (Date) result; } else if (result instanceof Calendar) { baseDate = ((Calendar) result).getTime(); } else if (result instanceof String) { baseDate = Clock.getTime(); int endOfELIndex = durationExpression.indexOf("}"); if (endOfELIndex < (durationExpression.length() - 1)) { throw new JbpmException("Invalid duedate, didnot support + or - in String type EL."); } durationString = (String) Expression.create(durationExpression, null).evaluate((Execution) null); } else { throw new JbpmException("Invalid basedate type: " + baseDateEL + " is of type " + result.getClass().getName() + ". Only Date and Calendar are supported"); } if (durationString == null) { int endOfELIndex = durationExpression.indexOf("}"); if (endOfELIndex < (durationExpression.length() - 1)) { durationSeparator = durationExpression.substring(endOfELIndex + 1).trim().charAt(0); if (durationSeparator != '+' && durationSeparator != '-') { throw new JbpmException("Invalid duedate, + or - missing after EL"); } durationString = durationExpression.substring(endOfELIndex + 1).substring(2).trim(); } } } else { baseDate = Clock.getTime(); durationString = durationExpression; } if (durationString == null || durationString.length() == 0) { duedate = baseDate; } else { if (durationString.contains("business") && durationSeparator == '-') { throw new JbpmException("Invalid duedate, subtraction ('-') not supported if duedate contains 'business'"); } BusinessCalendar businessCalendar = EnvironmentImpl.getFromCurrent(BusinessCalendar.class); if (durationSeparator == '+') { duedate = businessCalendar.add(baseDate, durationString); } else { duedate = businessCalendar.subtract(baseDate, durationString); } } } return duedate; } public Duration(boolean isBusinessTime, int millis, int seconds, int minutes, int hours, int days, int weeks, int months, int years) { this.isBusinessTime = isBusinessTime; this.millis = millis; this.seconds = seconds; this.minutes = minutes; this.hours = hours; this.days = days; this.weeks = weeks; this.months = months; this.years = years; } private List<String> splitInParts(String text) { List<String> parts = new ArrayList<String>(2); while (text!=null) { int commaIndex = text.indexOf(','); int andIndex = text.indexOf(" and "); if ( ( (commaIndex==-1) && (andIndex!=-1) ) || ( ( (commaIndex!=-1) && (andIndex!=-1) ) && (andIndex<commaIndex) ) ) { String part = text.substring(0, andIndex).trim(); parts.add(part); text = text.substring(andIndex+5); } else if ( ( (commaIndex!=-1) && (andIndex==-1) ) || ( ( (commaIndex!=-1) && (andIndex!=-1) ) && (andIndex>commaIndex) ) ) { String part = text.substring(0, commaIndex).trim(); parts.add(part); text = text.substring(commaIndex+1); } else { parts.add(text.trim()); text = null; } } return parts; } private void parsePart(String part) { int spaceIndex = part.indexOf(' '); if (spaceIndex==-1) { throw new JbpmException("couldn't parse duration part "+part); } String quantityText = part.substring(0, spaceIndex).trim(); spaceIndex = part.lastIndexOf(' '); String unitText = part.substring(spaceIndex+1).trim().toLowerCase(); int quantity; try { quantity = Integer.parseInt(quantityText); } catch (NumberFormatException e) { throw new JbpmException("couldn't parse quantity "+quantityText+" in duration text", e); } FieldSetter fieldSetter = fieldSetters.get(unitText); if (fieldSetter==null) { throw new JbpmException("couldn't parse quantity "+quantityText); } fieldSetter.set(this, quantity); } interface FieldSetter { void set(Duration duration, int quantity); } static class MillisSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.millis = quantity; } } static class SecondSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.seconds = quantity; } } static class MinuteSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.minutes = quantity; } } static class HourSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.hours = quantity; } } static class DaySetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.days = quantity; } } static class WeekSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.weeks = quantity; } } static class MonthSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.months = quantity; } } static class YearSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.years = quantity; } } private static final Map<String, FieldSetter> fieldSetters = new HashMap<String, FieldSetter>(); static { FieldSetter fieldSetter = new MillisSetter(); fieldSetters.put("ms", fieldSetter); fieldSetters.put("millis", fieldSetter); fieldSetters.put("millisecond", fieldSetter); fieldSetters.put("milliseconds", fieldSetter); fieldSetter = new SecondSetter(); fieldSetters.put("s", fieldSetter); fieldSetters.put("sec", fieldSetter); fieldSetters.put("second", fieldSetter); fieldSetters.put("seconds", fieldSetter); fieldSetter = new MinuteSetter(); fieldSetters.put("min", fieldSetter); fieldSetters.put("minute", fieldSetter); fieldSetters.put("minutes", fieldSetter); fieldSetter = new HourSetter(); fieldSetters.put("h", fieldSetter); fieldSetters.put("hour", fieldSetter); fieldSetters.put("hours", fieldSetter); fieldSetter = new DaySetter(); fieldSetters.put("d", fieldSetter); fieldSetters.put("day", fieldSetter); fieldSetters.put("days", fieldSetter); fieldSetter = new WeekSetter(); fieldSetters.put("w", fieldSetter); fieldSetters.put("week", fieldSetter); fieldSetters.put("weeks", fieldSetter); fieldSetter = new MonthSetter(); fieldSetters.put("month", fieldSetter); fieldSetters.put("months", fieldSetter); fieldSetter = new YearSetter(); fieldSetters.put("y", fieldSetter); fieldSetters.put("year", fieldSetter); fieldSetters.put("years", fieldSetter); } public int getDays() { return days; } public int getHours() { return hours; } public boolean isBusinessTime() { return isBusinessTime; } public int getMillis() { return millis; } public int getMinutes() { return minutes; } public int getMonths() { return months; } public int getSeconds() { return seconds; } public int getWeeks() { return weeks; } public int getYears() { return years; } }
这里有个策略模式的应用,duration构造函数中的参数可能带有year、month等,根据字符串的不同选择不同的算法,如果是我的实现可能就是if(str.equals("year"))..else if(str.equals("month"))...else if(str.equals("hour"))..
private void parsePart(String part) { int spaceIndex = part.indexOf(' '); if (spaceIndex==-1) { throw new JbpmException("couldn't parse duration part "+part); } String quantityText = part.substring(0, spaceIndex).trim(); spaceIndex = part.lastIndexOf(' '); String unitText = part.substring(spaceIndex+1).trim().toLowerCase(); int quantity; try { quantity = Integer.parseInt(quantityText); } catch (NumberFormatException e) { throw new JbpmException("couldn't parse quantity "+quantityText+" in duration text", e); } FieldSetter fieldSetter = fieldSetters.get(unitText); if (fieldSetter==null) { throw new JbpmException("couldn't parse quantity "+quantityText); } fieldSetter.set(this, quantity); } interface FieldSetter { void set(Duration duration, int quantity); } static class MillisSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.millis = quantity; } } static class SecondSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.seconds = quantity; } } static class MinuteSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.minutes = quantity; } } static class HourSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.hours = quantity; } } static class DaySetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.days = quantity; } } static class WeekSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.weeks = quantity; } } static class MonthSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.months = quantity; } } static class YearSetter implements FieldSetter { public void set(Duration duration, int quantity) { duration.years = quantity; } } private static final Map<String, FieldSetter> fieldSetters = new HashMap<String, FieldSetter>(); static { FieldSetter fieldSetter = new MillisSetter(); fieldSetters.put("ms", fieldSetter); fieldSetters.put("millis", fieldSetter); fieldSetters.put("millisecond", fieldSetter); fieldSetters.put("milliseconds", fieldSetter); fieldSetter = new SecondSetter(); fieldSetters.put("s", fieldSetter); fieldSetters.put("sec", fieldSetter); fieldSetters.put("second", fieldSetter); fieldSetters.put("seconds", fieldSetter); fieldSetter = new MinuteSetter(); fieldSetters.put("min", fieldSetter); fieldSetters.put("minute", fieldSetter); fieldSetters.put("minutes", fieldSetter); fieldSetter = new HourSetter(); fieldSetters.put("h", fieldSetter); fieldSetters.put("hour", fieldSetter); fieldSetters.put("hours", fieldSetter); fieldSetter = new DaySetter(); fieldSetters.put("d", fieldSetter); fieldSetters.put("day", fieldSetter); fieldSetters.put("days", fieldSetter); fieldSetter = new WeekSetter(); fieldSetters.put("w", fieldSetter); fieldSetters.put("week", fieldSetter); fieldSetters.put("weeks", fieldSetter); fieldSetter = new MonthSetter(); fieldSetters.put("month", fieldSetter); fieldSetters.put("months", fieldSetter); fieldSetter = new YearSetter(); fieldSetters.put("y", fieldSetter); fieldSetters.put("year", fieldSetter); fieldSetters.put("years", fieldSetter); }