View Javadoc
1   package ca.uhn.fhir.rest.param;
2   
3   /*
4    * #%L
5    * HAPI FHIR - Core Library
6    * %%
7    * Copyright (C) 2014 - 2019 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   * 
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   * 
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import ca.uhn.fhir.context.FhirContext;
24  import ca.uhn.fhir.model.api.IQueryParameterOr;
25  import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
26  import ca.uhn.fhir.model.api.annotation.SimpleSetter;
27  import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
28  import ca.uhn.fhir.model.primitive.DateDt;
29  import ca.uhn.fhir.model.primitive.DateTimeDt;
30  import ca.uhn.fhir.model.primitive.InstantDt;
31  import ca.uhn.fhir.parser.DataFormatException;
32  import ca.uhn.fhir.rest.api.QualifiedParamList;
33  import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
34  import ca.uhn.fhir.util.ObjectUtil;
35  import ca.uhn.fhir.util.ValidateUtil;
36  import org.apache.commons.lang3.ObjectUtils;
37  import org.apache.commons.lang3.builder.ToStringBuilder;
38  import org.apache.commons.lang3.builder.ToStringStyle;
39  import org.apache.commons.lang3.time.DateUtils;
40  import org.hl7.fhir.instance.model.api.IPrimitiveType;
41  
42  import java.util.*;
43  
44  import static org.apache.commons.lang3.StringUtils.isNotBlank;
45  
46  public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQueryParameterType , */IQueryParameterOr<DateParam> {
47  
48  	private static final long serialVersionUID = 1L;
49  	
50  	private final DateParamDateTimeHolder myValue = new DateParamDateTimeHolder();
51  
52  	/**
53  	 * Constructor
54  	 */
55  	public DateParam() {
56  	}
57  
58  	/**
59  	 * Constructor
60  	 */
61  	public DateParam(ParamPrefixEnum thePrefix, Date theDate) {
62  		setPrefix(thePrefix);
63  		setValue(theDate);
64  	}
65  
66  	/**
67  	 * Constructor
68  	 */
69  	public DateParam(ParamPrefixEnum thePrefix, DateTimeDt theDate) {
70  		setPrefix(thePrefix);
71  		myValue.setValueAsString(theDate != null ? theDate.getValueAsString() : null);
72  	}
73  
74  	/**
75  	 * Constructor
76  	 */
77  	public DateParam(ParamPrefixEnum thePrefix, IPrimitiveType<Date> theDate) {
78  		setPrefix(thePrefix);
79  		myValue.setValueAsString(theDate != null ? theDate.getValueAsString() : null);
80  	}
81  
82  	/**
83  	 * Constructor
84  	 */
85  	public DateParam(ParamPrefixEnum thePrefix, long theDate) {
86  		ValidateUtil.isGreaterThan(theDate, 0, "theDate must not be 0 or negative");
87  		setPrefix(thePrefix);
88  		setValue(new Date(theDate));
89  	}
90  
91  	/**
92  	 * Constructor
93  	 */
94  	public DateParam(ParamPrefixEnum thePrefix, String theDate) {
95  		setPrefix(thePrefix);
96  		setValueAsString(theDate);
97  	}
98  
99  
100 	/**
101 	 * Constructor which takes a complete [qualifier]{date} string.
102 	 * 
103 	 * @param theString
104 	 *           The string
105 	 */
106 	public DateParam(String theString) {
107 		setValueAsQueryToken(null, null, null, theString);
108 	}
109 
110 	@Override
111 	String doGetQueryParameterQualifier() {
112 		return null;
113 	}
114 
115 	@Override
116 	String doGetValueAsQueryToken(FhirContext theContext) {
117 		StringBuilder b = new StringBuilder();
118 		if (getPrefix() != null) {
119 			b.append(ParameterUtil.escapeWithDefault(getPrefix().getValue()));
120 		}
121 		
122 		if (myValue != null) {
123 			b.append(ParameterUtil.escapeWithDefault(myValue.getValueAsString()));
124 		}
125 
126 		return b.toString();
127 	}
128 
129 	@Override
130 	void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) {
131 		setValueAsString(theValue);
132 	}
133 
134 	public TemporalPrecisionEnum getPrecision() {
135 		if (myValue != null) {
136 			return myValue.getPrecision();
137 		}
138 		return null;
139 	}
140 
141 	public Date getValue() {
142 		if (myValue != null) {
143 			return myValue.getValue();
144 		}
145 		return null;
146 	}
147 
148 	public DateTimeDt getValueAsDateTimeDt() {
149 		if (myValue == null) {
150 			return null;
151 		}
152 		return new DateTimeDt(myValue.getValue());
153 	}
154 
155 	public InstantDt getValueAsInstantDt() {
156 		if (myValue == null) {
157 			return null;
158 		}
159 		return new InstantDt(myValue.getValue());
160 	}
161 
162 	public String getValueAsString() {
163 		if (myValue != null) {
164 			return myValue.getValueAsString();
165 		}
166 		return null;
167 	}
168 
169 	@Override
170 	public List<DateParam> getValuesAsQueryTokens() {
171 		return Collections.singletonList(this);
172 	}
173 
174 	/**
175 	 * Returns <code>true</code> if no date/time is specified. Note that this method does not check the comparator, so a
176 	 * QualifiedDateParam with only a comparator and no date/time is considered empty.
177 	 */
178 	public boolean isEmpty() {
179 		return myValue.isEmpty();
180 	}
181 
182 	/**
183 	 * Sets the value of the param to the given date (sets to the {@link TemporalPrecisionEnum#MILLI millisecond}
184 	 * precision, and will be encoded using the system local time zone).
185 	 */
186 	public DateParam setValue(Date theValue) {
187 		myValue.setValue(theValue, TemporalPrecisionEnum.MILLI);
188 		return this;
189 	}
190 
191 	/**
192 	 * Sets the value using a FHIR Date type, such as a {@link DateDt}, or a DateTimeType.
193 	 */
194 	public void setValue(IPrimitiveType<Date> theValue) {
195 		if (theValue != null) {
196 			myValue.setValueAsString(theValue.getValueAsString());
197 		} else {
198 			myValue.setValue(null);
199 		}
200 	}
201 
202 	/**
203 	 * Accepts values with or without a prefix (e.g. <code>gt2011-01-01</code> and <code>2011-01-01</code>).
204 	 * If no prefix is provided in the given value, the {@link #getPrefix() existing prefix} is preserved
205 	 */
206 	public void setValueAsString(String theDate) {
207 		if (isNotBlank(theDate)) {
208 			ParamPrefixEnum existingPrefix = getPrefix();
209 			myValue.setValueAsString(super.extractPrefixAndReturnRest(theDate));
210 			if (getPrefix() == null) {
211 				setPrefix(existingPrefix);
212 			}
213 		} else {
214 			myValue.setValue(null);
215 		}
216 	}
217 
218 	@Override
219 	public void  setValuesAsQueryTokens(FhirContext theContext, String theParamName, QualifiedParamList theParameters) {
220 		setMissing(null);
221 		setPrefix(null);
222 		setValueAsString(null);
223 		
224 		if (theParameters.size() == 1) {
225 			setValueAsString(theParameters.get(0));
226 		} else if (theParameters.size() > 1) {
227 			throw new InvalidRequestException("This server does not support multi-valued dates for this parameter: " + theParameters);
228 		}
229 		
230 	}
231 
232 	@Override
233 	public boolean equals(Object obj) {
234 		if (obj == this) {
235 			return true;
236 		}
237 		if (!(obj instanceof DateParam)) {
238 			return false;
239 		}
240 		DateParam other = (DateParam) obj;
241 		return	Objects.equals(getValue(), other.getValue()) &&
242 					Objects.equals(getPrefix(), other.getPrefix());
243 	}
244 
245 	@Override
246 	public int hashCode() {
247 		return Objects.hash(getValue(), getPrefix());
248 	}
249 
250 	@Override
251 	public String toString() {
252 		ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
253 		b.append("prefix", getPrefix());
254 		b.append("value", getValueAsString());
255 		return b.build();
256 	}
257 
258 	public static class DateParamDateTimeHolder extends BaseDateTimeDt {
259 
260 		/**
261 		 * Constructor
262 		 */
263 		public DateParamDateTimeHolder() {
264 			super();
265 		}
266 
267 		@Override
268 		protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() {
269 			return TemporalPrecisionEnum.SECOND;
270 		}
271 
272 		@Override
273 		protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) {
274 			return true;
275 		}
276 	}
277 }