001package ca.uhn.fhir.rest.param; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2018 University Health Network 008 * %% 009 * Licensed under the Apache License, Version 2.0 (the "License"); 010 * you may not use this file except in compliance with the License. 011 * You may obtain a copy of the License at 012 * 013 * http://www.apache.org/licenses/LICENSE-2.0 014 * 015 * Unless required by applicable law or agreed to in writing, software 016 * distributed under the License is distributed on an "AS IS" BASIS, 017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 018 * See the License for the specific language governing permissions and 019 * limitations under the License. 020 * #L% 021 */ 022 023import ca.uhn.fhir.context.FhirContext; 024import ca.uhn.fhir.model.api.IQueryParameterOr; 025import ca.uhn.fhir.model.api.TemporalPrecisionEnum; 026import ca.uhn.fhir.model.api.annotation.SimpleSetter; 027import ca.uhn.fhir.model.primitive.BaseDateTimeDt; 028import ca.uhn.fhir.model.primitive.DateDt; 029import ca.uhn.fhir.model.primitive.DateTimeDt; 030import ca.uhn.fhir.model.primitive.InstantDt; 031import ca.uhn.fhir.parser.DataFormatException; 032import ca.uhn.fhir.rest.api.QualifiedParamList; 033import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; 034import ca.uhn.fhir.util.ObjectUtil; 035import ca.uhn.fhir.util.ValidateUtil; 036import org.apache.commons.lang3.ObjectUtils; 037import org.apache.commons.lang3.builder.ToStringBuilder; 038import org.apache.commons.lang3.builder.ToStringStyle; 039import org.apache.commons.lang3.time.DateUtils; 040import org.hl7.fhir.instance.model.api.IPrimitiveType; 041 042import java.util.*; 043 044import static org.apache.commons.lang3.StringUtils.isNotBlank; 045 046public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQueryParameterType , */IQueryParameterOr<DateParam> { 047 048 private static final long serialVersionUID = 1L; 049 050 private final DateParamDateTimeHolder myValue = new DateParamDateTimeHolder(); 051 052 /** 053 * Constructor 054 */ 055 public DateParam() { 056 } 057 058 /** 059 * Constructor 060 */ 061 public DateParam(ParamPrefixEnum thePrefix, Date theDate) { 062 setPrefix(thePrefix); 063 setValue(theDate); 064 } 065 066 /** 067 * Constructor 068 */ 069 public DateParam(ParamPrefixEnum thePrefix, DateTimeDt theDate) { 070 setPrefix(thePrefix); 071 myValue.setValueAsString(theDate != null ? theDate.getValueAsString() : null); 072 } 073 074 /** 075 * Constructor 076 */ 077 public DateParam(ParamPrefixEnum thePrefix, IPrimitiveType<Date> theDate) { 078 setPrefix(thePrefix); 079 myValue.setValueAsString(theDate != null ? theDate.getValueAsString() : null); 080 } 081 082 /** 083 * Constructor 084 */ 085 public DateParam(ParamPrefixEnum thePrefix, long theDate) { 086 ValidateUtil.isGreaterThan(theDate, 0, "theDate must not be 0 or negative"); 087 setPrefix(thePrefix); 088 setValue(new Date(theDate)); 089 } 090 091 /** 092 * Constructor 093 */ 094 public DateParam(ParamPrefixEnum thePrefix, String theDate) { 095 setPrefix(thePrefix); 096 setValueAsString(theDate); 097 } 098 099 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 class DateParamDateTimeHolder extends BaseDateTimeDt { 259 @Override 260 protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() { 261 return TemporalPrecisionEnum.SECOND; 262 } 263 264 @Override 265 protected boolean isPrecisionAllowed(TemporalPrecisionEnum thePrecision) { 266 return true; 267 } 268 } 269}