KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > eclipse > emf > ecore > xml > type > internal > XMLDuration


1 /**
2  * <copyright>
3  *
4  * Copyright (c) 2004 IBM Corporation and others.
5  * All rights reserved. This program and the accompanying materials
6  * are made available under the terms of the Eclipse Public License v1.0
7  * which accompanies this distribution, and is available at
8  * http://www.eclipse.org/legal/epl-v10.html
9  *
10  * Contributors:
11  * IBM - Initial API and implementation
12  *
13  * </copyright>
14  *
15  * $Id: XMLDuration.java,v 1.4 2005/06/08 06:20:10 nickb Exp $
16  *
17  * ---------------------------------------------------------------------
18  *
19  * The Apache Software License, Version 1.1
20  *
21  *
22  * Copyright (c) 1999-2004 The Apache Software Foundation. All rights
23  * reserved.
24  *
25  * Redistribution and use in source and binary forms, with or without
26  * modification, are permitted provided that the following conditions
27  * are met:
28  *
29  * 1. Redistributions of source code must retain the above copyright
30  * notice, this list of conditions and the following disclaimer.
31  *
32  * 2. Redistributions in binary form must reproduce the above copyright
33  * notice, this list of conditions and the following disclaimer in
34  * the documentation and/or other materials provided with the
35  * distribution.
36  *
37  * 3. The end-user documentation included with the redistribution,
38  * if any, must include the following acknowledgment:
39  * "This product includes software developed by the
40  * Apache Software Foundation (http://www.apache.org/)."
41  * Alternately, this acknowledgment may appear in the software itself,
42  * if and wherever such third-party acknowledgments normally appear.
43  *
44  * 4. The names "Xerces" and "Apache Software Foundation" must
45  * not be used to endorse or promote products derived from this
46  * software without prior written permission. For written
47  * permission, please contact apache@apache.org.
48  *
49  * 5. Products derived from this software may not be called "Apache",
50  * nor may "Apache" appear in their name, without prior written
51  * permission of the Apache Software Foundation.
52  *
53  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
54  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
56  * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
57  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
58  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
59  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
60  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
61  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
62  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
63  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
64  * SUCH DAMAGE.
65  * ====================================================================
66  *
67  * This software consists of voluntary contributions made by many
68  * individuals on behalf of the Apache Software Foundation and was
69  * originally based on software copyright (c) 1999-2003, International
70  * Business Machines, Inc., http://www.apache.org. For more
71  * information on the Apache Software Foundation, please see
72  * <http://www.apache.org/>.
73  */

74 package org.eclipse.emf.ecore.xml.type.internal;
75
76 import org.eclipse.emf.ecore.xml.type.InvalidDatatypeValueException;
77 import org.eclipse.emf.ecore.xml.type.internal.DataValue.TypeValidator;
78
79
80 /**
81  * Representation for the <a HREF="http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/">W3C XML Schema 1.0</a>
82  * duration datatype.
83  *
84  * NOTE: this class is for internal use only.
85  * Later this class will be replaced by JAXP 1.3 javax.xml.datatype.Duration class.
86  * This class is based on Apache Xerces2 2.6.2 parser implementation of date/time validation.
87  */

