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 org.apache.commons.lang3.StringUtils; 028import org.apache.commons.lang3.builder.EqualsBuilder; 029import org.apache.commons.lang3.builder.HashCodeBuilder; 030import org.apache.commons.lang3.builder.ToStringBuilder; 031import org.apache.commons.lang3.builder.ToStringStyle; 032import org.hl7.fhir.instance.model.api.IBaseCoding; 033 034import static org.apache.commons.lang3.StringUtils.defaultString; 035import static org.apache.commons.lang3.StringUtils.isNotBlank; 036 037public class TokenParam extends BaseParam /*implements IQueryParameterType*/ { 038 039 private TokenParamModifier myModifier; 040 private String mySystem; 041 private String myValue; 042 043 private Boolean myMdmExpand; 044 045 /** 046 * Constructor 047 */ 048 public TokenParam() { 049 super(); 050 } 051 052 /** 053 * Constructor which copies the {@link InternalCodingDt#getSystemElement() system} and 054 * {@link InternalCodingDt#getCodeElement() code} from a {@link InternalCodingDt} instance and adds it as a parameter 055 * 056 * @param theCodingDt The coding 057 */ 058 public TokenParam(BaseCodingDt theCodingDt) { 059 this( 060 toSystemValue(theCodingDt.getSystemElement()), 061 theCodingDt.getCodeElement().getValue()); 062 } 063 064 /** 065 * Constructor which copies the {@link BaseIdentifierDt#getSystemElement() system} and 066 * {@link BaseIdentifierDt#getValueElement() value} from a {@link BaseIdentifierDt} instance and adds it as a 067 * parameter 068 * 069 * @param theIdentifierDt The identifier 070 */ 071 public TokenParam(BaseIdentifierDt theIdentifierDt) { 072 this( 073 toSystemValue(theIdentifierDt.getSystemElement()), 074 theIdentifierDt.getValueElement().getValue()); 075 } 076 077 /** 078 * Construct a {@link TokenParam} from the {@link IBaseCoding#getSystem()} () system} and 079 * {@link IBaseCoding#getCode()} () code} of a {@link IBaseCoding} instance. 080 * 081 * @param theCoding The coding 082 */ 083 public TokenParam(IBaseCoding theCoding) { 084 this(theCoding.getSystem(), theCoding.getCode()); 085 } 086 087 public TokenParam(String theSystem, String theValue) { 088 setSystem(theSystem); 089 setValue(theValue); 090 } 091 092 public TokenParam(String theSystem, String theValue, boolean theText) { 093 if (theText && isNotBlank(theSystem)) { 094 throw new IllegalArgumentException( 095 Msg.code(1938) 096 + "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"); 097 } 098 setSystem(theSystem); 099 setValue(theValue); 100 setText(theText); 101 } 102 103 /** 104 * Constructor that takes a code but no system 105 */ 106 public TokenParam(String theCode) { 107 this(null, theCode); 108 } 109 110 public boolean isMdmExpand() { 111 return myMdmExpand != null && myMdmExpand; 112 } 113 114 public TokenParam setMdmExpand(boolean theMdmExpand) { 115 myMdmExpand = theMdmExpand; 116 return this; 117 } 118 119 @Override 120 String doGetQueryParameterQualifier() { 121 if (getModifier() != null) { 122 return getModifier().getValue(); 123 } 124 return null; 125 } 126 127 /** 128 * {@inheritDoc} 129 */ 130 @Override 131 String doGetValueAsQueryToken(FhirContext theContext) { 132 if (getSystem() != null) { 133 if (getValue() != null) { 134 return ParameterUtil.escape(StringUtils.defaultString(getSystem())) 135 + '|' 136 + ParameterUtil.escape(getValue()); 137 } else { 138 return ParameterUtil.escape(StringUtils.defaultString(getSystem())) + '|'; 139 } 140 } 141 return ParameterUtil.escape(getValue()); 142 } 143 144 /** 145 * {@inheritDoc} 146 */ 147 @Override 148 void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theParameter) { 149 setModifier(null); 150 if (theQualifier != null) { 151 TokenParamModifier modifier = TokenParamModifier.forValue(theQualifier); 152 setModifier(modifier); 153 154 if (modifier == TokenParamModifier.TEXT) { 155 setSystem(null); 156 setValue(ParameterUtil.unescape(theParameter)); 157 return; 158 } 159 } 160 161 setSystem(null); 162 if (theParameter == null) { 163 setValue(null); 164 } else { 165 int barIndex = ParameterUtil.nonEscapedIndexOf(theParameter, '|'); 166 if (barIndex != -1) { 167 setSystem(theParameter.substring(0, barIndex)); 168 setValue(ParameterUtil.unescape(theParameter.substring(barIndex + 1))); 169 } else { 170 setValue(ParameterUtil.unescape(theParameter)); 171 } 172 } 173 } 174 175 /** 176 * Returns the modifier for this token 177 */ 178 public TokenParamModifier getModifier() { 179 return myModifier; 180 } 181 182 public TokenParam setModifier(TokenParamModifier theModifier) { 183 myModifier = theModifier; 184 return this; 185 } 186 187 /** 188 * Returns the system for this token. Note that if a {@link #getModifier()} is being used, the entire value of the 189 * parameter will be placed in {@link #getValue() value} and this method will return <code>null</code>. 190 * <p 191 * Also note that this value may be <code>null</code> or <code>""</code> (empty string) and that 192 * each of these have a different meaning. When a token is passed on a URL and it has no 193 * vertical bar (often meaning "return values that match the given code in any codesystem") 194 * this method will return <code>null</code>. When a token is passed on a URL and it has 195 * a vetical bar but nothing before the bar (often meaning "return values that match the 196 * given code but that have no codesystem) this method will return <code>""</code> 197 * </p> 198 */ 199 public String getSystem() { 200 return mySystem; 201 } 202 203 public TokenParam setSystem(String theSystem) { 204 mySystem = theSystem; 205 return this; 206 } 207 208 /** 209 * Returns the value for the token (generally the value to the right of the 210 * vertical bar on the URL) 211 */ 212 public String getValue() { 213 return myValue; 214 } 215 216 public TokenParam setValue(String theValue) { 217 myValue = theValue; 218 return this; 219 } 220 221 public InternalCodingDt getValueAsCoding() { 222 return new InternalCodingDt(mySystem, myValue); 223 } 224 225 public String getValueNotNull() { 226 return defaultString(myValue); 227 } 228 229 public boolean isEmpty() { 230 return StringUtils.isBlank(mySystem) && StringUtils.isBlank(myValue) && getMissing() == null; 231 } 232 233 /** 234 * Returns true if {@link #getModifier()} returns {@link TokenParamModifier#TEXT} 235 */ 236 public boolean isText() { 237 return myModifier == TokenParamModifier.TEXT; 238 } 239 240 /** 241 * @deprecated Use {@link #setModifier(TokenParamModifier)} instead 242 */ 243 @Deprecated 244 public TokenParam setText(boolean theText) { 245 if (theText) { 246 myModifier = TokenParamModifier.TEXT; 247 } else { 248 myModifier = null; 249 } 250 return this; 251 } 252 253 @Override 254 public String toString() { 255 ToStringBuilder builder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); 256 builder.append("system", defaultString(getSystem())); 257 if (myModifier != null) { 258 builder.append(":" + myModifier.getValue()); 259 } 260 builder.append("value", getValue()); 261 if (getMissing() != null) { 262 builder.append(":missing", getMissing()); 263 } 264 return builder.toString(); 265 } 266 267 @Override 268 public boolean equals(Object theO) { 269 if (this == theO) { 270 return true; 271 } 272 273 if (theO == null || getClass() != theO.getClass()) { 274 return false; 275 } 276 277 TokenParam that = (TokenParam) theO; 278 279 EqualsBuilder b = new EqualsBuilder(); 280 b.append(myModifier, that.myModifier); 281 b.append(mySystem, that.mySystem); 282 b.append(myValue, that.myValue); 283 return b.isEquals(); 284 } 285 286 @Override 287 public int hashCode() { 288 HashCodeBuilder b = new HashCodeBuilder(17, 37); 289 b.append(myModifier); 290 b.append(mySystem); 291 b.append(myValue); 292 return b.toHashCode(); 293 } 294 295 private static String toSystemValue(UriDt theSystem) { 296 return theSystem.getValueAsString(); 297 } 298}