1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70 public class RecurringDuration extends RecurringDurationBase {
71
72 private static final long serialVersionUID = -6037158412155942249L;
73
74
75 private static final String DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss.SSS";
76
77
78 private static final boolean DEBUG = false;
79
80
81
82
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
94
95
96
97
98 public RecurringDuration(TimeDuration duration, TimeDuration period) {
99 super(duration, period);
100 }
101
102
103
104
105
106
107
108 public RecurringDuration(String duration, String period) {
109 super(duration, period);
110 }
111
112
113
114
115
116
117
118
119
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
132
133
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
146
147
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
167
168
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
193
194
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
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 }
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
240
241
242
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
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
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
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
305
306
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 }
323
324
325
326
327
328
329
330
331
332
333
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
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 }
352
353
354
355
356
357
358
359
360
361
362 public String toString() {
363 return this.toPrivateString();
364 }
365
366
367
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
401
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
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 }
457
458 public static Object parse(String str) throws ParseException {
459 return parseRecurringDuration(str);
460 }
461
462
463
464
465
466
467
468
469
470 public static RecurringDuration parseRecurringDuration(String str) throws ParseException {
471
472 RecurringDuration result = new RecurringDuration();
473
474
475 if (str.endsWith("Z"))
476 str = str.substring(0, str.indexOf("Z"));
477
478
479 if (str.startsWith("-") && !str.startsWith("--"))
480 result.setNegative();
481
482
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
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
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
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
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
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
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
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
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
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
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
653
654 }
655 return result;
656 }
657
658
659
660
661
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
677
678
679
680
681
682
683
684
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 }
712
713
714
715
716
717
718
719
720
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 }
741
742 }