View Javadoc
1   /*
2    * Redistribution and use of this software and associated documentation ("Software"), with or
3    * without modification, are permitted provided that the following conditions are met:
4    *
5    * 1. Redistributions of source code must retain copyright statements and notices. Redistributions
6    * must also contain a copy of this document.
7    *
8    * 2. Redistributions in binary form must reproduce the above copyright notice, this list of
9    * conditions and the following disclaimer in the documentation and/or other materials provided with
10   * the distribution.
11   *
12   * 3. The name "Exolab" must not be used to endorse or promote products derived from this Software
13   * without prior written permission of Intalio, Inc. For written permission, please contact
14   * info@exolab.org.
15   *
16   * 4. Products derived from this Software may not be called "Exolab" nor may "Exolab" appear in
17   * their names without prior written permission of Intalio, Inc. Exolab is a registered trademark of
18   * Intalio, Inc.
19   *
20   * 5. Due credit should be given to the Exolab Project (http://www.exolab.org/).
21   *
22   * THIS SOFTWARE IS PROVIDED BY INTALIO, INC. AND CONTRIBUTORS ``AS IS'' AND ANY EXPRESSED OR
23   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
24   * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTALIO, INC. OR ITS
25   * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26   * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28   * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
29   * WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30   *
31   * Copyright 2000 (C) Intalio, Inc. All Rights Reserved.
32   *
33   * $Id$ Date Author Changes 05/13/2001 Arnaud Blandin Added the support for omitted components
34   * (section 4.5 of ISO8601) 12/05/2000 Arnaud Blandin Added the support for
35   * NotSupportedOperationException 11/08/2000 Arnaud Blandin Added new constructor and setValues
36   * method 11/07/2000 Arnaud Blandin Added isEqual() and isGreater() methods 11/02/2000 Arnaud
37   * Blandin Changed the constructor 10/26/2000 Arnaud Blandin Created
38   */
39  package org.exolab.castor.types;
40  
41  import java.util.Date;
42  import java.util.SimpleTimeZone;
43  import java.util.StringTokenizer;
44  import java.util.TimeZone;
45  import java.text.ParseException;
46  import java.text.SimpleDateFormat;
47  
48  import org.exolab.castor.xml.ValidationException;
49  
50  /**
51   * Represents recurringDuration utterly a recurringDuration must contain all the fields:
52   * <p>
53   * (+|-)CCYY-MM-DDThh:mm:ss.sss(Z|(+|-)hh:mm)
54   * <p>
55   * The validation of the date fields is done in the set methods and follows
56   * <a href="http://www.iso.ch/markete/8601.pdf">the ISO8601 Date and Time Format</a>
57   * <p>
58   * It is possible to omit higher components by using '-'.
59   * <p>
60   * Note: This datatype is not included in any recommendation. It was introduced in
61   * http://www.w3.org/TR/1999/WD-xmlschema-2-19990924/ and was last in
62   * http://www.w3.org/TR/2000/CR-xmlschema-2-20001024/ and was removed by
63   * http://www.w3.org/TR/2001/PR-xmlschema-2-20010316/. It was not in the final approved
64   * recommendation: http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/
65   *
66   * @author <a href="mailto:blandin@intalio.com">Arnaud Blandin</a>
67   * @version $Revision$
68   * @deprecated since Castor 1.0.6 since this type is not in any recommendation.
69   */
70  public class RecurringDuration extends RecurringDurationBase {
71    /** SerialVersionUID */
72    private static final long serialVersionUID = -6037158412155942249L;
73  
74    /** The date format used by the toDate() method */
75    private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS";
76  
77    /** Set to true and recompile to include debugging code in class. */
78    private static final boolean DEBUG = false;
79  
80  
81    // Private variables
82    // -1 means that the field has been omitted (cf section 4.5 of ISO 8601)
83    private short _century = 0;
84    private short _year = 0;
85    private short _month = 0;
86    private short _day = 0;
87  
88    private static final short OMITED = Short.parseShort("-1");
89  
90    public RecurringDuration() {}
91  
92    /**
93     * returns a recurringDuration with the facets duration and period set up
94     * 
95     * @param duration the TimeDuration representing the duration facet
96     * @param period the TimeDuration reprensenting the period facet
97     */
98    public RecurringDuration(TimeDuration duration, TimeDuration period) {
99      super(duration, period);
100   }
101 
102   /**
103    * returns a recurringDuration with the facets duration and period set up
104    * 
105    * @param duration the String representing the duration facet
106    * @param period the String reprensenting the period facet
107    */
108   public RecurringDuration(String duration, String period) {
109     super(duration, period);
110   }
111 
112 
113   /**
114    * returns a recurringDuration with the facets duration and period set up but also the fields
115    * 
116    * @param duration the String representing the duration facet
117    * @param period the String reprensenting the period facet
118    * @param values an array of shorts which contains the values of the fields
119    * @see #setValues
120    */
121   public RecurringDuration(String duration, String period, short[] values)
122       throws UnsupportedOperationException {
123     this(duration, period);
124     if (values.length != 10) {
125       throw new IllegalArgumentException("Wrong numbers of values");
126     }
127     this.setValues(values);
128   }
129 
130   /**
131    * set the century field
132    * 
133    * @param century the value to set up
134    */
135   public void setCentury(short century) {
136     String err = "";
137     if (century < -1) {
138       err = "century : " + century + " must not be a negative value.";
139       throw new IllegalArgumentException(err);
140     }
141     _century = century;
142   }
143 
144   /**
145    * set the Year field Note: 0000 is not allowed
146    * 
147    * @param year year to set up
148    */
149   public void setYear(short year) throws UnsupportedOperationException {
150     String err = "";
151     if (year < -1) {
152       err = "year : " + year + " must not be a negative value.";
153       throw new IllegalArgumentException(err);
154     } else if ((year == -1) && (_century != -1)) {
155       err = "year can not be omitted if century is not omitted.";
156       throw new IllegalArgumentException(err);
157     } else if ((year == 0) && (_century == 0)) {
158       err = "0000 is not an allowed year";
159       throw new IllegalArgumentException(err);
160     }
161 
162     _year = year;
163   }
164 
165   /**
166    * set the Month Field
167    * 
168    * @param month the value to set up Note 1<month<12
169    */
170   public void setMonth(short month) throws UnsupportedOperationException {
171     String err = "";
172     if (month == -1) {
173       if (_century != -1) {
174         err = "month cannot be omitted if the previous component is not omitted.\n"
175             + "only higher level components can be omitted.";
176         throw new IllegalArgumentException(err);
177       }
178     } else if (month < 1) {
179       err = "month : " + month + " is not a correct value." + "\n 1<month<12";
180       throw new IllegalArgumentException(err);
181     }
182 
183     else if (month > 12) {
184       err = "month : " + month + " is not a correct value.";
185       err += "\n 1<month<12";
186       throw new IllegalArgumentException(err);
187     }
188     _month = month;
189   }
190 
191   /**
192    * set the Day Field
193    * 
194    * @param day the value to set up Note a validation is done on the day field
195    */
196 
197   public void setDay(short day) throws UnsupportedOperationException {
198     String err = "";
199     if (day == -1) {
200       if (_month != -1) {
201         err = "day cannot be omitted if the previous component is not omitted.\n"
202             + "only higher level components can be omitted.";
203         throw new IllegalArgumentException(err);
204       }
205     } else if (day < 1) {
206       err = "day : " + day + " is not a correct value.";
207       err += "\n 1<day";
208       throw new IllegalArgumentException(err);
209     }
210     // in february
211     if (_month == 2) {
212       if (isLeap()) {
213         if (day > 29) {
214           err = "day : " + day + " is not a correct value.";
215           err += "\n day<30 (leap year and month is february)";
216           throw new IllegalArgumentException(err);
217         }
218       } else if (day > 28) {
219         err = "day : " + day + " is not a correct value.";
220         err += "\n day<30 (not a leap year and month is february)";
221         throw new IllegalArgumentException(err);
222       } // february
223     } else if ((_month == 4) || (_month == 6) || (_month == 9) || (_month == 11)) {
224       if (day > 30) {
225         err = "day : " + day + " is not a correct value.";
226         err += "\n day<31 ";
227         throw new IllegalArgumentException(err);
228       }
229     } else if (day > 31) {
230       err = "day : " + day + " is not a correct value.";
231       err += "\n day<=31 ";
232       throw new IllegalArgumentException(err);
233     }
234 
235     _day = day;
236   }
237 
238   /**
239    * return true if the year field represents a leap year A specific year is a leap year if it is
240    * either evenly divisible by 400 OR evenly divisible by 4 and not evenly divisible by 100
241    * 
242    * @return true if the year field represents a leap year
243    */
244   public boolean isLeap() {
245     int temp = (_century * 100 + _year);
246     boolean result = (((temp % 4) == 0) && ((temp % 100) != 0));
247     result = (result || ((temp % 400) == 0));
248     return result;
249   }
250 
251   /**
252    * set all the fields by reading the values in an array
253    * 
254    * @param values an array of shorts with the values the array is supposed to be of length 10 and
255    *        ordered like that:
256    *        <ul>
257    *        <li>century</li>
258    *        <li>year</li>
259    *        <li>month</li>
260    *        <li>day</li>
261    *        <li>hour</li>
262    *        <li>minute</li>
263    *        <li>second</li>
264    *        <li>millisecond</li>
265    *        <li>zoneHour</li>
266    *        <li>zoneMinute</li>
267    *        </ul>
268    *
269    * @throws UnsupportedOperationException this exception is thrown if changing the value of one
270    *         field os not allowed
271    * @see RecurringDurationBase#setValues
272    */
273   public void setValues(short[] values) throws UnsupportedOperationException {
274     this.setCentury(values[0]);
275     this.setYear(values[1]);
276     this.setMonth(values[2]);
277     this.setDay(values[3]);
278     this.setHour(values[4]);
279     this.setMinute(values[5]);
280     this.setSecond(values[6], values[7]);
281     this.setZone(values[8], values[9]);
282   }
283 
284 
285   // Get methods
286   public short getCentury() {
287     return (_century);
288   }
289 
290   public short getYear() {
291     return (_year);
292   }
293 
294   public short getMonth() {
295     return (_month);
296   }
297 
298   public short getDay() {
299     return (_day);
300   }
301 
302 
303   /**
304    * returns an array of short with all the fields which describe a RecurringDuration
305    * 
306    * @return an array of short with all the fields which describe a RecurringDuration
307    */
308   public short[] getValues() {
309     short[] result = null;
310     result = new short[10];
311     result[0] = this.getCentury();
312     result[1] = this.getYear();
313     result[2] = this.getMonth();
314     result[3] = this.getDay();
315     result[4] = this.getHour();
316     result[5] = this.getMinute();
317     result[6] = this.getSeconds();
318     result[7] = this.getMilli();
319     result[8] = this.getZoneHour();
320     result[5] = this.getZoneMinute();
321     return result;
322   } // getValues
323 
324   /**
325    * convert this recurringDuration into a local Date
326    * <p>
327    * Note : Be aware a the 'local' property of the date i.e <tt>toDate()</tt> will de the conversion
328    * between a UTC date and your computer date format. For instance if you have set up your computer
329    * time zone on the Pacific Day Time the conversion of <tt>2000-10-20T00:00:00.000</tt> into a
330    * <tt>java.util.Date</tt> will return <tt>Thu Oct 19 17:00:00 PDT 2000</tt>
331    * 
332    * @return a local date representing this recurringDuration
333    * @throws ParseException
334    */
335   public Date toDate() throws ParseException {
336     Date date = null;
337     SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT);
338     SimpleTimeZone timeZone = new SimpleTimeZone(0, "UTC");
339 
340     // Set the time zone
341     if (!isUTC()) {
342       int offset = 0;
343       offset = ((this.getZoneMinute() + this.getZoneHour() * 60) * 60 * 1000);
344       offset = isZoneNegative() ? -offset : offset;
345       timeZone.setRawOffset(offset);
346       timeZone.setID(TimeZone.getAvailableIDs(offset)[0]);
347     }
348     df.setTimeZone(timeZone);
349     date = df.parse(this.toPrivateString());
350     return date;
351   }// toDate()
352 
353   /**
354    * <p>
355    * Convert this recurringDuration to a string
356    * <p>
357    * The format is defined by W3C XML Schema draft and ISO8601 i.e
358    * (+|-)CCYY-MM-DDThh:mm:ss.sss(Z|(+|-)hh:mm)
359    * 
360    * @return a string representing this recurringDuration
361    */
362   public String toString() {
363     return this.toPrivateString();
364   }
365 
366   /*
367    * This method is needed for the toDate() method
368    */
369   private final String toPrivateString() {
370 
371     StringBuilder result = new StringBuilder();
372 
373     if (this.getCentury() == -1)
374       result.append('-');
375     else {
376       if (this.getCentury() / 10 == 0)
377         result.append(0);
378       result.append(this.getCentury());
379 
380       if ((this.getYear() / 10) == 0)
381         result.append(0);
382       result.append(this.getYear());
383     }
384     result.append('-');
385     if (this.getMonth() == -1)
386       result.append('-');
387     else {
388       if ((this.getMonth() / 10) == 0)
389         result.append(0);
390       result.append(this.getMonth());
391     }
392     result.append('-');
393     if (this.getDay() == -1)
394       result.append('-');
395     else {
396       if ((this.getDay() / 10) == 0)
397         result.append(0);
398       result.append(this.getDay());
399     }
400     // nowhere it is said in the specs that Time can be omitted
401     // choose to always keep it
402     result.append('T');
403     if (this.getHour() == -1)
404       result.append('-');
405     else {
406       if ((this.getHour() / 10) == 0)
407         result.append(0);
408       result.append(this.getHour());
409     }
410     result.append(':');
411     if (this.getMinute() == -1)
412       result.append('-');
413     else {
414       if ((this.getMinute() / 10) == 0)
415         result.append(0);
416       result.append(this.getMinute());
417     }
418     result.append(':');
419     if (this.getSeconds() == -1)
420       result.append('-');
421     else {
422       if ((this.getSeconds() / 10) == 0)
423         result.append(0);
424       result.append(this.getSeconds());
425     }
426     result.append('.');
427     result.append(this.getMilli());
428 
429     if (isNegative())
430       result.append('-');
431 
432     // by default we choose to not concat the Z
433     if (!isUTC()) {
434       StringBuilder timeZone = new StringBuilder();
435       if ((this.getZoneHour() / 10) == 0)
436         timeZone.append(0);
437       timeZone.append(this.getZoneHour());
438 
439       timeZone.append(':');
440       if ((this.getZoneMinute() / 10) == 0)
441         timeZone.append(0);
442       timeZone.append(this.getZoneMinute());
443 
444       if (isZoneNegative())
445         timeZone.insert(0, '-');
446       else
447         timeZone.insert(0, '+');
448       result.append(timeZone);
449     }
450 
451     if (isNegative())
452       result.insert(0, '-');
453 
454     return result.toString();
455 
456   }// toString
457 
458   public static Object parse(String str) throws ParseException {
459     return parseRecurringDuration(str);
460   }
461 
462   /**
463    * Parse a String and convert it into a recurringDuration.
464    *
465    * @param str The string to parse.
466    * @return The recurringDuration represented by the string.
467    * @throws ParseException A parse exception is thrown if the string to parse does not follow the
468    *         rigth format (see the description of this class).
469    */
470   public static RecurringDuration parseRecurringDuration(String str) throws ParseException {
471     // TODO optimize this method (too much strings)
472     RecurringDuration result = new RecurringDuration();
473 
474     // remove if necessary the Z at the end
475     if (str.endsWith("Z"))
476       str = str.substring(0, str.indexOf("Z"));
477 
478     // isNegative ?
479     if (str.startsWith("-") && !str.startsWith("--"))
480       result.setNegative();
481 
482     // Is there a time Zone?
483     String zoneStr = str.substring(str.length() - 6, str.length());
484     boolean timeZone = (((zoneStr.lastIndexOf("-") != -1) || (zoneStr.lastIndexOf("+") != -1))
485         && (zoneStr.lastIndexOf(":") != -1));
486 
487     if (DEBUG) {
488       System.out.println("In parsing method of RecurringDuration");
489       System.out.println("String to parse : " + str);
490       System.out.println("Negative ? " + result.isNegative());
491       String tzone = timeZone ? zoneStr : "false";
492       System.out.println("Time zone :" + tzone);
493     }
494 
495     if (!timeZone)
496       zoneStr = null;
497     else {
498       int index = str.lastIndexOf("+") != -1 ? str.lastIndexOf("+") : str.lastIndexOf("-");
499       str = str.substring(0, index);
500     }
501 
502     // the 'T' is required
503     if (str.indexOf('T') == -1) {
504       throw new ParseException("The 'T' element is required", 0);
505     }
506     String date = str.substring(0, str.indexOf("T"));
507     String time = str.substring(str.indexOf("T"));
508 
509     // proceed date
510     StringTokenizer token = new StringTokenizer(date, "-");
511 
512     if (token.countTokens() > 3)
513       throw new ParseException(str + ": Bad date format", 0);
514 
515     try {
516       // CCYY
517       boolean process = false;
518       String temp;
519       if (token.countTokens() == 3) {
520         temp = token.nextToken();
521         if (temp.length() != 4)
522           throw new ParseException(str + ":Bad year format", 1);
523         if (DEBUG) {
524           System.out.println("Processing century: " + temp.substring(0, 2));
525         }
526         result.setCentury(Short.parseShort(temp.substring(0, 2)));
527         if (DEBUG) {
528           System.out.println("Processing year: " + temp.substring(2, 4));
529         }
530         result.setYear(Short.parseShort(temp.substring(2, 4)));
531         process = true;
532       }
533       if (!process)
534         result.setCentury(OMITED);
535       if (token.countTokens() == 2) {
536         // MM
537         temp = token.nextToken();
538         if (temp.length() != 2)
539           throw new ParseException(str + ": Bad month format", 5);
540         if (DEBUG) {
541           System.out.println("Processing month: " + temp);
542         }
543         result.setMonth(Short.parseShort(temp));
544         process = true;
545       }
546 
547       if ((!process)) {
548         result.setMonth(OMITED);
549       }
550       if (token.countTokens() == 1) {
551         // DD
552         temp = token.nextToken();
553         if (temp.length() != 2)
554           throw new ParseException(str + ":Bad day format", 8);
555         if (DEBUG) {
556           System.out.println("Processing day: " + temp);
557         }
558         result.setDay(Short.parseShort(temp));
559         process = true;
560       }
561 
562       if (!process) {
563         result.setDay(OMITED);
564       }
565 
566 
567       // proceed Time
568       token = new StringTokenizer(time, ":");
569       process = false;
570       if (token.countTokens() > 5)
571         throw new ParseException(str + ": Bad time format", 11);
572 
573       if (token.countTokens() == 3) {
574         // hh
575         temp = token.nextToken();
576         temp = temp.substring(temp.indexOf("T") + 1);
577         if (temp.length() != 2)
578           throw new ParseException(str + ": Bad hour format", 11);
579         if (DEBUG) {
580           System.out.println("Processing hour: " + temp);
581         }
582         result.setHour(Short.parseShort(temp));
583         process = true;
584       }
585 
586       if (!process) {
587         if (result.getDay() == OMITED)
588           result.setHour(OMITED);
589         else
590           throw new IllegalArgumentException("hour cannot be omitted");
591       }
592       if (token.countTokens() == 2) {
593         // mm
594         temp = token.nextToken();
595 
596         if (temp.length() != 2)
597           throw new ParseException(str + ": Bad minute format", 14);
598 
599         if (DEBUG) {
600           System.out.println("Processing minute: " + temp);
601         }
602         result.setMinute(Short.parseShort(temp));
603         process = true;
604       }
605       if (!process) {
606         if (result.getDay() == OMITED) {
607           result.setHour(OMITED);
608           result.setMinute(OMITED);
609         } else
610           throw new IllegalArgumentException("hour cannot be omitted");
611       }
612       if (token.countTokens() == 1) {
613         // ss
614         temp = token.nextToken();
615         String milsecond = "0";
616         if (temp.indexOf(".") != -1) {
617           milsecond = temp.substring(temp.indexOf(".") + 1);
618           temp = temp.substring(0, temp.indexOf("."));
619         }
620 
621         if (temp.length() != 2)
622           throw new ParseException(str + ": Bad second format", 17);
623         if (DEBUG) {
624           System.out.println("Processing seconds: " + temp);
625         }
626         result.setSecond(Short.parseShort(temp.substring(0, 2)), Short.parseShort(milsecond));
627 
628         process = true;
629       }
630 
631       if (!process) {
632         if (result.getDay() == OMITED) {
633           result.setHour(OMITED);
634           result.setMinute(OMITED);
635           result.setSecond(OMITED, OMITED);
636         } else
637           throw new IllegalArgumentException("hour cannot be omitted");
638       }
639 
640       // proceed TimeZone if any
641       if (timeZone) {
642         if (zoneStr.startsWith("-"))
643           result.setZoneNegative();
644         if (zoneStr.length() != 6)
645           throw new ParseException(str + ": Bad time zone format", 20);
646         result.setZone(Short.parseShort(zoneStr.substring(1, 3)),
647             Short.parseShort(zoneStr.substring(4, 6)));
648       } else
649         result.isUTC();
650       temp = null;
651     } catch (UnsupportedOperationException e) {
652       // we are sure that this method is used with a recurringDuration
653       // (if not a ParseException is thrown) so we can never reach that point
654     }
655     return result;
656   }// parse
657 
658   /**
659    * Override the java.lang.equals method
660    * 
661    * @see #equal
662    */
663   public boolean equals(Object object) {
664     if (object instanceof RecurringDuration) {
665       try {
666         return equal((RecurringDuration) object);
667       } catch (ValidationException e) {
668         e.printStackTrace();
669         return false;
670       }
671     }
672     return false;
673   }
674 
675   /**
676    * <p>
677    * Returns true if the present instance of Recurring Duration is equal to the parameter.
678    * <p>
679    * The equals relation is the following :
680    * <p>
681    * <tt>rd1 equals rd2 </tt> iff each field of rd1 is equal to the corresponding field of rd2
682    * 
683    * @param reccD the recurring duration to compare with the present instance
684    * @return true if the present instance is equal to the parameter false if not
685    */
686   public boolean equal(RecurringDuration reccD) throws ValidationException {
687     boolean result = false;
688     if (reccD == null)
689       return false;
690     if (!(this.getPeriod().equals(reccD.getPeriod()))
691         || !(this.getDuration().equals(reccD.getDuration()))) {
692       String err = " Recurring Duration which have different values "
693           + "for the duration and period can not be compared";
694       throw new ValidationException(err);
695     }
696     result = this.getCentury() == reccD.getCentury();
697     result = result && (this.getYear() == reccD.getYear());
698     result = result && (this.getMonth() == reccD.getMonth());
699     result = result && (this.getDay() == reccD.getDay());
700     result = result && (this.getHour() == reccD.getHour());
701     result = result && (this.getMinute() == reccD.getMinute());
702     result = result && (this.getSeconds() == reccD.getSeconds());
703     result = result && (this.getMilli() == reccD.getMilli());
704     result = result && (this.isNegative() == this.isNegative());
705     if (!reccD.isUTC()) {
706       result = result && (!this.isUTC());
707       result = result && (this.getZoneHour() == reccD.getZoneHour());
708       result = result && (this.getZoneMinute() == reccD.getZoneMinute());
709     }
710     return result;
711   }// equals
712 
713   /**
714    * <p>
715    * Returns true if the present instance of RecurringDuration is greater than the parameter
716    * <p>
717    * Note : the order relation follows the W3C XML Schema draft i.e <tt>rd1 < rd2 </tt>iff rd2-rd1>0
718    * 
719    * @param reccD the recurring duration to compare with the present instance
720    * @return true if the present instance is the greatest, false if not
721    */
722   public boolean isGreater(RecurringDuration reccD) throws ValidationException {
723     boolean result = false;
724     if (!(this.getPeriod().equals(reccD.getPeriod()))
725         || !(this.getDuration().equals(reccD.getDuration()))) {
726       String err = " Recurring Duration which have different values "
727           + "for the duration and period can not be compared";
728       throw new ValidationException(err);
729     }
730     short[] val_this = this.getValues();
731     short[] val_reccD = reccD.getValues();
732     int i = 0;
733     while ((result != true) && (i < (val_this.length - 1))) {
734       result = val_this[i] > val_reccD[i];
735       if (val_this[i] < val_reccD[i])
736         return false;
737       i++;
738     }
739     return result;
740   }// isGreater
741 
742 } // RecurringDuration