View Javadoc
1   package ca.uhn.fhir.rest.param;
2   
3   import ca.uhn.fhir.context.FhirContext;
4   import ca.uhn.fhir.model.api.IQueryParameterAnd;
5   import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
6   import ca.uhn.fhir.parser.DataFormatException;
7   import ca.uhn.fhir.rest.api.QualifiedParamList;
8   import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
9   import org.apache.commons.lang3.time.DateUtils;
10  import org.hl7.fhir.instance.model.api.IPrimitiveType;
11  
12  import java.util.*;
13  
14  import static ca.uhn.fhir.rest.param.ParamPrefixEnum.*;
15  import static java.lang.String.format;
16  import static org.apache.commons.lang3.StringUtils.isNotBlank;
17  
18  /*
19   * #%L
20   * HAPI FHIR - Core Library
21   * %%
22   * Copyright (C) 2014 - 2018 University Health Network
23   * %%
24   * Licensed under the Apache License, Version 2.0 (the "License");
25   * you may not use this file except in compliance with the License.
26   * You may obtain a copy of the License at
27   * 
28   *      http://www.apache.org/licenses/LICENSE-2.0
29   * 
30   * Unless required by applicable law or agreed to in writing, software
31   * distributed under the License is distributed on an "AS IS" BASIS,
32   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
33   * See the License for the specific language governing permissions and
34   * limitations under the License.
35   * #L%
36   */
37  
38  @SuppressWarnings("UnusedReturnValue")
39  public class DateRangeParam implements IQueryParameterAnd<DateParam> {
40  
41  	private static final long serialVersionUID = 1L;
42  
43  	private DateParam myLowerBound;
44  	private DateParam myUpperBound;
45  
46  	/**
47  	 * Basic constructor. Values must be supplied by calling {@link #setLowerBound(DateParam)} and
48  	 * {@link #setUpperBound(DateParam)}
49  	 */
50  	public DateRangeParam() {
51  		super();
52  	}
53  
54  	/**
55  	 * Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
56  	 *
57  	 * @param theLowerBound A qualified date param representing the lower date bound (optionally may include time), e.g.
58  	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
59  	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
60  	 * @param theUpperBound A qualified date param representing the upper date bound (optionally may include time), e.g.
61  	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
62  	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
63  	 */
64  	public DateRangeParam(Date theLowerBound, Date theUpperBound) {
65  		this();
66  		setRangeFromDatesInclusive(theLowerBound, theUpperBound);
67  	}
68  
69  	/**
70  	 * Sets the range from a single date param. If theDateParam has no qualifier, treats it as the lower and upper bound
71  	 * (e.g. 2011-01-02 would match any time on that day). If theDateParam has a qualifier, treats it as either the lower
72  	 * or upper bound, with no opposite bound.
73  	 */
74  	public DateRangeParam(DateParam theDateParam) {
75  		this();
76  		if (theDateParam == null) {
77  			throw new NullPointerException("theDateParam can not be null");
78  		}
79  		if (theDateParam.isEmpty()) {
80  			throw new IllegalArgumentException("theDateParam can not be empty");
81  		}
82  		if (theDateParam.getPrefix() == null) {
83  			setRangeFromDatesInclusive(theDateParam.getValueAsString(), theDateParam.getValueAsString());
84  		} else {
85  			switch (theDateParam.getPrefix()) {
86  				case EQUAL:
87  					setRangeFromDatesInclusive(theDateParam.getValueAsString(), theDateParam.getValueAsString());
88  					break;
89  				case STARTS_AFTER:
90  				case GREATERTHAN:
91  				case GREATERTHAN_OR_EQUALS:
92  					validateAndSet(theDateParam, null);
93  					break;
94  				case ENDS_BEFORE:
95  				case LESSTHAN:
96  				case LESSTHAN_OR_EQUALS:
97  					validateAndSet(null, theDateParam);
98  					break;
99  				default:
100 					// Should not happen
101 					throw new InvalidRequestException("Invalid comparator for date range parameter:" + theDateParam.getPrefix() + ". This is a bug.");
102 			}
103 		}
104 	}
105 
106 	/**
107 	 * Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
108 	 *
109 	 * @param theLowerBound A qualified date param representing the lower date bound (optionally may include time), e.g.
110 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
111 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
112 	 * @param theUpperBound A qualified date param representing the upper date bound (optionally may include time), e.g.
113 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
114 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
115 	 */
116 	public DateRangeParam(DateParam theLowerBound, DateParam theUpperBound) {
117 		this();
118 		setRangeFromDatesInclusive(theLowerBound, theUpperBound);
119 	}
120 
121 	/**
122 	 * Constructor which takes two Dates representing the lower and upper bounds of the range (inclusive on both ends)
123 	 *
124 	 * @param theLowerBound A qualified date param representing the lower date bound (optionally may include time), e.g.
125 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
126 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
127 	 * @param theUpperBound A qualified date param representing the upper date bound (optionally may include time), e.g.
128 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
129 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
130 	 */
131 	public DateRangeParam(IPrimitiveType<Date> theLowerBound, IPrimitiveType<Date> theUpperBound) {
132 		this();
133 		setRangeFromDatesInclusive(theLowerBound, theUpperBound);
134 	}
135 
136 	/**
137 	 * Constructor which takes two strings representing the lower and upper bounds of the range (inclusive on both ends)
138 	 *
139 	 * @param theLowerBound An unqualified date param representing the lower date bound (optionally may include time), e.g.
140 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Either theLowerBound or theUpperBound may both be populated, or
141 	 *                      one may be null, but it is not valid for both to be null.
142 	 * @param theUpperBound An unqualified date param representing the upper date bound (optionally may include time), e.g.
143 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Either theLowerBound or theUpperBound may both be populated, or
144 	 *                      one may be null, but it is not valid for both to be null.
145 	 */
146 	public DateRangeParam(String theLowerBound, String theUpperBound) {
147 		this();
148 		setRangeFromDatesInclusive(theLowerBound, theUpperBound);
149 	}
150 
151 	private void addParam(DateParam theParsed) throws InvalidRequestException {
152 		if (theParsed.getPrefix() == null || theParsed.getPrefix() == EQUAL) {
153 			if (myLowerBound != null || myUpperBound != null) {
154 				throw new InvalidRequestException("Can not have multiple date range parameters for the same param without a qualifier");
155 			}
156 
157 			if (theParsed.getMissing() != null) {
158 				myLowerBound = theParsed;
159 				myUpperBound = theParsed;
160 			} else {
161 				myLowerBound = new DateParam(EQUAL, theParsed.getValueAsString());
162 				myUpperBound = new DateParam(EQUAL, theParsed.getValueAsString());
163 			}
164 
165 		} else {
166 
167 			switch (theParsed.getPrefix()) {
168 				case GREATERTHAN:
169 				case GREATERTHAN_OR_EQUALS:
170 					if (myLowerBound != null) {
171 						throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify a lower bound");
172 					}
173 					myLowerBound = theParsed;
174 					break;
175 				case LESSTHAN:
176 				case LESSTHAN_OR_EQUALS:
177 					if (myUpperBound != null) {
178 						throw new InvalidRequestException("Can not have multiple date range parameters for the same param that specify an upper bound");
179 					}
180 					myUpperBound = theParsed;
181 					break;
182 				default:
183 					throw new InvalidRequestException("Unknown comparator: " + theParsed.getPrefix());
184 			}
185 
186 		}
187 	}
188 
189 	@Override
190 	public boolean equals(Object obj) {
191 		if (obj == this) {
192 			return true;
193 		}
194 		if (!(obj instanceof DateRangeParam)) {
195 			return false;
196 		}
197 		DateRangeParam other = (DateRangeParam) obj;
198 		return Objects.equals(myLowerBound, other.myLowerBound) &&
199 			Objects.equals(myUpperBound, other.myUpperBound);
200 	}
201 
202 	public DateParam getLowerBound() {
203 		return myLowerBound;
204 	}
205 
206 	public DateRangeParam setLowerBound(DateParam theLowerBound) {
207 		validateAndSet(theLowerBound, myUpperBound);
208 		return this;
209 	}
210 
211 	/**
212 	 * Sets the lower bound using a string that is compliant with
213 	 * FHIR dateTime format (ISO-8601).
214 	 * <p>
215 	 * This lower bound is assumed to have a <code>ge</code>
216 	 * (greater than or equals) modifier.
217 	 * </p>
218 	 */
219 	public DateRangeParam setLowerBound(String theLowerBound) {
220 		setLowerBound(new DateParam(GREATERTHAN_OR_EQUALS, theLowerBound));
221 		return this;
222 	}
223 
224 	/**
225 	 * Sets the lower bound to be greaterthan or equal to the given date
226 	 */
227 	public DateRangeParam setLowerBoundInclusive(Date theLowerBound) {
228 		validateAndSet(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, theLowerBound), myUpperBound);
229 		return this;
230 	}
231 
232 	/**
233 	 * Sets the upper bound to be greaterthan or equal to the given date
234 	 */
235 	public DateRangeParam setUpperBoundInclusive(Date theUpperBound) {
236 		validateAndSet(myLowerBound, new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, theUpperBound));
237 		return this;
238 	}
239 
240 
241 	/**
242 	 * Sets the lower bound to be greaterthan to the given date
243 	 */
244 	public DateRangeParam setLowerBoundExclusive(Date theLowerBound) {
245 		validateAndSet(new DateParam(ParamPrefixEnum.GREATERTHAN, theLowerBound), myUpperBound);
246 		return this;
247 	}
248 
249 	/**
250 	 * Sets the upper bound to be greaterthan to the given date
251 	 */
252 	public DateRangeParam setUpperBoundExclusive(Date theUpperBound) {
253 		validateAndSet(myLowerBound, new DateParam(ParamPrefixEnum.LESSTHAN, theUpperBound));
254 		return this;
255 	}
256 
257 	public Date getLowerBoundAsInstant() {
258 		if (myLowerBound == null || myLowerBound.getValue() == null) {
259 			return null;
260 		}
261 		Date retVal = myLowerBound.getValue();
262 
263 		if (myLowerBound.getPrecision().ordinal() <= TemporalPrecisionEnum.DAY.ordinal()) {
264 			Calendar cal = DateUtils.toCalendar(retVal);
265 			cal.setTimeZone(TimeZone.getTimeZone("GMT-11:30"));
266 			cal = DateUtils.truncate(cal, Calendar.DATE);
267 			retVal = cal.getTime();
268 		}
269 
270 		if (myLowerBound.getPrefix() != null) {
271 			switch (myLowerBound.getPrefix()) {
272 				case GREATERTHAN:
273 				case STARTS_AFTER:
274 					retVal = myLowerBound.getPrecision().add(retVal, 1);
275 					break;
276 				case EQUAL:
277 				case GREATERTHAN_OR_EQUALS:
278 					break;
279 				case LESSTHAN:
280 				case APPROXIMATE:
281 				case LESSTHAN_OR_EQUALS:
282 				case ENDS_BEFORE:
283 				case NOT_EQUAL:
284 					throw new IllegalStateException("Unvalid lower bound comparator: " + myLowerBound.getPrefix());
285 			}
286 		}
287 		return retVal;
288 	}
289 
290 	public DateParam getUpperBound() {
291 		return myUpperBound;
292 	}
293 
294 	/**
295 	 * Sets the upper bound using a string that is compliant with
296 	 * FHIR dateTime format (ISO-8601).
297 	 * <p>
298 	 * This upper bound is assumed to have a <code>le</code>
299 	 * (less than or equals) modifier.
300 	 * </p>
301 	 */
302 	public DateRangeParam setUpperBound(String theUpperBound) {
303 		setUpperBound(new DateParam(LESSTHAN_OR_EQUALS, theUpperBound));
304 		return this;
305 	}
306 
307 	public DateRangeParam setUpperBound(DateParam theUpperBound) {
308 		validateAndSet(myLowerBound, theUpperBound);
309 		return this;
310 	}
311 
312 	public Date getUpperBoundAsInstant() {
313 		if (myUpperBound == null || myUpperBound.getValue() == null) {
314 			return null;
315 		}
316 
317 		Date retVal = myUpperBound.getValue();
318 
319 		if (myUpperBound.getPrecision().ordinal() <= TemporalPrecisionEnum.DAY.ordinal()) {
320 			Calendar cal = DateUtils.toCalendar(retVal);
321 			cal.setTimeZone(TimeZone.getTimeZone("GMT+11:30"));
322 			cal = DateUtils.truncate(cal, Calendar.DATE);
323 			retVal = cal.getTime();
324 		}
325 
326 		if (myUpperBound.getPrefix() != null) {
327 			switch (myUpperBound.getPrefix()) {
328 				case LESSTHAN:
329 				case ENDS_BEFORE:
330 					retVal = new Date(retVal.getTime() - 1L);
331 					break;
332 				case EQUAL:
333 				case LESSTHAN_OR_EQUALS:
334 					retVal = myUpperBound.getPrecision().add(retVal, 1);
335 					retVal = new Date(retVal.getTime() - 1L);
336 					break;
337 				case GREATERTHAN_OR_EQUALS:
338 				case GREATERTHAN:
339 				case APPROXIMATE:
340 				case NOT_EQUAL:
341 				case STARTS_AFTER:
342 					throw new IllegalStateException("Unvalid upper bound comparator: " + myUpperBound.getPrefix());
343 			}
344 		}
345 		return retVal;
346 	}
347 
348 	@Override
349 	public List<DateParam> getValuesAsQueryTokens() {
350 		ArrayList<DateParam> retVal = new ArrayList<>();
351 		if (myLowerBound != null && myLowerBound.getMissing() != null) {
352 			retVal.add((myLowerBound));
353 		} else {
354 			if (myLowerBound != null && !myLowerBound.isEmpty()) {
355 				retVal.add((myLowerBound));
356 			}
357 			if (myUpperBound != null && !myUpperBound.isEmpty()) {
358 				retVal.add((myUpperBound));
359 			}
360 		}
361 		return retVal;
362 	}
363 
364 	private boolean hasBound(DateParam bound) {
365 		return bound != null && !bound.isEmpty();
366 	}
367 
368 	@Override
369 	public int hashCode() {
370 		return Objects.hash(myLowerBound, myUpperBound);
371 	}
372 
373 	public boolean isEmpty() {
374 		return (getLowerBoundAsInstant() == null) && (getUpperBoundAsInstant() == null);
375 	}
376 
377 	/**
378 	 * Sets the range from a pair of dates, inclusive on both ends
379 	 *
380 	 * @param theLowerBound A qualified date param representing the lower date bound (optionally may include time), e.g.
381 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
382 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
383 	 * @param theUpperBound A qualified date param representing the upper date bound (optionally may include time), e.g.
384 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
385 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
386 	 */
387 	public void setRangeFromDatesInclusive(Date theLowerBound, Date theUpperBound) {
388 		DateParam lowerBound = theLowerBound != null
389 			? new DateParam(GREATERTHAN_OR_EQUALS, theLowerBound) : null;
390 		DateParam upperBound = theUpperBound != null
391 			? new DateParam(LESSTHAN_OR_EQUALS, theUpperBound) : null;
392 		validateAndSet(lowerBound, upperBound);
393 	}
394 
395 	/**
396 	 * Sets the range from a pair of dates, inclusive on both ends
397 	 *
398 	 * @param theLowerBound A qualified date param representing the lower date bound (optionally may include time), e.g.
399 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
400 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
401 	 * @param theUpperBound A qualified date param representing the upper date bound (optionally may include time), e.g.
402 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
403 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
404 	 */
405 	public void setRangeFromDatesInclusive(DateParam theLowerBound, DateParam theUpperBound) {
406 		validateAndSet(theLowerBound, theUpperBound);
407 	}
408 
409 	/**
410 	 * Sets the range from a pair of dates, inclusive on both ends. Note that if
411 	 * theLowerBound is after theUpperBound, thie method will automatically reverse
412 	 * the order of the arguments in order to create an inclusive range.
413 	 *
414 	 * @param theLowerBound A qualified date param representing the lower date bound (optionally may include time), e.g.
415 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
416 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
417 	 * @param theUpperBound A qualified date param representing the upper date bound (optionally may include time), e.g.
418 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
419 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
420 	 */
421 	public void setRangeFromDatesInclusive(IPrimitiveType<Date> theLowerBound, IPrimitiveType<Date> theUpperBound) {
422 		IPrimitiveType<Date> lowerBound = theLowerBound;
423 		IPrimitiveType<Date> upperBound = theUpperBound;
424 		if (lowerBound != null && lowerBound.getValue() != null && upperBound != null && upperBound.getValue() != null) {
425 			if (lowerBound.getValue().after(upperBound.getValue())) {
426 				IPrimitiveType<Date> temp = lowerBound;
427 				lowerBound = upperBound;
428 				upperBound = temp;
429 			}
430 		}
431 		validateAndSet(
432 			lowerBound != null ? new DateParam(GREATERTHAN_OR_EQUALS, lowerBound) : null,
433 			upperBound != null ? new DateParam(LESSTHAN_OR_EQUALS, upperBound) : null);
434 	}
435 
436 	/**
437 	 * Sets the range from a pair of dates, inclusive on both ends
438 	 *
439 	 * @param theLowerBound A qualified date param representing the lower date bound (optionally may include time), e.g.
440 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
441 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
442 	 * @param theUpperBound A qualified date param representing the upper date bound (optionally may include time), e.g.
443 	 *                      "2011-02-22" or "2011-02-22T13:12:00Z". Will be treated inclusively. Either theLowerBound or
444 	 *                      theUpperBound may both be populated, or one may be null, but it is not valid for both to be null.
445 	 */
446 	public void setRangeFromDatesInclusive(String theLowerBound, String theUpperBound) {
447 		DateParam lowerBound = theLowerBound != null
448 			? new DateParam(GREATERTHAN_OR_EQUALS, theLowerBound)
449 			: null;
450 		DateParam upperBound = theUpperBound != null
451 			? new DateParam(LESSTHAN_OR_EQUALS, theUpperBound)
452 			: null;
453 		if (isNotBlank(theLowerBound) && isNotBlank(theUpperBound) && theLowerBound.equals(theUpperBound)) {
454 			lowerBound.setPrefix(EQUAL);
455 			upperBound.setPrefix(EQUAL);
456 		}
457 		validateAndSet(lowerBound, upperBound);
458 	}
459 
460 	@Override
461 	public void setValuesAsQueryTokens(FhirContext theContext, String theParamName, List<QualifiedParamList> theParameters)
462 		throws InvalidRequestException {
463 
464 		boolean haveHadUnqualifiedParameter = false;
465 		for (QualifiedParamList paramList : theParameters) {
466 			if (paramList.size() == 0) {
467 				continue;
468 			}
469 			if (paramList.size() > 1) {
470 				throw new InvalidRequestException("DateRange parameter does not suppport OR queries");
471 			}
472 			String param = paramList.get(0);
473 
474 			/*
475 			 * Since ' ' is escaped as '+' we'll be nice to anyone might have accidentally not
476 			 * escaped theirs
477 			 */
478 			param = param.replace(' ', '+');
479 
480 			DateParam parsed = new DateParam();
481 			parsed.setValueAsQueryToken(theContext, theParamName, paramList.getQualifier(), param);
482 			addParam(parsed);
483 
484 			if (parsed.getPrefix() == null) {
485 				if (haveHadUnqualifiedParameter) {
486 					throw new InvalidRequestException("Multiple date parameters with the same name and no qualifier (>, <, etc.) is not supported");
487 				}
488 				haveHadUnqualifiedParameter = true;
489 			}
490 
491 		}
492 
493 	}
494 
495 	@Override
496 	public String toString() {
497 		StringBuilder b = new StringBuilder();
498 		b.append(getClass().getSimpleName());
499 		b.append("[");
500 		if (hasBound(myLowerBound)) {
501 			if (myLowerBound.getPrefix() != null) {
502 				b.append(myLowerBound.getPrefix().getValue());
503 			}
504 			b.append(myLowerBound.getValueAsString());
505 		}
506 		if (hasBound(myUpperBound)) {
507 			if (hasBound(myLowerBound)) {
508 				b.append(" ");
509 			}
510 			if (myUpperBound.getPrefix() != null) {
511 				b.append(myUpperBound.getPrefix().getValue());
512 			}
513 			b.append(myUpperBound.getValueAsString());
514 		} else {
515 			if (!hasBound(myLowerBound)) {
516 				b.append("empty");
517 			}
518 		}
519 		b.append("]");
520 		return b.toString();
521 	}
522 
523 	private void validateAndSet(DateParam lowerBound, DateParam upperBound) {
524 		if (hasBound(lowerBound) && hasBound(upperBound)) {
525 			if (lowerBound.getValue().getTime() > upperBound.getValue().getTime()) {
526 				throw new DataFormatException(format(
527 					"Lower bound of %s is after upper bound of %s",
528 					lowerBound.getValueAsString(), upperBound.getValueAsString()));
529 			}
530 		}
531 
532 		if (hasBound(lowerBound)) {
533 			if (lowerBound.getPrefix() == null) {
534 				lowerBound.setPrefix(GREATERTHAN_OR_EQUALS);
535 			}
536 			switch (lowerBound.getPrefix()) {
537 				case GREATERTHAN:
538 				case GREATERTHAN_OR_EQUALS:
539 				default:
540 					break;
541 				case LESSTHAN:
542 				case LESSTHAN_OR_EQUALS:
543 					throw new DataFormatException("Lower bound comparator must be > or >=, can not be " + lowerBound.getPrefix().getValue());
544 			}
545 		}
546 
547 		if (hasBound(upperBound)) {
548 			if (upperBound.getPrefix() == null) {
549 				upperBound.setPrefix(LESSTHAN_OR_EQUALS);
550 			}
551 			switch (upperBound.getPrefix()) {
552 				case LESSTHAN:
553 				case LESSTHAN_OR_EQUALS:
554 				default:
555 					break;
556 				case GREATERTHAN:
557 				case GREATERTHAN_OR_EQUALS:
558 					throw new DataFormatException("Upper bound comparator must be < or <=, can not be " + upperBound.getPrefix().getValue());
559 			}
560 		}
561 
562 		myLowerBound = lowerBound;
563 		myUpperBound = upperBound;
564 	}
565 
566 }