svn commit: r695688 - in /ofbiz/trunk/framework/service: ./ data/ entitydef/ src/org/ofbiz/service/calendar/

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
1 message Options
Reply | Threaded
Open this post in threaded view
|

svn commit: r695688 - in /ofbiz/trunk/framework/service: ./ data/ entitydef/ src/org/ofbiz/service/calendar/

adrianc
Author: adrianc
Date: Mon Sep 15 16:40:31 2008
New Revision: 695688

URL: http://svn.apache.org/viewvc?rev=695688&view=rev
Log:
Temporal expression recurring event framework. Based upon a design by Martin Fowler, and discussed in https://issues.apache.org/jira/browse/OFBIZ-1956.

Added:
    ofbiz/trunk/framework/service/data/ServiceDemoData.xml   (with props)
    ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/DateRange.java   (with props)
    ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpression.java   (with props)
    ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressionWorker.java   (with props)
    ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java   (with props)
    ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TimeDuration.java   (with props)
Modified:
    ofbiz/trunk/framework/service/entitydef/entitymodel.xml
    ofbiz/trunk/framework/service/ofbiz-component.xml

Added: ofbiz/trunk/framework/service/data/ServiceDemoData.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/data/ServiceDemoData.xml?rev=695688&view=auto
==============================================================================
--- ofbiz/trunk/framework/service/data/ServiceDemoData.xml (added)
+++ ofbiz/trunk/framework/service/data/ServiceDemoData.xml Mon Sep 15 16:40:31 2008
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+Licensed to the Apache Software Foundation (ASF) under one
+or more contributor license agreements.  See the NOTICE file
+distributed with this work for additional information
+regarding copyright ownership.  The ASF licenses this file
+to you 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.
+-->
+
+<entity-engine-xml>
+    <!-- Temporal Expression demo data -->
+    
+    <!-- Pre-define all days of the week (Sunday -> Saturday) -->
+    <TemporalExpression tempExprId="DAYOFWEEK_01" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="1" integer2="1"/>
+    <TemporalExpression tempExprId="DAYOFWEEK_02" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="2" integer2="2"/>
+    <TemporalExpression tempExprId="DAYOFWEEK_03" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="3" integer2="3"/>
+    <TemporalExpression tempExprId="DAYOFWEEK_04" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="4" integer2="4"/>
+    <TemporalExpression tempExprId="DAYOFWEEK_05" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="5" integer2="5"/>
+    <TemporalExpression tempExprId="DAYOFWEEK_06" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="6" integer2="6"/>
+    <TemporalExpression tempExprId="DAYOFWEEK_07" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="7" integer2="7"/>
+
+    <!-- Pre-define some day of the week ranges -->
+    <TemporalExpression tempExprId="MON_TO_FRI" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="2" integer2="6"/>
+    <TemporalExpression tempExprId="SAT_TO_SUN" tempExprTypeId="DAY_OF_WEEK_RANGE" integer1="7" integer2="1"/>
+
+    <!-- Pre-define all 13 months (January -> Undecimber) -->
+    <TemporalExpression tempExprId="MONTH_RANGE_01" tempExprTypeId="MONTH_RANGE" integer1="0" integer2="0"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_02" tempExprTypeId="MONTH_RANGE" integer1="1" integer2="1"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_03" tempExprTypeId="MONTH_RANGE" integer1="2" integer2="2"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_04" tempExprTypeId="MONTH_RANGE" integer1="3" integer2="3"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_05" tempExprTypeId="MONTH_RANGE" integer1="4" integer2="4"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_06" tempExprTypeId="MONTH_RANGE" integer1="5" integer2="5"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_07" tempExprTypeId="MONTH_RANGE" integer1="6" integer2="6"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_08" tempExprTypeId="MONTH_RANGE" integer1="7" integer2="7"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_09" tempExprTypeId="MONTH_RANGE" integer1="8" integer2="8"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_10" tempExprTypeId="MONTH_RANGE" integer1="9" integer2="9"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_11" tempExprTypeId="MONTH_RANGE" integer1="10" integer2="10"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_12" tempExprTypeId="MONTH_RANGE" integer1="11" integer2="11"/>
+    <TemporalExpression tempExprId="MONTH_RANGE_13" tempExprTypeId="MONTH_RANGE" integer1="12" integer2="12"/>
+
+    <!-- Pre-define all 31 days of the month -->
+    <TemporalExpression tempExprId="DAYOFMONTH_01" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="1" integer2="1"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_02" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="2" integer2="2"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_03" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="3" integer2="3"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_04" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="4" integer2="4"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_05" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="5" integer2="5"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_06" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="6" integer2="6"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_07" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="7" integer2="7"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_08" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="8" integer2="8"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_09" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="9" integer2="9"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_10" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="10" integer2="10"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_11" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="11" integer2="11"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_12" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="12" integer2="12"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_13" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="13" integer2="13"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_14" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="14" integer2="14"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_15" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="15" integer2="15"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_16" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="16" integer2="16"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_17" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="17" integer2="17"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_18" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="18" integer2="18"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_19" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="19" integer2="19"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_20" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="20" integer2="20"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_21" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="21" integer2="21"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_22" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="22" integer2="22"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_23" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="23" integer2="23"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_24" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="24" integer2="24"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_25" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="25" integer2="25"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_26" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="26" integer2="26"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_27" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="27" integer2="27"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_28" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="28" integer2="28"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_29" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="29" integer2="29"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_30" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="30" integer2="30"/>
+    <TemporalExpression tempExprId="DAYOFMONTH_31" tempExprTypeId="DAY_OF_MONTH_RANGE" integer1="31" integer2="31"/>
+
+    <!-- Pre-define nth Monday of the month - many US observances occur on a Monday -->
+    <TemporalExpression tempExprId="1ST_MONDAY_IN_MONTH" tempExprTypeId="DAY_IN_MONTH" integer1="2" integer2="1"/>
+    <TemporalExpression tempExprId="2ND_MONDAY_IN_MONTH" tempExprTypeId="DAY_IN_MONTH" integer1="2" integer2="2"/>
+    <TemporalExpression tempExprId="3RD_MONDAY_IN_MONTH" tempExprTypeId="DAY_IN_MONTH" integer1="2" integer2="3"/>
+    <TemporalExpression tempExprId="4TH_MONDAY_IN_MONTH" tempExprTypeId="DAY_IN_MONTH" integer1="2" integer2="4"/>
+    <TemporalExpression tempExprId="LAST_MONDAY_IN_MONTH" tempExprTypeId="DAY_IN_MONTH" integer1="2" integer2="-1"/>
+
+    <!-- A US federal holiday schedule -->
+    <TemporalExpression tempExprId="US_FED_HOLIDAYS" tempExprTypeId="UNION"/>
+    <!-- New Years Day -->
+    <TemporalExpression tempExprId="JANUARY_FIRST" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="JANUARY_FIRST" toTempExprId="MONTH_RANGE_01"/>
+    <TemporalExpressionAssoc fromTempExprId="JANUARY_FIRST" toTempExprId="DAYOFMONTH_01"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="JANUARY_FIRST"/>
+    <!-- Martin Luther King Day -->
+    <TemporalExpression tempExprId="MLK_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="MLK_DAY" toTempExprId="MONTH_RANGE_01"/>
+    <TemporalExpressionAssoc fromTempExprId="MLK_DAY" toTempExprId="3RD_MONDAY_IN_MONTH"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="MLK_DAY"/>
+    <!-- Presidents Day -->
+    <TemporalExpression tempExprId="PRESIDENTS_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="PRESIDENTS_DAY" toTempExprId="MONTH_RANGE_02"/>
+    <TemporalExpressionAssoc fromTempExprId="PRESIDENTS_DAY" toTempExprId="3RD_MONDAY_IN_MONTH"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="PRESIDENTS_DAY"/>
+    <!-- Memorial Day -->
+    <TemporalExpression tempExprId="MEMORIAL_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="MEMORIAL_DAY" toTempExprId="MONTH_RANGE_05"/>
+    <TemporalExpressionAssoc fromTempExprId="MEMORIAL_DAY" toTempExprId="LAST_MONDAY_IN_MONTH"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="MEMORIAL_DAY"/>
+    <!-- Independence Day -->
+    <TemporalExpression tempExprId="INDEPENDENCE_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="INDEPENDENCE_DAY" toTempExprId="MONTH_RANGE_07"/>
+    <TemporalExpressionAssoc fromTempExprId="INDEPENDENCE_DAY" toTempExprId="DAYOFMONTH_04"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="INDEPENDENCE_DAY"/>
+    <!-- Labor Day -->
+    <TemporalExpression tempExprId="LABOR_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="LABOR_DAY" toTempExprId="MONTH_RANGE_09"/>
+    <TemporalExpressionAssoc fromTempExprId="LABOR_DAY" toTempExprId="1ST_MONDAY_IN_MONTH"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="LABOR_DAY"/>
+    <!-- Columbus Day -->
+    <TemporalExpression tempExprId="COLUMBUS_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="COLUMBUS_DAY" toTempExprId="MONTH_RANGE_10"/>
+    <TemporalExpressionAssoc fromTempExprId="COLUMBUS_DAY" toTempExprId="2ND_MONDAY_IN_MONTH"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="COLUMBUS_DAY"/>
+    <!-- Veterans Day -->
+    <TemporalExpression tempExprId="VETERANS_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="VETERANS_DAY" toTempExprId="MONTH_RANGE_11"/>
+    <TemporalExpressionAssoc fromTempExprId="VETERANS_DAY" toTempExprId="DAYOFMONTH_11"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="VETERANS_DAY"/>
+    <!-- Thanksgiving Day -->
+    <TemporalExpression tempExprId="THANKSGIVING_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpression tempExprId="4TH_THURS_IN_MONTH" tempExprTypeId="DAY_IN_MONTH" integer1="5" integer2="4"/>
+    <TemporalExpressionAssoc fromTempExprId="THANKSGIVING_DAY" toTempExprId="MONTH_RANGE_11"/>
+    <TemporalExpressionAssoc fromTempExprId="THANKSGIVING_DAY" toTempExprId="4TH_THURS_IN_MONTH"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="THANKSGIVING_DAY"/>
+    <!-- Christmas Day -->
+    <TemporalExpression tempExprId="CHRISTMAS_DAY" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpressionAssoc fromTempExprId="CHRISTMAS_DAY" toTempExprId="MONTH_RANGE_12"/>
+    <TemporalExpressionAssoc fromTempExprId="CHRISTMAS_DAY" toTempExprId="DAYOFMONTH_25"/>
+    <TemporalExpressionAssoc fromTempExprId="US_FED_HOLIDAYS" toTempExprId="CHRISTMAS_DAY"/>
+
+    <!-- A semi-monthly expression -> 1st and 15th of the month -->
+    <TemporalExpression tempExprId="1ST_AND_15TH_MONTH" tempExprTypeId="UNION"/>
+    <TemporalExpressionAssoc fromTempExprId="1ST_AND_15TH_MONTH" toTempExprId="DAYOFMONTH_01"/>
+    <TemporalExpressionAssoc fromTempExprId="1ST_AND_15TH_MONTH" toTempExprId="DAYOFMONTH_15"/>
+
+    <!-- A Mon-Fri expression that excludes US federal holidays -->
+    <TemporalExpression tempExprId="GOVT_WORK_SCHED" tempExprTypeId="DIFFERENCE"/>
+    <TemporalExpressionAssoc fromTempExprId="GOVT_WORK_SCHED" toTempExprId="MON_TO_FRI" exprAssocType="INCLUDE"/>
+    <TemporalExpressionAssoc fromTempExprId="GOVT_WORK_SCHED" toTempExprId="US_FED_HOLIDAYS" exprAssocType="EXCLUDE"/>
+
+    <!-- An 8am-5pm Mon-Fri expression that excludes US federal holidays -->
+    <TemporalExpression tempExprId="DAILY_GRIND" tempExprTypeId="INTERSECTION"/>
+    <TemporalExpression tempExprId="8AM_TO_5PM" tempExprTypeId="TIME_OF_DAY_RANGE" string1="08:00" string2="17:00"/>
+    <TemporalExpressionAssoc fromTempExprId="DAILY_GRIND" toTempExprId="8AM_TO_5PM"/>
+    <TemporalExpressionAssoc fromTempExprId="DAILY_GRIND" toTempExprId="GOVT_WORK_SCHED"/>
+
+    <!-- An every-other-Monday at 5pm expression -->
+    <TemporalExpression tempExprId="5PM_BIMONDAY" tempExprTypeId="FREQUENCY" date1="2000-01-03 17:00:00.000" integer1="5" integer2="14"/>
+
+    <!-- TemporalExpression field details... -->
+    
+    <!-- The TemporalExpression field meanings depend upon what type of expression it is. The integer
+        values are typically obtained from the java.util.Calendar field constants. For more
+        information, see the org.ofbiz.service.calendar.TemporalExpressions.java file.
+        
+        tempExprTypeId       integer1       integer2        date1  date2  string1    string2
+        ==================== ============== =============== ====== ====== ========== ========
+        DATE_RANGE                                          start  end
+        TIME_OF_DAY_RANGE                                                 start [1]  end [1]
+        DAY_OF_WEEK_RANGE    start [2]      end [2]
+        MONTH_RANGE          start [3]      end [3]
+        DAY_OF_MONTH_RANGE   start [4]      end [4]
+        DAY_IN_MONTH         day [2]        occurrence [5]
+        FREQUENCY            freq type [6]  freq count [7]  start
+
+        [1] hh:mm:ss.sss
+        [2] Day of week: 1 = Sunday, 7 = Saturday
+        [3] Month: January = 0, Undecimber = 12
+        [4] Day of month: 1 to 31
+        [5] Integer: -5 to +5, zero excluded
+        [6] Second = 13, Minute = 12, Hour = 11, Day = 5, Month = 2, Year = 1
+        [7] Positive integer, zero excluded
+    -->
+    
+</entity-engine-xml>

