KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xerces > impl > dv > xs > DurationDV


1 /*
2  * Copyright 1999-2002,2004,2005 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.apache.xerces.impl.dv.xs;
18
19 import java.math.BigDecimal JavaDoc;
20 import java.math.BigInteger JavaDoc;
21
22 import javax.xml.datatype.DatatypeConstants JavaDoc;
23 import javax.xml.datatype.Duration JavaDoc;
24
25 import org.apache.xerces.impl.dv.InvalidDatatypeValueException;
26 import org.apache.xerces.impl.dv.ValidationContext;
27
28 /**
29  * Validator for <duration> datatype (W3C Schema Datatypes)
30  *
31  * @xerces.internal
32  *
33  * @author Elena Litani
34  * @author Gopal Sharma, SUN Microsystem Inc.
35  * @version $Id: DurationDV.java,v 1.20 2005/05/06 15:31:14 ankitp Exp $
36  */

37 public class DurationDV extends AbstractDateTimeDV {
38
39     public static final int DURATION_TYPE = 0;
40     public static final int YEARMONTHDURATION_TYPE = 1;
41     public static final int DAYTIMEDURATION_TYPE = 2;
42     // order-relation on duration is a partial order. The dates below are used to
43
// for comparison of 2 durations, based on the fact that
44
// duration x and y is x<=y iff s+x<=s+y
45
// see 3.2.6 duration W3C schema datatype specs
46
//
47
// the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone}
48
private final static DateTimeData[] DATETIMES= {
49         new DateTimeData(1696, 9, 1, 0, 0, 0, 'Z', null, true, null),
50         new DateTimeData(1697, 2, 1, 0, 0, 0, 'Z', null, true, null),
51         new DateTimeData(1903, 3, 1, 0, 0, 0, 'Z', null, true, null),
52         new DateTimeData(1903, 7, 1, 0, 0, 0, 'Z', null, true, null)};
53
54     public Object JavaDoc getActualValue(String JavaDoc content, ValidationContext context) throws InvalidDatatypeValueException{
55         try{
56             return parse(content, DURATION_TYPE);
57         } catch (Exception JavaDoc ex) {
58             throw new InvalidDatatypeValueException("cvc-datatype-valid.1.2.1", new Object JavaDoc[]{content, "duration"});
59         }
60     }
61
62     /**
63      * Parses, validates and computes normalized version of duration object
64      *
65      * @param str The lexical representation of duration object PnYn MnDTnH nMnS
66      * @param durationType
67      * @return normalized date representation
68      * @exception SchemaDateTimeException Invalid lexical representation
69      */

70     protected DateTimeData parse(String JavaDoc str, int durationType) throws SchemaDateTimeException{
71         int len = str.length();
72         DateTimeData date= new DateTimeData(str, this);
73         
74         int start = 0;
75         char c=str.charAt(start++);
76         if ( c!='P' && c!='-' ) {
77             throw new SchemaDateTimeException();
78         }
79         else {
80             date.utc=(c=='-')?'-':0;
81             if ( c=='-' && str.charAt(start++)!='P' ) {
82                 throw new SchemaDateTimeException();
83             }
84         }
85         
86         int negate = 1;
87         //negative duration
88
if ( date.utc=='-' ) {
89             negate = -1;
90             
91         }
92         //at least one number and designator must be seen after P
93
boolean designator = false;
94         
95         int endDate = indexOf (str, start, len, 'T');
96         if ( endDate == -1 ) {
97             endDate = len;
98         }
99         else if (durationType == YEARMONTHDURATION_TYPE) {
100             throw new SchemaDateTimeException();
101         }
102         
103         //find 'Y'
104
int end = indexOf (str, start, endDate, 'Y');
105         if ( end!=-1 ) {
106             
107             if (durationType == DAYTIMEDURATION_TYPE) {
108                 throw new SchemaDateTimeException();
109             }
110             
111             //scan year
112
date.year=negate * parseInt(str,start,end);
113             start = end+1;
114             designator = true;
115         }
116         
117         end = indexOf (str, start, endDate, 'M');
118         if ( end!=-1 ) {
119             
120             if (durationType == DAYTIMEDURATION_TYPE) {
121                 throw new SchemaDateTimeException();
122             }
123             
124             //scan month
125
date.month=negate * parseInt(str,start,end);
126             start = end+1;
127             designator = true;
128         }
129         
130         end = indexOf (str, start, endDate, 'D');
131         if ( end!=-1 ) {
132             
133             if(durationType == YEARMONTHDURATION_TYPE) {
134                 throw new SchemaDateTimeException();
135             }
136             
137             //scan day
138
date.day=negate * parseInt(str,start,end);
139             start = end+1;
140             designator = true;
141         }
142         
143         if ( len == endDate && start!=len ) {
144             throw new SchemaDateTimeException();
145         }
146         if ( len !=endDate ) {
147             
148             //scan hours, minutes, seconds
149
//REVISIT: can any item include a decimal fraction or only seconds?
150
//
151

152             end = indexOf (str, ++start, len, 'H');
153             if ( end!=-1 ) {
154                 //scan hours
155
date.hour=negate * parseInt(str,start,end);
156                 start=end+1;
157                 designator = true;
158             }
159             
160             end = indexOf (str, start, len, 'M');
161             if ( end!=-1 ) {
162                 //scan min
163
date.minute=negate * parseInt(str,start,end);
164                 start=end+1;
165                 designator = true;
166             }
167             
168             end = indexOf (str, start, len, 'S');
169             if ( end!=-1 ) {
170                 //scan seconds
171
date.second = negate * parseSecond(str, start, end);
172                 start=end+1;
173                 designator = true;
174             }
175             // no additional data shouls appear after last item
176
// P1Y1M1DT is illigal value as well
177
if ( start != len || str.charAt(--start)=='T' ) {
178                 throw new SchemaDateTimeException();
179             }
180         }
181         
182         if ( !designator ) {
183             throw new SchemaDateTimeException();
184         }
185         
186         return date;
187     }
188
189     /**
190      * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration")
191      *
192      * @param date1 Unnormalized duration
193      * @param date2 Unnormalized duration
194      * @param strict (min/max)Exclusive strict == true ( LESS_THAN ) or ( GREATER_THAN )
195      * (min/max)Inclusive strict == false (LESS_EQUAL) or (GREATER_EQUAL)
196      * @return INDETERMINATE if the order relationship between date1 and date2 is indeterminate.
197      * EQUAL if the order relation between date1 and date2 is EQUAL.
198      * If the strict parameter is true, return LESS_THAN if date1 is less than date2 and
199      * return GREATER_THAN if date1 is greater than date2.
200      * If the strict parameter is false, return LESS_THAN if date1 is less than OR equal to date2 and
201      * return GREATER_THAN if date1 is greater than OR equal to date2
202      */

203     protected short compareDates(DateTimeData date1, DateTimeData date2, boolean strict) {
204
205         //REVISIT: this is unoptimazed vs of comparing 2 durations
206
// Algorithm is described in 3.2.6.2 W3C Schema Datatype specs
207
//
208

209         //add constA to both durations
210
short resultA, resultB= INDETERMINATE;
211         //try and see if the objects are equal
212
resultA = compareOrder (date1, date2);
213         if ( resultA == 0 ) {
214             return 0;
215         }
216
217         DateTimeData[] result = new DateTimeData[2];
218         result[0] = new DateTimeData(null, this);
219         result[1] = new DateTimeData(null, this);
220
221         //long comparison algorithm is required
222
DateTimeData tempA = addDuration (date1, DATETIMES[0], result[0]);
223         DateTimeData tempB = addDuration (date2, DATETIMES[0], result[1]);
224         resultA = compareOrder(tempA, tempB);
225         if ( resultA == INDETERMINATE ) {
226             return INDETERMINATE;
227         }
228
229         tempA = addDuration(date1, DATETIMES[1], result[0]);
230         tempB = addDuration(date2, DATETIMES[1], result[1]);
231         resultB = compareOrder(tempA, tempB);
232         resultA = compareResults(resultA, resultB, strict);
233         if (resultA == INDETERMINATE) {
234             return INDETERMINATE;
235         }
236
237         tempA = addDuration(date1, DATETIMES[2], result[0]);
238         tempB = addDuration(date2, DATETIMES[2], result[1]);
239         resultB = compareOrder(tempA, tempB);
240         resultA = compareResults(resultA, resultB, strict);
241         if (resultA == INDETERMINATE) {
242             return INDETERMINATE;
243         }
244
245         tempA = addDuration(date1, DATETIMES[3], result[0]);
246         tempB = addDuration(date2, DATETIMES[3], result[1]);
247         resultB = compareOrder(tempA, tempB);
248         resultA = compareResults(resultA, resultB, strict);
249
250         return resultA;
251     }
252
253     private short compareResults(short resultA, short resultB, boolean strict){
254
255       if ( resultB == INDETERMINATE ) {
256             return INDETERMINATE;
257         }
258         else if ( resultA!=resultB && strict ) {
259             return INDETERMINATE;
260         }
261         else if ( resultA!=resultB && !strict ) {
262             if ( resultA!=0 && resultB!=0 ) {
263                 return INDETERMINATE;
264             }
265             else {
266                 return (resultA!=0)?resultA:resultB;
267             }
268         }
269         return resultA;
270     }
271
272     private DateTimeData addDuration(DateTimeData date, DateTimeData addto, DateTimeData duration) {
273
274         //REVISIT: some code could be shared between normalize() and this method,
275
// however is it worth moving it? The structures are different...
276
//
277

278         resetDateObj(duration);
279         //add months (may be modified additionaly below)
280
int temp = addto.month + date.month;
281         duration.month = modulo (temp, 1, 13);
282         int carry = fQuotient (temp, 1, 13);
283
284         //add years (may be modified additionaly below)
285
duration.year=addto.year + date.year + carry;
286
287         //add seconds
288
double dtemp = addto.second + date.second;
289         carry = (int)Math.floor(dtemp/60);
290         duration.second = dtemp - carry*60;
291
292         //add minutes
293
temp = addto.minute +date.minute + carry;
294         carry = fQuotient (temp, 60);
295         duration.minute= mod(temp, 60, carry);
296
297         //add hours
298
temp = addto.hour + date.hour + carry;
299         carry = fQuotient(temp, 24);
300         duration.hour = mod(temp, 24, carry);
301
302
303         duration.day=addto.day + date.day + carry;
304
305         while ( true ) {
306
307             temp=maxDayInMonthFor(duration.year, duration.month);
308             if ( duration.day < 1 ) { //original duration was negative
309
duration.day = duration.day + maxDayInMonthFor(duration.year, duration.month-1);
310                 carry=-1;
311             }
312             else if ( duration.day > temp ) {
313                 duration.day = duration.day - temp;
314                 carry=1;
315             }
316             else {
317                 break;
318             }
319             temp = duration.month+carry;
320             duration.month = modulo(temp, 1, 13);
321             duration.year = duration.year+fQuotient(temp, 1, 13);
322         }
323
324         duration.utc='Z';
325         return duration;
326     }
327
328     protected double parseSecond(String JavaDoc buffer, int start, int end)
329         throws NumberFormatException JavaDoc {
330         int dot = -1;
331         for (int i = start; i < end; i++) {
332             char ch = buffer.charAt(i);
333             if (ch == '.')
334                 dot = i;
335             else if (ch > '9' || ch < '0')
336                 throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
337         }
338         if (dot+1 == end) {
339             throw new NumberFormatException JavaDoc("'" + buffer + "' has wrong format");
340         }
341         return Double.parseDouble(buffer.substring(start, end));
342     }
343
344     protected String JavaDoc dateToString(DateTimeData date) {
345         StringBuffer JavaDoc message = new StringBuffer JavaDoc(30);
346         if ( date.year<0 || date.month<0 || date.day<0
347                 || date.hour<0 || date.minute<0 || date.second<0) {
348             message.append('-');
349         }
350         message.append('P');
351         message.append((date.year < 0?-1:1) * date.year);
352         message.append('Y');
353         message.append((date.month < 0?-1:1) * date.month);
354         message.append('M');
355         message.append((date.day < 0?-1:1) * date.day);
356         message.append('D');
357         message.append('T');
358         message.append((date.hour < 0?-1:1) * date.hour);
359         message.append('H');
360         message.append((date.minute < 0?-1:1) * date.minute);
361         message.append('M');
362         message.append((date.second < 0?-1:1) * date.second);
363         message.append('S');
364
365         return message.toString();
366     }
367     
368     protected Duration JavaDoc getDuration(DateTimeData date) {
369         int sign = 1;
370         if ( date.year<0 || date.month<0 || date.day<0
371                 || date.hour<0 || date.minute<0 || date.second<0) {
372             sign = -1;
373         }
374         return factory.newDuration(sign == 1,
375                 date.year != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.year):null,
376                 date.month != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.month):null,
377                 date.day != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.day):null,
378                 date.hour != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.hour):null,
379                 date.minute != DatatypeConstants.FIELD_UNDEFINED?BigInteger.valueOf(sign*date.minute):null,
380                 date.second != DatatypeConstants.FIELD_UNDEFINED?new BigDecimal JavaDoc(String.valueOf(sign*date.second)):null);
381     }
382 }
383
Popular Tags