001/* 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2024 Smile CDR, Inc. 006 * %% 007 * Licensed under the Apache License, Version 2.0 (the "License"); 008 * you may not use this file except in compliance with the License. 009 * You may obtain a copy of the License at 010 * 011 * http://www.apache.org/licenses/LICENSE-2.0 012 * 013 * Unless required by applicable law or agreed to in writing, software 014 * distributed under the License is distributed on an "AS IS" BASIS, 015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 016 * See the License for the specific language governing permissions and 017 * limitations under the License. 018 * #L% 019 */ 020package ca.uhn.fhir.rest.param; 021 022import ca.uhn.fhir.context.FhirContext; 023import ca.uhn.fhir.i18n.Msg; 024import ca.uhn.fhir.model.base.composite.BaseCodingDt; 025import ca.uhn.fhir.model.base.composite.BaseIdentifierDt; 026import ca.uhn.fhir.model.primitive.UriDt; 027import ca.uhn.fhir.rest.api.Constants; 028import org.apache.commons.lang3.StringUtils; 029import org.apache.commons.lang3.builder.EqualsBuilder; 030import org.apache.commons.lang3.builder.HashCodeBuilder; 031import org.apache.commons.lang3.builder.ToStringBuilder; 032import org.apache.commons.lang3.builder.ToStringStyle; 033import org.hl7.fhir.instance.model.api.IBaseCoding; 034 035import static org.apache.commons.lang3.StringUtils.defaultString; 036import static org.apache.commons.lang3.StringUtils.isNotBlank; 037 038public class TokenParam extends BaseParam /*implements IQueryParameterType*/ { 039 040 private TokenParamModifier myModifier; 041 private String mySystem; 042 private String myValue; 043 044 private Boolean myMdmExpand; 045 046 /** 047 * Constructor 048 */ 049 public TokenParam() { 050 super(); 051 } 052 053 /** 054 * Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and 055 * {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a parameter 056 * 057 * @param theCodingDt The coding 058 */ 059 public TokenParam(BaseCodingDt theCodingDt) { 060 this( 061 toSystemValue(theCodingDt.getSystemElement()), 062 theCodingDt.getCodeElement().getValue()); 063 } 064 065 /** 066 * Constructor which copies the {@link BaseIdentifierDt#getSystemElement() system} and 067 * {@link BaseIdentifierDt#getValueElement() value} from a {@link BaseIdentifierDt} instance and adds it as a 068 * parameter 069 * 070 * @param theIdentifierDt The identifier 071 */ 072 public TokenParam(BaseIdentifierDt theIdentifierDt) { 073 this( 074 toSystemValue(theIdentifierDt.getSystemElement()), 075 theIdentifierDt.getValueElement().getValue()); 076 } 077 078 /** 079 * Construct a {@link TokenParam} from the {@link IBaseCoding#getSystem()} () system} and 080 * {@link IBaseCoding#getCode()} () code} of a {@link IBaseCoding} instance. 081 * 082 * @param theCoding The coding 083 */ 084 public TokenParam(IBaseCoding theCoding) { 085 this(theCoding.getSystem(), theCoding.getCode()); 086 } 087 088 public TokenParam(String theSystem, String theValue) { 089 setSystem(theSystem); 090 setValue(theValue); 091 } 092 093 public TokenParam(String theSystem, String theValue, boolean theText) { 094 if (theText && isNotBlank(theSystem)) { 095 throw new IllegalArgumentException( 096 Msg.code(1938) 097 + "theSystem can not be non-blank if theText is true (:text searches do not include a system). In other words, set the first parameter to null for a text search"); 098 } 099 setSystem(theSystem); 100 setValue(theValue); 101 setText(theText); 102 } 103 104 /** 105 * Constructor that takes a code but no system 106 */ 107 public TokenParam(String theCode) { 108 this(null, theCode); 109 } 110 111 public boolean isMdmExpand() { 112 return myMdmExpand != null && myMdmExpand; 113 } 114 115 public TokenParam setMdmExpand(boolean theMdmExpand) { 116 myMdmExpand = theMdmExpand; 117 return this; 118 } 119 120 @Override 121 String doGetQueryParameterQualifier() { 122 if (getModifier() != null) { 123 return getModifier().getValue(); 124 } 125 return null; 126 } 127 128 /** 129 * {@inheritDoc} 130 */ 131 @Override 132 String doGetValueAsQueryToken(FhirContext theContext) { 133 if (getSystem() != null) { 134 if (getValue() != null) { 135 return ParameterUtil.escape(StringUtils.defaultString(getSystem())) 136 + '|' 137 + ParameterUtil.escape(getValue()); 138 } else { 139 return ParameterUtil.escape(StringUtils.defaultString(getSystem())) + '|'; 140 } 141 } 142 return ParameterUtil.escape(getValue()); 143 } 144 145 /** 146 * {@inheritDoc} 147 */ 148 @Override 149 void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theParameter) { 150 setModifier(null); 151 setSystem(null); 152 153 if (theQualifier != null) { 154 if (Constants.PARAMQUALIFIER_MDM.equals(theQualifier)) { 155 setMdmExpand(true); 156 } 157 158 TokenParamModifier modifier = TokenParamModifier.forValue(theQualifier); 159 setModifier(modifier); 160 161 if (modifier == TokenParamModifier.TEXT) { 162 setValue(ParameterUtil.unescape(theParameter)); 163 return; 164 } 165 } 166 167 if (theParameter == null) { 168 setValue(null); 169 } else { 170 int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|'); 171 if (barIndex != -1) { 172 setSystem(theParameter.substring(0, barIndex)); 173 setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1))); 174 } else { 175 setValue(ParameterUtil.unescape(theParameter)); 176 } 177 } 178 } 179 180 /** 181 * Returns the modifier for this token 182 */ 183 public TokenParamModifier getModifier() { 184 return myModifier; 185 } 186 187 public TokenParam setModifier(TokenParamModifier theModifier) { 188 myModifier = theModifier; 189 return this; 190 } 191 192 /** 193 * Returns the system for this token. Note that if a {@link #getModifier()} is being used, the entire value of the 194 * parameter will be placed in {@link #getValue() value} and this method will return <code>null</code>. 195 * <p 196 * Also note that this value may be <code>null</code> or <code>""</code> (empty string) and that 197 * each of these have a different meaning. When a token is passed on a URL and it has no 198 * vertical bar (often meaning "return values that match the given code in any codesystem") 199 * this method will return <code>null</code>. When a token is passed on a URL and it has 200 * a vetical bar but nothing before the bar (often meaning "return values that match the 201 * given code but that have no codesystem) this method will return <code>""</code> 202 * </p> 203 */ 204 public String getSystem() { 205 return mySystem; 206 } 207 208 public TokenParam setSystem(String theSystem) { 209 mySystem = theSystem; 210 return this; 211 } 212 213 /** 214 * Returns the value for the token (generally the value to the right of the 215 * vertical bar on the URL) 216 */ 217 public String getValue() { 218 return myValue; 219 } 220 221 public TokenParam setValue(String theValue) { 222 myValue = theValue; 223 return this; 224 } 225 226 public InternalCodingDt getValueAsCoding() { 227 return new InternalCodingDt(mySystem, myValue); 228 } 229 230 public String getValueNotNull() { 231 return defaultString(myValue); 232 } 233 234 public boolean isEmpty() { 235 return StringUtils.isBlank(mySystem) && StringUtils.isBlank(myValue) && getMissing() == null; 236 } 237 238 /** 239 * Returns true if {@link #getModifier()} returns {@link TokenParamModifier#TEXT} 240 */ 241 public boolean isText() { 242 return myModifier == TokenParamModifier.TEXT; 243 } 244 245 /** 246 * @deprecated Use {@link #setModifier(TokenParamModifier)} instead 247 */ 248 @Deprecated 249 public TokenParam setText(boolean theText) { 250 if (theText) { 251 myModifier = TokenParamModifier.TEXT; 252 } else { 253 myModifier = null; 254 } 255 return this; 256 } 257 258 @Override 259 public String toString() { 260 ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); 261 builder.append("system", defaultString(getSystem())); 262 if (myModifier != null) { 263 builder.append(":" + myModifier.getValue()); 264 } 265 builder.append("value", getValue()); 266 if (getMissing() != null) { 267 builder.append(":missing", getMissing()); 268 } 269 return builder.toString(); 270 } 271 272 @Override 273 public boolean equals(Object theO) { 274 if (this == theO) { 275 return true; 276 } 277 278 if (theO == null || getClass() != theO.getClass()) { 279 return false; 280 } 281 282 TokenParam that = (TokenParam) theO; 283 284 EqualsBuilder b = new EqualsBuilder(); 285 b.append(myModifier, that.myModifier); 286 b.append(mySystem, that.mySystem); 287 b.append(myValue, that.myValue); 288 return b.isEquals(); 289 } 290 291 @Override 292 public int hashCode() { 293 HashCodeBuilder b = new HashCodeBuilder(17, 37); 294 b.append(myModifier); 295 b.append(mySystem); 296 b.append(myValue); 297 return b.toHashCode(); 298 } 299 300 private static String toSystemValue(UriDt theSystem) { 301 return theSystem.getValueAsString(); 302 } 303}