88 public final class XMLDuration {
89
90    private final String JavaDoc ERROR_MESSAGE="The 'duration' value is invalid: ";
91     // order-relation on duration is a partial order. The dates below are used to
92
// for comparison of 2 durations, based on the fact that
93
// duration x and y is x<=y iff s+x<=s+y
94
// see 3.2.6 duration W3C schema datatype specs
95
//
96
// the dates are in format: {CCYY,MM,DD, H, S, M, MS, timezone}
97
private final static int[][] DATETIMES= {
98         {1696, 9, 1, 0, 0, 0, 0, 'Z'},
99         {1697, 2, 1, 0, 0, 0, 0, 'Z'},
100         {1903, 3, 1, 0, 0, 0, 0, 'Z'},
101         {1903, 7, 1, 0, 0, 0, 0, 'Z'}};
102     
103     private int hashCode = 0;
104     
105     final int[] dateValue;
106     
107     final String JavaDoc valueString;
108
109     public XMLDuration(String JavaDoc value)
110     {
111       this.dateValue = parse(value);
112       valueString = value;
113     }
114     
115     public boolean equals(Object JavaDoc obj)
116     {
117       if (!(obj instanceof XMLDuration))
118         return false;
119       int[] odata = ((XMLDuration)obj).dateValue;
120       return compareDates(dateValue, odata, true) == 0;
121     }
122     
123     public int hashCode()
124     {
125       if (hashCode == 0)
126       {
127         int[] temp = addDuration(dateValue, DATETIMES[0], new int[XMLCalendar.TOTAL_SIZE]);
128         for (int i=0;i<XMLCalendar.TOTAL_SIZE;i++)
129         {
130           hashCode^=temp[i];
131         }
132       }
133       return hashCode;
134     }
135     
136     // the parameters are in compiled form (from getActualValue)
137
public static int compare(XMLDuration value1, XMLDuration value2)
138     {
139       return compareDates(value1.dateValue, value2.dateValue, true);
140     }//compare()
141

142
143     /**
144      * Parses, validates and computes normalized version of duration object
145      *
146      * @param str The lexical representation of duration object PnYn MnDTnH nMnS
147      * @return normalized date representation
148      * @exception InvalidDatatypeValueException Invalid lexical representation
149      */

150     private int[] parse(String JavaDoc str) throws InvalidDatatypeValueException{
151         int len = str.length();
152         int[] date=new int[XMLCalendar.TOTAL_SIZE];
153
154         int start = 0;
155         char c=str.charAt(start++);
156         if ( c!='P' && c!='-' ) {
157             throw new InvalidDatatypeValueException(ERROR_MESSAGE+str);
158         }
159         else {
160             date[XMLCalendar.utc]=(c=='-')?'-':0;
161             if ( c=='-' && str.charAt(start++)!='P' ) {
162                 throw new InvalidDatatypeValueException(ERROR_MESSAGE+str);
163             }
164         }
165
166         int negate = 1;
167         //negative duration
168
if ( date[XMLCalendar.utc]=='-' ) {
169             negate = -1;
170
171         }
172         //at least one number and designator must be seen after P
173
boolean designator = false;
174
175         int endDate = XMLCalendar.indexOf (str, start, len, 'T');
176         if ( endDate == -1 ) {
177             endDate = len;
178         }
179         //find 'Y'
180
int end = XMLCalendar.indexOf (str, start, endDate, 'Y');
181         if ( end!=-1 ) {
182             //scan year
183
date[XMLCalendar.CY]=negate * XMLCalendar.parseInt(str,start,end);
184             start = end+1;
185             designator = true;
186         }
187
188         end = XMLCalendar.indexOf (str, start, endDate, 'M');
189         if ( end!=-1 ) {
190             //scan month
191
date[XMLCalendar.M]=negate * XMLCalendar.parseInt(str,start,end);
192             start = end+1;
193             designator = true;
194         }
195
196         end = XMLCalendar.indexOf (str, start, endDate, 'D');
197         if ( end!=-1 ) {
198             //scan day
199
date[XMLCalendar.D]=negate * XMLCalendar.parseInt(str,start,end);
200             start = end+1;
201             designator = true;
202         }
203
204         if ( len == endDate && start!=len ) {
205             throw new InvalidDatatypeValueException(ERROR_MESSAGE+str);
206         }
207         if ( len !=endDate ) {
208
209             end = XMLCalendar.indexOf (str, ++start, len, 'H');
210             if ( end!=-1 ) {
211                 //scan hours
212
date[XMLCalendar.h]=negate * XMLCalendar.parseInt(str,start,end);
213                 start=end+1;
214                 designator = true;
215             }
216
217             end = XMLCalendar.indexOf (str, start, len, 'M');
218             if ( end!=-1 ) {
219                 //scan min
220
date[XMLCalendar.m]=negate * XMLCalendar.parseInt(str,start,end);
221                 start=end+1;
222                 designator = true;
223             }
224
225             end = XMLCalendar.indexOf (str, start, len, 'S');
226             if ( end!=-1 ) {
227                 //scan seconds
228
int mlsec = XMLCalendar.indexOf (str, start, end, '.');
229                 if ( mlsec >0 ) {
230                     date[XMLCalendar.s] = negate * XMLCalendar.parseInt (str, start, mlsec);
231                     date[XMLCalendar.ms] = negate * XMLCalendar.parseInt (str, mlsec+1, end);
232                 }
233                 else {
234                     date[XMLCalendar.s]=negate * XMLCalendar.parseInt(str, start,end);
235                 }
236                 start=end+1;
237                 designator = true;
238             }
239             // no additional data shouls appear after last item
240
// P1Y1M1DT is illigal value as well
241
if ( start != len || str.charAt(--start)=='T' ) {
242                 throw new InvalidDatatypeValueException(ERROR_MESSAGE+str);
243             }
244         }
245
246         if ( !designator ) {
247             throw new InvalidDatatypeValueException(ERROR_MESSAGE+str);
248         }
249
250         return date;
251     }
252
253     /**
254      * Compares 2 given durations. (refer to W3C Schema Datatypes "3.2.6 duration")
255      *
256      * @param date1 Unnormalized duration
257      * @param date2 Unnormalized duration
258      * @param strict (min/max)Exclusive strict == true ( LESS_THAN ) or ( GREATER_THAN )
259      * (min/max)Inclusive strict == false (LESS_EQUAL) or (GREATER_EQUAL)
260      * @return INDETERMINATE if the order relationship between date1 and date2 is indeterminate.
261      * EQUAL if the order relation between date1 and date2 is EQUAL.
262      * If the strict parameter is true, return LESS_THAN if date1 is less than date2 and
263      * return GREATER_THAN if date1 is greater than date2.
264      * If the strict parameter is false, return LESS_THAN if date1 is less than OR equal to date2 and
265      * return GREATER_THAN if date1 is greater than OR equal to date2
266      */

267     protected static short compareDates(int[] date1, int[] date2, boolean strict) {
268
269         //REVISIT: this is unoptimazed vs of comparing 2 durations
270
// Algorithm is described in 3.2.6.2 W3C Schema Datatype specs
271
//
272

273         //add constA to both durations
274
short resultA, resultB= TypeValidator.INDETERMINATE;
275
276         //try and see if the objects are equal
277
resultA = XMLCalendar.compareOrder (date1, date2);
278         if ( resultA == 0 ) {
279             return 0;
280         }
281
282         int[][] result = new int[2][XMLCalendar.TOTAL_SIZE];
283
284         //long comparison algorithm is required
285
int[] tempA = addDuration (date1, DATETIMES[0], result[0]);
286         int[] tempB = addDuration (date2, DATETIMES[0], result[1]);
287         resultA = XMLCalendar.compareOrder(tempA, tempB);
288         if ( resultA == TypeValidator.INDETERMINATE ) {
289             return TypeValidator.INDETERMINATE;
290         }
291
292         tempA = addDuration(date1, DATETIMES[1], result[0]);
293         tempB = addDuration(date2, DATETIMES[1], result[1]);
294         resultB = XMLCalendar.compareOrder(tempA, tempB);
295         resultA = compareResults(resultA, resultB, strict);
296         if (resultA == TypeValidator.INDETERMINATE) {
297             return TypeValidator.INDETERMINATE;
298         }
299
300         tempA = addDuration(date1, DATETIMES[2], result[0]);
301         tempB = addDuration(date2, DATETIMES[2], result[1]);
302         resultB = XMLCalendar.compareOrder(tempA, tempB);
303         resultA = compareResults(resultA, resultB, strict);
304         if (resultA == TypeValidator.INDETERMINATE) {
305             return TypeValidator.INDETERMINATE;
306         }
307
308         tempA = addDuration(date1, DATETIMES[3], result[0]);
309         tempB = addDuration(date2, DATETIMES[3], result[1]);
310         resultB = XMLCalendar.compareOrder(tempA, tempB);
311         resultA = compareResults(resultA, resultB, strict);
312
313         return resultA;
314     }
315
316     private static short compareResults(short resultA, short resultB, boolean strict){
317
318       if ( resultB == TypeValidator.INDETERMINATE ) {
319             return TypeValidator.INDETERMINATE;
320         }
321         else if ( resultA!=resultB && strict ) {
322             return TypeValidator.INDETERMINATE;
323         }
324         else if ( resultA!=resultB && !strict ) {
325             if ( resultA!=0 && resultB!=0 ) {
326                 return TypeValidator.INDETERMINATE;
327             }
328             else {
329                 return (resultA!=0)?resultA:resultB;
330             }
331         }
332         return resultA;
333     }
334
335     private static int[] addDuration(int[] date, int[] addto, int[] duration) {
336
337         //REVISIT: some code could be shared between normalize() and this method,
338
// however is it worth moving it? The structures are different...
339
//
340

341         XMLCalendar.resetDateObj(duration);
342         //add months (may be modified additionaly below)
343
int temp = addto[XMLCalendar.M] + date[XMLCalendar.M];
344         duration[XMLCalendar.M] = XMLCalendar.modulo (temp, 1, 13);
345         int carry = XMLCalendar.fQuotient (temp, 1, 13);
346
347         //add years (may be modified additionaly below)
348
duration[XMLCalendar.CY]=addto[XMLCalendar.CY] + date[XMLCalendar.CY] + carry;
349         
350         //add seconds
351
temp = addto[XMLCalendar.s] + date[XMLCalendar.s];
352         carry = XMLCalendar.fQuotient (temp, 60);
353         duration[XMLCalendar.s] = XMLCalendar.mod(temp, 60, carry);
354
355         //add minutes
356
temp = addto[XMLCalendar.m] +date[XMLCalendar.m] + carry;
357         carry = XMLCalendar.fQuotient (temp, 60);
358         duration[XMLCalendar.m]= XMLCalendar.mod(temp, 60, carry);
359
360         //add hours
361
temp = addto[XMLCalendar.h] + date[XMLCalendar.h] + carry;
362         carry = XMLCalendar.fQuotient(temp, 24);
363         duration[XMLCalendar.h] = XMLCalendar.mod(temp, 24, carry);
364
365
366         duration[XMLCalendar.D]=addto[XMLCalendar.D] + date[XMLCalendar.D] + carry;
367
368         while ( true ) {
369
370             temp=XMLCalendar.maxDayInMonthFor(duration[XMLCalendar.CY], duration[XMLCalendar.M]);
371             if ( duration[XMLCalendar.D] < 1 ) { //original duration was negative
372
duration[XMLCalendar.D] = duration[XMLCalendar.D] + XMLCalendar.maxDayInMonthFor(duration[XMLCalendar.CY], duration[XMLCalendar.M]-1);
373                 carry=-1;
374             }
375             else if ( duration[XMLCalendar.D] > temp ) {
376                 duration[XMLCalendar.D] = duration[XMLCalendar.D] - temp;
377                 carry=1;
378             }
379             else {
380                 break;
381             }
382             temp = duration[XMLCalendar.M]+carry;
383             duration[XMLCalendar.M] = XMLCalendar.modulo(temp, 1, 13);
384             duration[XMLCalendar.CY] = duration[XMLCalendar.CY]+XMLCalendar.fQuotient(temp, 1, 13);
385         }
386
387         duration[XMLCalendar.utc]='Z';
388         return duration;
389     }
390
391     public String JavaDoc toString() {
392       return valueString;
393     }
394 }
395
Popular Tags