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