Propchange: ofbiz/trunk/framework/service/data/ServiceDemoData.xml
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: ofbiz/trunk/framework/service/entitydef/entitymodel.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/entitydef/entitymodel.xml?rev=695688&r1=695687&r2=695688&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/entitydef/entitymodel.xml (original)
+++ ofbiz/trunk/framework/service/entitydef/entitymodel.xml Mon Sep 15 16:40:31 2008
@@ -128,6 +128,39 @@
         <prim-key field="runtimeDataId"/>
     </entity>
 
+    <!-- Note: TemporalExpression values should be treated as immutable.
+        In other words, they should be created once and left unmodified by user
+        interaction. -->
+    <entity entity-name="TemporalExpression"
+            package-name="org.ofbiz.service.schedule"
+            title="Temporal Expression">
+      <field name="tempExprId" type="id-ne"></field>
+      <field name="tempExprTypeId" type="id-ne"></field>
+      <field name="date1" type="date-time"></field>
+      <field name="date2" type="date-time"></field>
+      <field name="integer1" type="numeric"></field>
+      <field name="integer2" type="numeric"></field>
+      <field name="string1" type="id"></field>
+      <field name="string2" type="id"></field>
+      <prim-key field="tempExprId"/>
+    </entity>
+
+    <entity entity-name="TemporalExpressionAssoc"
+            package-name="org.ofbiz.service.schedule"
+            title="Temporal Expression Association">
+      <field name="fromTempExprId" type="id-ne"><description>The "parent" expression</description></field>
+      <field name="toTempExprId" type="id-ne"><description>The "child" expression</description></field>
+      <field name="exprAssocType" type="id"><description>Expression association type, applies to DIFFERENCE expression types only. Valid values are INCLUDED or EXCLUDED.</description></field>
+      <prim-key field="fromTempExprId"/>
+      <prim-key field="toTempExprId"/>
+      <relation type="one" fk-name="TEMP_EXPR_FROM" rel-entity-name="TemporalExpression" title="From">
+        <key-map field-name="fromTempExprId" rel-field-name="tempExprId"/>
+      </relation>
+      <relation type="one" fk-name="TEMP_EXPR_TO" rel-entity-name="TemporalExpression" title="To">
+        <key-map field-name="toTempExprId" rel-field-name="tempExprId"/>
+      </relation>
+    </entity>
+
   <!-- ========================================================= -->
   <!-- org.ofbiz.service.semaphore -->
   <!-- ========================================================= -->

Modified: ofbiz/trunk/framework/service/ofbiz-component.xml
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/ofbiz-component.xml?rev=695688&r1=695687&r2=695688&view=diff
==============================================================================
--- ofbiz/trunk/framework/service/ofbiz-component.xml (original)
+++ ofbiz/trunk/framework/service/ofbiz-component.xml Mon Sep 15 16:40:31 2008
@@ -31,6 +31,7 @@
     <entity-resource type="data" reader-name="seed" loader="main" location="data/ScheduledServiceData.xml"/>
     <entity-resource type="data" reader-name="seed-initial" loader="main" location="data/ScheduledServices.xml"/>
     <entity-resource type="data" reader-name="seed" loader="main" location="data/ServiceSecurityData.xml"/>
+    <entity-resource type="data" reader-name="demo" loader="main" location="data/ServiceDemoData.xml"/>
 
     <service-resource type="model" loader="main" location="servicedef/services.xml"/>
     <service-resource type="model" loader="main" location="servicedef/services_test_se.xml"/>

Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/DateRange.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/DateRange.java?rev=695688&view=auto
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/DateRange.java (added)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/DateRange.java Mon Sep 15 16:40:31 2008
@@ -0,0 +1,115 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ofbiz.service.calendar;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/** An immutable range of dates.
+ */
+@SuppressWarnings("serial")
+public class DateRange implements Serializable {
+    public static final Date MIN_DATE = new Date(Long.MIN_VALUE);
+    public static final Date MAX_DATE = new Date(Long.MAX_VALUE);
+    public static final DateRange FullRange = new DateRange();
+
+    protected Date start = MIN_DATE;
+    protected Date end = MAX_DATE;
+
+    protected DateRange() {}
+
+    public DateRange(Date start, Date end) {
+        if (start != null) {
+            this.start = start;
+        }
+        if (end != null) {
+            this.end = end;
+        }
+    }
+
+    public long durationInMillis() {
+        if (this.end.after(this.start)) {
+            return this.end.getTime() - this.start.getTime();
+        } else {
+            return this.start.getTime() - this.end.getTime();
+        }
+    }
+
+    public boolean equals(Object obj) {
+        return obj instanceof DateRange && ((DateRange)obj).start.equals(this.start) && ((DateRange)obj).end.equals(this.end);
+    }
+
+    public String toString() {
+        return super.toString() + ", start = " + this.start + ", end = " + this.end;
+    }
+
+    public Date start() {
+        return (Date) this.start.clone();
+    }
+
+    public Date end() {
+        return (Date) this.end.clone();
+    }
+
+    public boolean isAscending() {
+        return this.end.after(this.start) && !this.end.equals(this.start);
+    }
+
+    public boolean isPoint() {
+        return this.end.equals(this.start);
+    }
+
+    public boolean includesDate(Date date) {
+        if (isPoint()) {
+            return date.equals(this.start);
+        }
+        if (isAscending()) {
+            return (this.start.equals(date) || date.after(this.start)) && (this.end.equals(date) || date.before(this.end));
+        } else {
+            return (this.start.equals(date) || date.before(this.start)) && (this.end.equals(date) || date.after(this.end));
+        }
+    }
+
+    public boolean intersectsRange(DateRange dateRange) {
+        return intersectsRange(dateRange.start, dateRange.end);
+    }
+
+    public boolean intersectsRange(Date start, Date end) {
+        if (start == null) {
+            throw new IllegalArgumentException("start argument cannot be null");
+        }
+        if (end == null) {
+            throw new IllegalArgumentException("end argument cannot be null");
+        }
+        if (isPoint()) {
+            return end.equals(start) && this.start.equals(start);
+        }
+        if (isAscending()) {
+            if (start.after(end)) {
+                return false;
+            }
+            return (this.end.equals(start) || start.before(this.end)) && (this.start.equals(end) || end.after(this.start));
+        } else {
+            if (end.after(start)) {
+                return false;
+            }
+            return (this.end.equals(start) || start.after(this.end)) && (this.start.equals(end) || end.before(this.start));
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/DateRange.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpression.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpression.java?rev=695688&view=auto
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpression.java (added)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpression.java Mon Sep 15 16:40:31 2008
@@ -0,0 +1,106 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ofbiz.service.calendar;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Set;
+import java.util.TreeSet;
+
+/** Temporal expression abstract class. */
+public abstract class TemporalExpression implements Serializable, Comparable<TemporalExpression> {
+    protected TemporalExpression() {}
+    
+    /** Field used to sort expressions. Expression evaluation depends
+     * on correct ordering. Expressions are evaluated from lowest value
+     * to highest value. */
+    protected int sequence = Integer.MAX_VALUE;
+    
+    /** Field used to sort expressions. Expression evaluation depends
+     * on correct ordering. Expressions are evaluated from lowest value
+     * to highest value. */
+    protected int subSequence = Integer.MAX_VALUE;
+    
+    /** Returns true if this expression includes the specified date.
+     * @param cal A date to evaluate
+     * @return true if this expression includes the date represented by
+     * <code>cal</code>
+     */
+    public abstract boolean includesDate(Calendar cal);
+    
+    /** Returns a date representing the first occurrence of this expression
+     * on or after a specified date. Returns <code>null</code> if there
+     * is no matching date.
+     * @param cal A date to evaluate
+     * @return A Calendar instance representing the first matching date,
+     * or <code>null</code> if no matching date is found
+     */
+    public abstract Calendar first(Calendar cal);
+    
+    /** Returns a date representing the next occurrence of this expression
+     * after a specified date. Returns <code>null</code> if there
+     * is no matching date.
+     * @param cal A date to evaluate
+     * @return A Calendar instance representing the first matching date,
+     * or <code>null</code> if no matching date is found
+     */
+    public abstract Calendar next(Calendar cal);
+
+    public int compareTo(TemporalExpression obj) {
+        if (this.equals(obj)) {
+            return 0;
+        }
+        if (obj.sequence < this.sequence) {
+            return 1;
+        } else if (obj.sequence > this.sequence) {
+            return -1;
+        }
+        return obj.subSequence < this.subSequence ? 1 : -1;
+    }
+
+    /** Returns a range of dates matching this expression. Returns an
+     * empty Set if no dates are found.
+     * @param range The range of dates to evaluate
+     * @param cal The starting date
+     * @return A Set of matching <code>Date</code> objects
+     */
+    public Set<Date> getRange(org.ofbiz.service.calendar.DateRange range, Calendar cal) {
+        Set<Date> set = new TreeSet<Date>();
+        Date last = range.start();
+        Calendar next = first(cal);
+        while (next != null && range.includesDate(next.getTime())) {
+            last = next.getTime();
+            set.add(last);
+            next = next(next);
+            if (next != null && last.equals(next.getTime())) {
+                break;
+            }
+        }
+        return set;
+    }
+
+    protected Calendar setStartOfDay(Calendar cal) {
+        cal.set(Calendar.HOUR_OF_DAY, 0);
+        cal.set(Calendar.MINUTE, 0);
+        cal.set(Calendar.SECOND, 0);
+        cal.set(Calendar.MILLISECOND, 0);
+        return cal;
+    }
+}

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpression.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressionWorker.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressionWorker.java?rev=695688&view=auto
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressionWorker.java (added)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressionWorker.java Mon Sep 15 16:40:31 2008
@@ -0,0 +1,118 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ofbiz.service.calendar;
+
+import java.util.List;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.ofbiz.base.util.UtilMisc;
+import org.ofbiz.base.util.UtilValidate;
+import org.ofbiz.entity.GenericDelegator;
+import org.ofbiz.entity.GenericEntityException;
+import org.ofbiz.entity.GenericValue;
+import org.ofbiz.entity.condition.EntityCondition;
+import org.ofbiz.entity.util.EntityUtil;
+
+/** Schedule and TemporalExpression persistence worker.
+ */
+public class TemporalExpressionWorker {
+
+    // Temporal expression constants
+    public final static String DateRange = "DATE_RANGE";
+    public final static String DayInMonth = "DAY_IN_MONTH";
+    public final static String DayOfMonthRange = "DAY_OF_MONTH_RANGE";
+    public final static String DayOfWeekRange = "DAY_OF_WEEK_RANGE";
+    public final static String Difference = "DIFFERENCE";
+    public final static String Frequency = "FREQUENCY";
+    public final static String Intersection = "INTERSECTION";
+    public final static String MonthRange = "MONTH_RANGE";
+    public final static String TimeOfDayRange = "TIME_OF_DAY_RANGE";
+    public final static String Union = "UNION";
+    public final static String ExpressionTypeList[] = {DateRange, DayInMonth, DayOfMonthRange, DayOfWeekRange,
+        Difference, Frequency, Intersection, MonthRange, TimeOfDayRange, Union};
+
+    /** Get a <code>TemporalExpression</code> from persistent storage.
+     * @param delegator
+     * @param tempExprId
+     * @return
+     * @throws GenericEntityException
+     */
+    public static TemporalExpression getTemporalExpression(GenericDelegator delegator, String tempExprId) throws GenericEntityException {
+        if (UtilValidate.isEmpty(tempExprId)) {
+            throw new IllegalArgumentException("tempExprId argument cannot be empty");
+        }
+        GenericValue exprValue = delegator.findOne("TemporalExpression", UtilMisc.toMap("tempExprId", tempExprId), true);
+        if (UtilValidate.isEmpty(exprValue)) {
+            throw new IllegalArgumentException("tempExprId argument invalid - expression not found");
+        }
+        return makeTemporalExpression(delegator, exprValue);
+    }
+
+    /** Create a <code>TemporalExpression</code> instance from a TemporalExpression
+     * GenericValue.<p>This method makes recursive calls, so care must be taken to
+     * avoid endless loops.</p>
+     * @param delegator
+     * @param exprValue
+     * @return
+     * @throws GenericEntityException
+     */
+    public static TemporalExpression makeTemporalExpression(GenericDelegator delegator, GenericValue exprValue) throws GenericEntityException {
+        String tempExprId = exprValue.getString("tempExprId");
+        String tempExprTypeId = exprValue.getString("tempExprTypeId");
+        if (DateRange.equals(tempExprTypeId)) {
+            return new TemporalExpressions.DateRange(exprValue.getTimestamp("date1"), exprValue.getTimestamp("date2"));
+        } else if (DayInMonth.equals(tempExprTypeId)) {
+            return new TemporalExpressions.DayInMonth(exprValue.getLong("integer1").intValue(), exprValue.getLong("integer2").intValue());
+        } else if (DayOfMonthRange.equals(tempExprTypeId)) {
+            return new TemporalExpressions.DayOfMonthRange(exprValue.getLong("integer1").intValue(), exprValue.getLong("integer2").intValue());
+        } else if (DayOfWeekRange.equals(tempExprTypeId)) {
+            return new TemporalExpressions.DayOfWeekRange(exprValue.getLong("integer1").intValue(), exprValue.getLong("integer2").intValue());
+        } else if (Difference.equals(tempExprTypeId)) {
+            GenericValue inclAssoc = EntityUtil.getFirst(delegator.findList("TemporalExpressionAssoc", EntityCondition.makeCondition(EntityCondition.makeCondition("fromTempExprId", tempExprId), EntityCondition.makeCondition("exprAssocType", "INCLUDE")), null, null, null, true));
+            GenericValue exclAssoc = EntityUtil.getFirst(delegator.findList("TemporalExpressionAssoc", EntityCondition.makeCondition(EntityCondition.makeCondition("fromTempExprId", tempExprId), EntityCondition.makeCondition("exprAssocType", "EXCLUDE")), null, null, null, true));
+            if (inclAssoc != null && exclAssoc != null) {
+                return new TemporalExpressions.Difference(getTemporalExpression(delegator, inclAssoc.getString("toTempExprId")), getTemporalExpression(delegator, exclAssoc.getString("toTempExprId")));
+            }
+        } else if (Frequency.equals(tempExprTypeId)) {
+            return new TemporalExpressions.Frequency(exprValue.getTimestamp("date1"), exprValue.getLong("integer1").intValue(), exprValue.getLong("integer2").intValue());
+        } else if (Intersection.equals(tempExprTypeId)) {
+            return new TemporalExpressions.Intersection(getChildExpressions(delegator, tempExprId));
+        } else if (MonthRange.equals(tempExprTypeId)) {
+            return new TemporalExpressions.MonthRange(exprValue.getLong("integer1").intValue(), exprValue.getLong("integer2").intValue());
+        } else if (TimeOfDayRange.equals(tempExprTypeId)) {
+            return new TemporalExpressions.TimeOfDayRange(exprValue.getString("string1"), exprValue.getString("string2"));
+        } else if (Union.equals(tempExprTypeId)) {
+            return new TemporalExpressions.Union(getChildExpressions(delegator, tempExprId));
+        }
+        return TemporalExpressions.NullExpression;
+    }
+
+    protected static Set<TemporalExpression> getChildExpressions(GenericDelegator delegator, String tempExprId) throws GenericEntityException {
+        List<GenericValue> valueList = delegator.findList("TemporalExpressionAssoc", EntityCondition.makeCondition("fromTempExprId", tempExprId), null, null, null, true);
+        if (UtilValidate.isEmpty(valueList)) {
+            throw new IllegalArgumentException("tempExprId argument invalid - no child expressions found");
+        }
+        Set<TemporalExpression> exprList = new TreeSet<TemporalExpression>();
+        for (GenericValue value : valueList) {
+            exprList.add(makeTemporalExpression(delegator, value.getRelatedOne("ToTemporalExpression")));
+        }
+        return exprList;
+    }
+}

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressionWorker.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java?rev=695688&view=auto
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java (added)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java Mon Sep 15 16:40:31 2008
@@ -0,0 +1,861 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ofbiz.service.calendar;
+
+import java.io.Serializable;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Set;
+import java.util.TreeSet;
+import org.ofbiz.base.util.Debug;
+
+/** A collection of TemporalExpression classes. */
+@SuppressWarnings("serial")
+public class TemporalExpressions implements Serializable {
+    public static final String module = TemporalExpressions.class.getName();
+    public static final TemporalExpression NullExpression = new Null();
+
+    /** This class represents a null expression. */
+    protected static class Null extends TemporalExpression {
+        public Calendar first(Calendar cal) {
+            return null;
+        }
+        public boolean includesDate(Calendar cal) {
+            return false;
+        }
+        public Calendar next(Calendar cal) {
+            return null;
+        }
+        public Calendar previous(Calendar cal) {
+            return null;
+        }
+    }
+
+    /** This class represents a mathematical union of all of its
+     * member expressions. */
+    public static class Union extends TemporalExpression {
+        protected Set<TemporalExpression> expressionSet = null;
+
+        protected Union() {}
+
+        public Union(Set<TemporalExpression> expressionSet) {
+            if (expressionSet == null) {
+                throw new IllegalArgumentException("expressionSet argument cannot be null");
+            }
+            this.expressionSet = expressionSet;
+            if (this.expressionSet.size() > 0) {
+                TemporalExpression that = this.expressionSet.iterator().next();
+                if (this.compareTo(that) > 0) {
+                    this.sequence = that.sequence;
+                    this.subSequence = that.subSequence;
+                }
+            }
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                return this.expressionSet.equals(((Union) obj).expressionSet);
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", size = " + this.expressionSet.size();
+        }
+
+        public boolean includesDate(Calendar cal) {
+            for (TemporalExpression expression : this.expressionSet) {
+                if (expression.includesDate(cal)) {
+                    return true;
+                }
+            }
+            return false;
+        }
+
+        public Calendar first(Calendar cal) {
+            for (TemporalExpression expression : this.expressionSet) {
+                Calendar first = expression.first(cal);
+                if (first != null && includesDate(first)) {
+                    return first;
+                }
+            }
+            return null;
+        }
+
+        public Calendar next(Calendar cal) {
+            for (TemporalExpression expression : this.expressionSet) {
+                Calendar next = expression.next(cal);
+                if (next != null && includesDate(next)) {
+                    return next;
+                }
+            }
+            return null;
+        }
+
+        public Set<Date> getRange(org.ofbiz.service.calendar.DateRange range, Calendar cal) {
+            Set<Date> rawSet = new TreeSet<Date>();
+            Set<Date> finalSet = new TreeSet<Date>();
+            for (TemporalExpression expression : this.expressionSet) {
+                rawSet.addAll(expression.getRange(range, cal));
+            }
+            Calendar checkCal = (Calendar) cal.clone();
+            for (Date date : rawSet) {
+                checkCal.setTime(date);
+                if (includesDate(checkCal)) {
+                    finalSet.add(date);
+                }
+            }
+            return finalSet;
+        }
+    }
+
+    /** This class represents a mathematical intersection of all of its
+     * member expressions. */
+    public static class Intersection extends TemporalExpression {
+        protected Set<TemporalExpression> expressionSet = null;
+
+        protected Intersection() {}
+
+        public Intersection(Set<TemporalExpression> expressionSet) {
+            if (expressionSet == null) {
+                throw new IllegalArgumentException("expressionSet argument cannot be null");
+            }
+            this.expressionSet = expressionSet;
+            if (this.expressionSet.size() > 0) {
+                TemporalExpression that = this.expressionSet.iterator().next();
+                if (this.compareTo(that) > 0) {
+                    this.sequence = that.sequence;
+                    this.subSequence = that.subSequence;
+                }
+            }
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                return this.expressionSet.equals(((Intersection) obj).expressionSet);
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", size = " + this.expressionSet.size();
+        }
+
+        public void add(TemporalExpression expr) {
+            this.expressionSet.add(expr);
+            if (this.compareTo(expr) > 0) {
+                this.sequence = expr.sequence;
+                this.subSequence = expr.subSequence;
+            }
+        }
+
+        public boolean includesDate(Calendar cal) {
+            for (TemporalExpression expression : this.expressionSet) {
+                if (!expression.includesDate(cal)) {
+                    return false;
+                }
+            }
+            return true;
+        }
+
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            for (TemporalExpression expression : this.expressionSet) {
+                first = expression.first(first);
+                if (first == null) {
+                    return null;
+                }
+            }
+            if (includesDate(first)) {
+                return first;
+            } else {
+                return null;
+            }
+        }
+
+        public Calendar next(Calendar cal) {
+            Calendar next = (Calendar) cal.clone();
+            for (TemporalExpression expression : this.expressionSet) {
+                next = expression.next(next);
+                if (next == null) {
+                    return null;
+                }
+            }
+            if (includesDate(next)) {
+                return next;
+            } else {
+                return null;
+            }
+        }
+
+        public Set<Date> getRange(org.ofbiz.service.calendar.DateRange range, Calendar cal) {
+            Set<Date> finalSet = new TreeSet<Date>();
+            Set<Date> rawSet = new TreeSet<Date>();
+            Date last = range.start();
+            Calendar next = first(cal);
+            while (next != null && range.includesDate(next.getTime())) {
+                last = next.getTime();
+                rawSet.add(last);
+                next = next(next);
+                if (next != null && last.equals(next.getTime())) {
+                    break;
+                }
+            }
+            Calendar checkCal = (Calendar) cal.clone();
+            for (Date date : rawSet) {
+                checkCal.setTime(date);
+                if (includesDate(checkCal)) {
+                    finalSet.add(date);
+                }
+            }
+            return finalSet;
+        }
+    }
+
+    /** This class represents a difference of two temporal expressions. */
+    public static class Difference extends TemporalExpression {
+        protected TemporalExpression included = null;
+        protected TemporalExpression excluded = null;
+
+        public Difference(TemporalExpression included, TemporalExpression excluded) {
+            if (included == null) {
+                throw new IllegalArgumentException("included argument cannot be null");
+            }
+            if (excluded == null) {
+                throw new IllegalArgumentException("excluded argument cannot be null");
+            }
+            this.included = included;
+            this.excluded = excluded;
+            if (this.compareTo(included) > 0) {
+                this.sequence = included.sequence;
+                this.subSequence = included.subSequence;
+            }
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                Difference that = (Difference) obj;
+                return this.included.equals(that.included) && this.excluded.equals(that.excluded);
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", included = " + this.included + ", excluded = " + this.excluded;
+        }
+
+        public boolean includesDate(Calendar cal) {
+            return this.included.includesDate(cal) && !this.excluded.includesDate(cal);
+        }
+
+        public Calendar first(Calendar cal) {
+            Calendar first = this.included.first(cal);
+            while (first != null && this.excluded.includesDate(first)) {
+                first = this.included.next(first);
+            }
+            return first;
+        }
+
+        public Calendar next(Calendar cal) {
+            Calendar next = this.included.next(cal);
+            while (next != null && this.excluded.includesDate(next)) {
+                next = this.included.next(next);
+            }
+            return next;
+        }
+
+        public Set<Date> getRange(org.ofbiz.service.calendar.DateRange range, Calendar cal) {
+            Set<Date> finalSet = new TreeSet<Date>();
+            Set<Date> rawSet = this.included.getRange(range, cal);
+            Calendar checkCal = (Calendar) cal.clone();
+            for (Date date : rawSet) {
+                checkCal.setTime(date);
+                if (!this.excluded.includesDate(checkCal)) {
+                    finalSet.add(date);
+                }
+            }
+            return finalSet;
+        }
+    }
+
+    /** A temporal expression that represents a range of dates. */
+    public static class DateRange extends TemporalExpression {
+        protected org.ofbiz.service.calendar.DateRange range = null;
+
+        public DateRange(Date start, Date end) {
+            this.sequence = 1000;
+            this.range = new org.ofbiz.service.calendar.DateRange(start, end);
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                return this.range.equals(((DateRange) obj).range);
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", start = " + this.range.start() + ", end = " + this.range.end();
+        }
+
+        public boolean includesDate(Calendar cal) {
+            return this.range.includesDate(cal.getTime());
+        }
+
+        public Calendar first(Calendar cal) {
+            return includesDate(cal) ? cal : null;
+        }
+
+        public Calendar next(Calendar cal) {
+            return includesDate(cal) ? cal : null;
+        }
+    }
+
+    /** A temporal expression that represents a time of day range. */
+    public static class TimeOfDayRange extends TemporalExpression {
+        protected int start = 0;
+        protected int end = 0;
+        
+        /**
+         * @param start A time String in the form of hh:mm:ss.sss (24 hr clock)
+         * @param end A time String in the form of hh:mm:ss.sss (24 hr clock)
+         */
+        public TimeOfDayRange(String start, String end) {
+            if (start == null || start.length() == 0) {
+                throw new IllegalArgumentException("start argument cannot be null or empty");
+            }
+            if (end == null || end.length() == 0) {
+                throw new IllegalArgumentException("end argument cannot be null or empty");
+            }
+            this.start = strToMillis(start);
+            this.end = strToMillis(end);
+            this.sequence = 600;
+            this.subSequence = this.start;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                TimeOfDayRange that = (TimeOfDayRange) obj;
+                return this.start == that.start && this.end == that.end;
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        }
+
+        public boolean includesDate(Calendar cal) {
+            int millis = calToMillis(cal);
+            if (this.start <= this.end) {
+                return millis >= this.start && millis <= this.end;
+            } else {
+                return millis <= this.start && millis >= this.end;
+            }
+        }
+
+        public Calendar first(Calendar cal) {
+            if (includesDate(cal)) {
+                return cal;
+            }
+            Calendar first = (Calendar) cal.clone();
+            if (calToMillis(cal) > this.end) {
+                first.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            int start = this.start;
+            int hour = start / 3600000;
+            start -= hour * 3600000;
+            int minute = start / 60000;
+            start -= minute * 60000;
+            int second = start  / 1000;
+            int millis = start - (second * 1000);
+            first.set(Calendar.HOUR_OF_DAY, hour);
+            first.set(Calendar.MINUTE, minute);
+            first.set(Calendar.SECOND, second);
+            first.set(Calendar.MILLISECOND, millis);
+            return first;
+        }
+
+        public Calendar next(Calendar cal) {
+            return first(cal);
+        }
+
+        protected int strToMillis(String str) {
+            int result = 0;
+            String strArray[] = str.split(":");
+            if (strArray.length == 0 || strArray.length > 3) {
+                throw new IllegalArgumentException("Invalid time argument");
+            }
+            result = Integer.valueOf(strArray[0]) * 3600000;
+            if (strArray.length > 1) {
+                result += (Integer.valueOf(strArray[1]) * 60000);
+            }
+            if (strArray.length > 2) {
+                float val = Float.valueOf(strArray[2]);
+                result += (int)(val * 1000);
+            }
+            return result;
+        }
+
+        protected int calToMillis(Calendar cal) {
+            return (cal.get(Calendar.HOUR_OF_DAY) * 3600000) +
+            (cal.get(Calendar.MINUTE) * 60000) +
+            (cal.get(Calendar.SECOND) * 1000) +
+            (cal.get(Calendar.MILLISECOND));
+        }
+    }
+
+    /** A temporal expression that represents a day of week range. */
+    public static class DayOfWeekRange extends TemporalExpression {
+        protected int start;
+        protected int end;
+        
+        /**
+         * @param start An integer in the range of <code>Calendar.SUNDAY</code>
+         * to <code>Calendar.SATURDAY</code>
+         * @param end An integer in the range of <code>Calendar.SUNDAY</code>
+         * to <code>Calendar.SATURDAY</code>
+         */
+        public DayOfWeekRange(int start, int end) {
+            if (start < Calendar.SUNDAY || start > Calendar.SATURDAY) {
+                throw new IllegalArgumentException("Invalid start argument");
+            }
+            if (end < Calendar.SUNDAY || end > Calendar.SATURDAY) {
+                throw new IllegalArgumentException("Invalid end argument");
+            }
+            this.sequence = 500;
+            this.subSequence = start;
+            this.start = start;
+            this.end = end;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                DayOfWeekRange that = (DayOfWeekRange) obj;
+                return this.start == that.start && this.end == that.end;
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        }
+
+        public boolean includesDate(Calendar cal) {
+            int dow = cal.get(Calendar.DAY_OF_WEEK);
+            if (dow == this.start || dow == this.end) {
+                return true;
+            }
+            Calendar compareCal = (Calendar) cal.clone();
+            while (compareCal.get(Calendar.DAY_OF_WEEK) != this.start) {
+                compareCal.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            while (compareCal.get(Calendar.DAY_OF_WEEK) != this.end) {
+                if (compareCal.get(Calendar.DAY_OF_WEEK) == dow) {
+                    return true;
+                }
+                compareCal.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            return false;
+        }
+
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            while (!includesDate(first)) {
+                first.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            return setStartOfDay(first);
+        }
+
+        public Calendar next(Calendar cal) {
+            Calendar next = (Calendar) cal.clone();
+            next.add(Calendar.DAY_OF_MONTH, 1);
+            while (!includesDate(next)) {
+                next.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            return setStartOfDay(next);
+        }
+    }
+
+    /** A temporal expression that represents a month range. */
+    public static class MonthRange extends TemporalExpression {
+        protected int start;
+        protected int end;
+        
+        /**
+         * @param start An integer in the range of <code>Calendar.JANUARY</code>
+         * to <code>Calendar.UNDECIMBER</code>
+         * @param end An integer in the range of <code>Calendar.JANUARY</code>
+         * to <code>Calendar.UNDECIMBER</code>
+         */
+        public MonthRange(int start, int end) {
+            if (start < Calendar.JANUARY || start > Calendar.UNDECIMBER) {
+                throw new IllegalArgumentException("Invalid start argument");
+            }
+            if (end < Calendar.JANUARY || end > Calendar.UNDECIMBER) {
+                throw new IllegalArgumentException("Invalid end argument");
+            }
+            this.sequence = 200;
+            this.subSequence = start;
+            this.start = start;
+            this.end = end;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                MonthRange that = (MonthRange) obj;
+                return this.start == that.start && this.end == that.end;
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        }
+
+        public boolean includesDate(Calendar cal) {
+            int month = cal.get(Calendar.MONTH);
+            if (month == this.start || month == this.end) {
+                return true;
+            }
+            Calendar compareCal = (Calendar) cal.clone();
+            while (compareCal.get(Calendar.MONTH) != this.start) {
+                compareCal.add(Calendar.MONTH, 1);
+            }
+            while (compareCal.get(Calendar.MONTH) != this.end) {
+                if (compareCal.get(Calendar.MONTH) == month) {
+                    return true;
+                }
+                compareCal.add(Calendar.MONTH, 1);
+            }
+            return false;
+        }
+
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            first.set(Calendar.DAY_OF_MONTH, 1);
+            while (!includesDate(first)) {
+                first.add(Calendar.MONTH, 1);
+            }
+            return first;
+        }
+
+        public Calendar next(Calendar cal) {
+            Calendar next = (Calendar) cal.clone();
+            next.set(Calendar.DAY_OF_MONTH, 1);
+            next.add(Calendar.MONTH, 1);
+            while (!includesDate(next)) {
+                next.add(Calendar.MONTH, 1);
+            }
+            return next;
+        }
+    }
+
+    /** A temporal expression that represents a day of month range. */
+    public static class DayOfMonthRange extends TemporalExpression {
+        protected int start;
+        protected int end;
+        
+        /**
+         * @param start An integer in the range of 1 to 31
+         * @param end An integer in the range of 1 to 31
+         */
+        public DayOfMonthRange(int start, int end) {
+            if (start < 1 || start > end) {
+                throw new IllegalArgumentException("Invalid start argument");
+            }
+            if (end < 1 || end > 31) {
+                throw new IllegalArgumentException("Invalid end argument");
+            }
+            this.sequence = 300;
+            this.subSequence = start;
+            this.start = start;
+            this.end = end;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                DayOfMonthRange that = (DayOfMonthRange) obj;
+                return this.start == that.start && this.end == that.end;
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", end = " + this.end;
+        }
+
+        public boolean includesDate(Calendar cal) {
+            int dom = cal.get(Calendar.DAY_OF_MONTH);
+            int end = this.end;
+            if (cal.getActualMaximum(Calendar.DAY_OF_MONTH) < end) {
+                end = cal.getActualMaximum(Calendar.DAY_OF_MONTH);
+            }
+            return dom >= this.start && dom <= end;
+        }
+
+        public Calendar first(Calendar cal) {
+            int month = cal.get(Calendar.MONTH);
+            Calendar first = (Calendar) cal.clone();
+            if (first.get(Calendar.DAY_OF_MONTH) > first.getActualMaximum(Calendar.DAY_OF_MONTH)) {
+                first.set(Calendar.DAY_OF_MONTH, first.getActualMaximum(Calendar.DAY_OF_MONTH));
+            }
+            setStartOfDay(first);
+            while (!includesDate(first)) {
+                first.add(Calendar.DAY_OF_MONTH, 1);
+                if (first.get(Calendar.MONTH) != month) {
+                    first.set(Calendar.MONTH, month);
+                    first.set(Calendar.DAY_OF_MONTH, 1);
+                }
+            }
+            return first;
+        }
+
+        public Calendar next(Calendar cal) {
+            Calendar next = (Calendar) cal.clone();
+            setStartOfDay(next);
+            next.add(Calendar.DAY_OF_MONTH, 1);
+            while (!includesDate(next)) {
+                next.add(Calendar.DAY_OF_MONTH, 1);
+            }
+            return next;
+        }
+    }
+
+    /** A temporal expression that represents a day in the month. */
+    public static class DayInMonth extends TemporalExpression {
+        protected int dayOfWeek;
+        protected int occurrence;
+        
+        /**
+         * @param start An integer in the range of <code>Calendar.SUNDAY</code>
+         * to <code>Calendar.SATURDAY</code>
+         * @param end An integer in the range of -5 to 5, excluding zero
+         */
+        public DayInMonth(int dayOfWeek, int occurrence) {
+            if (dayOfWeek < Calendar.SUNDAY || dayOfWeek > Calendar.SATURDAY) {
+                throw new IllegalArgumentException("Invalid day argument");
+            }
+            if (occurrence < -5 || occurrence == 0 || occurrence > 5) {
+                throw new IllegalArgumentException("Invalid occurrence argument");
+            }
+            this.sequence = 400;
+            this.subSequence = dayOfWeek;
+            this.dayOfWeek = dayOfWeek;
+            this.occurrence = occurrence;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                DayInMonth that = (DayInMonth) obj;
+                return this.dayOfWeek == that.dayOfWeek && this.occurrence == that.occurrence;
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", dayOfWeek = " + this.dayOfWeek + ", occurrence = " + this.occurrence;
+        }
+
+        public boolean includesDate(Calendar cal) {
+            if (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
+                return false;
+            }
+            int month = cal.get(Calendar.MONTH);
+            int dom = cal.get(Calendar.DAY_OF_MONTH);
+            Calendar next = (Calendar) cal.clone();
+            alignDayOfWeek(next);
+            return dom == next.get(Calendar.DAY_OF_MONTH) && next.get(Calendar.MONTH) == month;
+        }
+
+        public Calendar first(Calendar cal) {
+            int month = cal.get(Calendar.MONTH);
+            Calendar first = (Calendar) cal.clone();
+            alignDayOfWeek(first);
+            setStartOfDay(first);
+            if (first.before(cal)) {
+                first.set(Calendar.DAY_OF_MONTH, 1);
+                if (first.get(Calendar.MONTH) == month) {
+                    first.add(Calendar.MONTH, 1);
+                }
+                alignDayOfWeek(first);
+            }
+            return first;
+        }
+
+        public Calendar next(Calendar cal) {
+            int month = cal.get(Calendar.MONTH);
+            Calendar next = (Calendar) cal.clone();
+            alignDayOfWeek(next);
+            setStartOfDay(next);
+            if (next.before(cal) || next.equals(cal)) {
+                next.set(Calendar.DAY_OF_MONTH, 1);
+                if (next.get(Calendar.MONTH) == month) {
+                    next.add(Calendar.MONTH, 1);
+                }
+                alignDayOfWeek(next);
+            }
+            return next;
+        }
+
+        protected void alignDayOfWeek(Calendar cal) {
+            cal.set(Calendar.DAY_OF_MONTH, 1);
+            if (this.occurrence > 0) {
+                while (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
+                    cal.add(Calendar.DAY_OF_MONTH, 1);
+                }
+                cal.add(Calendar.DAY_OF_MONTH, (this.occurrence - 1) * 7);
+            } else {
+                cal.add(Calendar.MONTH, 1);
+                cal.add(Calendar.DAY_OF_MONTH, -1);
+                while (cal.get(Calendar.DAY_OF_WEEK) != this.dayOfWeek) {
+                    cal.add(Calendar.DAY_OF_MONTH, -1);
+                }
+                cal.add(Calendar.DAY_OF_MONTH, (this.occurrence + 1) * 7);
+            }
+        }
+    }
+
+    /** A temporal expression that represents a frequency. */
+    public static class Frequency extends TemporalExpression {
+        protected Date start;
+        protected int freqType;
+        protected int freqCount;
+        
+        /**
+         * @param start One of the following integer values: <code>Calendar.SECOND
+         * Calendar.MINUTE Calendar.HOUR Calendar.DAY_OF_MONTH Calendar.MONTH
+         * Calendar.YEAR</code>
+         * @param end An integer in the range of -5 to 5, excluding zero
+         */
+        public Frequency(Date start, int freqType, int freqCount) {
+            if (start == null) {
+                throw new IllegalArgumentException("Invalid start argument");
+            }
+            if (freqType != Calendar.SECOND && freqType != Calendar.MINUTE
+                    && freqType != Calendar.HOUR && freqType != Calendar.DAY_OF_MONTH
+                    && freqType != Calendar.MONTH && freqType != Calendar.YEAR) {
+                throw new IllegalArgumentException("Invalid freqType argument");
+            }
+            if (freqCount < 1) {
+                throw new IllegalArgumentException("freqCount argument must be a positive integer");
+            }
+            this.sequence = 100;
+            this.subSequence = freqType;
+            this.start = start;
+            this.freqType = freqType;
+            this.freqCount = freqCount;
+            if (Debug.verboseOn()) {
+                Debug.logVerbose("Created " + this, module);
+            }
+        }
+
+        public boolean equals(Object obj) {
+            if (obj == this) {
+                return true;
+            }
+            try {
+                Frequency that = (Frequency) obj;
+                return this.start.equals(that.start) && this.freqType == that.freqType && this.freqCount == that.freqCount;
+            } catch (Exception e) {}
+            return false;
+        }
+
+        public String toString() {
+            return super.toString() + ", start = " + this.start + ", freqType = " + this.freqType + ", freqCount = " + this.freqCount;
+        }
+
+        public boolean includesDate(Calendar cal) {
+            Calendar next = first(cal);
+            return next.equals(cal);
+        }
+
+        public Calendar first(Calendar cal) {
+            Calendar first = (Calendar) cal.clone();
+            first.setTime(this.start);
+            while (first.before(cal)) {
+                first.add(this.freqType, this.freqCount);
+            }
+            return first;
+        }
+
+        public Calendar next(Calendar cal) {
+            Calendar next = (Calendar) cal.clone();
+            next.setTime(this.start);
+            while (next.before(cal) || next.equals(cal)) {
+                next.add(this.freqType, this.freqCount);
+            }
+            return next;
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TemporalExpressions.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TimeDuration.java
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TimeDuration.java?rev=695688&view=auto
==============================================================================
--- ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TimeDuration.java (added)
+++ ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TimeDuration.java Mon Sep 15 16:40:31 2008
@@ -0,0 +1,149 @@
+/*******************************************************************************
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you 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.ofbiz.service.calendar;
+
+import java.io.Serializable;
+import java.util.Calendar;
+
+import org.ofbiz.entity.GenericValue;
+
+/** A representation of a period of time. */
+@SuppressWarnings("serial")
+public class TimeDuration implements Serializable {
+    public static final TimeDuration ZeroTimeDuration = new NullDuration();
+
+    protected int millis = 0;
+    protected int seconds = 0;
+    protected int minutes = 0;
+    protected int hours = 0;
+    protected int days = 0;
+    protected int months = 0;
+    protected int years = 0;
+
+    protected TimeDuration() {}
+
+    public TimeDuration(int millis, int seconds, int minutes, int hours, int days, int months, int years) {
+        this.millis = millis;
+        this.seconds = seconds;
+        this.minutes = minutes;
+        this.hours = hours;
+        this.days = days;
+        this.months = months;
+        this.years = years;
+    }
+
+    public long millis() {
+        return this.millis;
+    }
+
+    public long seconds() {
+        return this.seconds;
+    }
+
+    public long minutes() {
+        return this.minutes;
+    }
+
+    public long hours() {
+        return this.hours;
+    }
+
+    public long days() {
+        return this.days;
+    }
+
+    public long months() {
+        return this.months;
+    }
+
+    public long years() {
+        return this.years;
+    }
+
+    /** Add this time duration to a Calendar instance. Returns the original
+     * Calendar instance.
+     * @param cal
+     * @return The <code>cal</code> argument
+     */
+    public Calendar addToCalendar(Calendar cal) {
+        cal.add(Calendar.MILLISECOND, this.millis);
+        cal.add(Calendar.SECOND, this.seconds);
+        cal.add(Calendar.MINUTE, this.minutes);
+        cal.add(Calendar.HOUR, this.hours);
+        cal.add(Calendar.DAY_OF_MONTH, this.days);
+        cal.add(Calendar.MONTH, this.months);
+        cal.add(Calendar.YEAR, this.years);
+        return cal;
+    }
+
+    /** Subtract this time duration to a Calendar instance. Returns the original
+     * Calendar instance.
+     * @param cal
+     * @return The <code>cal</code> argument
+     */
+    public Calendar subtractFromCalendar(Calendar cal) {
+        cal.add(Calendar.MILLISECOND, -this.millis);
+        cal.add(Calendar.SECOND, -this.seconds);
+        cal.add(Calendar.MINUTE, -this.minutes);
+        cal.add(Calendar.HOUR, -this.hours);
+        cal.add(Calendar.DAY_OF_MONTH, -this.days);
+        cal.add(Calendar.MONTH, -this.months);
+        cal.add(Calendar.YEAR, -this.years);
+        return cal;
+    }
+
+    /** Get a <code>TimeDuration</code> instance based on duration fields
+     * in a GenericValue. Returns ZeroTimeDuration if there is no
+     * information in the duration fields or if the value argument is null.
+     * <p>The GenericValue <b>must</b> contain the following <code>numeric</code>
+     * fields:<ul><li>durationMillis</li><li>durationSeconds</li><li>durationMinutes</li>
+     * <li>durationHours</li><li>durationDays</li><li>durationMonths</li>
+     * <li>durationYears</li></ul></p>
+     * @param value
+     * @return A TimeDuration instance
+     */
+    public static TimeDuration getTimeDuration(GenericValue value) {
+        if (value != null) {
+            int millis = safeLongToInt(value.getLong("durationMillis"));
+            int secs = safeLongToInt(value.getLong("durationSeconds"));
+            int mins = safeLongToInt(value.getLong("durationMinutes"));
+            int hrs = safeLongToInt(value.getLong("durationHours"));
+            int days = safeLongToInt(value.getLong("durationDays"));
+            int mos = safeLongToInt(value.getLong("durationMonths"));
+            int yrs = safeLongToInt(value.getLong("durationYears"));
+            if (millis != 0 || secs != 0 || mins != 0 || hrs != 0 || days != 0 || mos != 0 || yrs != 0) {
+                return new TimeDuration(millis, secs, mins, hrs, days, mos, yrs);
+            }
+        }
+        return ZeroTimeDuration;
+    }
+
+    protected static int safeLongToInt(Long longObj) {
+        return longObj == null ? 0 : longObj.intValue();
+    }
+    
+    protected static class NullDuration extends TimeDuration {
+        public Calendar addToCalendar(Calendar cal) {
+            return cal;
+        }
+        public Calendar subtractFromCalendar(Calendar cal) {
+            return cal;
+        }
+    }
+}

Propchange: ofbiz/trunk/framework/service/src/org/ofbiz/service/calendar/TimeDuration.java
------------------------------------------------------------------------------
    svn:eol-style = native