001package ca.uhn.fhir.rest.param; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2020 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.primitive.IdDt; 025import ca.uhn.fhir.parser.DataFormatException; 026import ca.uhn.fhir.util.CoverageIgnore; 027import org.apache.commons.lang3.builder.ToStringBuilder; 028import org.apache.commons.lang3.builder.ToStringStyle; 029import org.hl7.fhir.instance.model.api.IBaseResource; 030 031import java.math.BigDecimal; 032 033import static ca.uhn.fhir.model.primitive.IdDt.isValidLong; 034import static org.apache.commons.lang3.StringUtils.*; 035 036public class ReferenceParam extends BaseParam /*implements IQueryParameterType*/ { 037 038 private String myChain; 039 private String myResourceType; 040 private String myBaseUrl; 041 private String myValue; 042 private String myIdPart; 043 044 /** 045 * Constructor 046 */ 047 public ReferenceParam() { 048 super(); 049 } 050 051 /** 052 * Constructor 053 */ 054 public ReferenceParam(String theValue) { 055 setValueAsQueryToken(null, null, null, theValue); 056 } 057 058 /** 059 * Constructor 060 */ 061 public ReferenceParam(String theChain, String theValue) { 062 setValueAsQueryToken(null, null, null, theValue); 063 setChain(theChain); 064 } 065 066 /** 067 * Constructor 068 */ 069 public ReferenceParam(String theResourceType, String theChain, String theValue) { 070 String qualifier = ""; 071 if (isNotBlank(theResourceType)) { 072 qualifier = ":" + theResourceType; 073 } 074 if (isNotBlank(theChain)) { 075 qualifier = qualifier + "." + theChain; 076 } 077 078 setValueAsQueryToken(null, null, qualifier, theValue); 079 } 080 081 @Override 082 String doGetQueryParameterQualifier() { 083 StringBuilder b = new StringBuilder(); 084 if (isNotBlank(myChain)) { 085 if (isNotBlank(getResourceType())) { 086 b.append(':'); 087 b.append(getResourceType()); 088 } 089 b.append('.'); 090 b.append(myChain); 091 } 092 if (b.length() != 0) { 093 return b.toString(); 094 } 095 return null; 096 } 097 098 @Override 099 String doGetValueAsQueryToken(FhirContext theContext) { 100 if (isBlank(getResourceType())) { 101 return myValue; // e.g. urn:asdjd or 123 or cid:wieiuru or #1 102 } else { 103 if (isBlank(getChain()) && isNotBlank(getResourceType())) { 104 return getResourceType() + "/" + getIdPart(); 105 } 106 return myValue; 107 } 108 } 109 110 @Override 111 void doSetValueAsQueryToken(FhirContext theContext, String theParamName, String theQualifier, String theValue) { 112 String q = theQualifier; 113 if (isNotBlank(q)) { 114 if (q.startsWith(":")) { 115 int nextIdx = q.indexOf('.'); 116 if (nextIdx != -1) { 117 myChain = q.substring(nextIdx + 1); 118 myResourceType = q.substring(1, nextIdx); 119 } else { 120 myChain = null; 121 myResourceType = q.substring(1); 122 } 123 124 myValue = theValue; 125 myIdPart = theValue; 126 127 IdDt id = new IdDt(theValue); 128 if (!id.hasBaseUrl() && id.hasIdPart() && id.hasResourceType()) { 129 if (id.getResourceType().equals(myResourceType)) { 130 myIdPart = id.getIdPart(); 131 } 132 } 133 134 } else if (q.startsWith(".")) { 135 myChain = q.substring(1); 136 myResourceType = null; 137 myValue = theValue; 138 myIdPart = theValue; 139 } 140 } else { 141 myChain = null; 142 myValue = theValue; 143 IdDt id = new IdDt(theValue); 144 myResourceType = id.getResourceType(); 145 myIdPart = id.getIdPart(); 146 myBaseUrl = id.getBaseUrl(); 147 } 148 149 } 150 151 152 @CoverageIgnore 153 public String getBaseUrl() { 154 return myBaseUrl; 155 } 156 157 158 public String getChain() { 159 return myChain; 160 } 161 162 public ReferenceParam setChain(String theChain) { 163 myChain = theChain; 164 return this; 165 } 166 167 @CoverageIgnore 168 public String getIdPart() { 169 return myIdPart; 170 } 171 172 @CoverageIgnore 173 public BigDecimal getIdPartAsBigDecimal() { 174 return new IdDt(myValue).getIdPartAsBigDecimal(); 175 } 176 177 @CoverageIgnore 178 public Long getIdPartAsLong() { 179 return new IdDt(myValue).getIdPartAsLong(); 180 } 181 182 public String getResourceType() { 183 if (isNotBlank(myResourceType)) { 184 return myResourceType; 185 } 186 if (isBlank(myChain)) { 187 return new IdDt(myValue).getResourceType(); 188 } 189 return null; 190 } 191 192 public Class<? extends IBaseResource> getResourceType(FhirContext theCtx) { 193 if (isBlank(getResourceType())) { 194 return null; 195 } 196 return theCtx.getResourceDefinition(getResourceType()).getImplementingClass(); 197 } 198 199 public String getValue() { 200 return myValue; 201 } 202 203 public ReferenceParam setValue(String theValue) { 204 IdDt id = new IdDt(theValue); 205 String qualifier= null; 206 if (id.hasResourceType()) { 207 qualifier = ":" + id.getResourceType(); 208 } 209 setValueAsQueryToken(null, null, qualifier, id.getIdPart()); 210 return this; 211 } 212 213 public boolean hasResourceType() { 214 return isNotBlank(myResourceType); 215 } 216 217 @Override 218 protected boolean isSupportsChain() { 219 return true; 220 } 221 222 /** 223 * Returns a new param containing the same value as this param, but with the type copnverted 224 * to {@link DateParam}. This is useful if you are using reference parameters and want to handle 225 * chained parameters of different types in a single method. 226 * <p> 227 * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a> 228 * in the HAPI FHIR documentation for an example of how to use this method. 229 * </p> 230 */ 231 public DateParam toDateParam(FhirContext theContext) { 232 DateParam retVal = new DateParam(); 233 retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext)); 234 return retVal; 235 } 236 237 /** 238 * Returns a new param containing the same value as this param, but with the type copnverted 239 * to {@link NumberParam}. This is useful if you are using reference parameters and want to handle 240 * chained parameters of different types in a single method. 241 * <p> 242 * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a> 243 * in the HAPI FHIR documentation for an example of how to use this method. 244 * </p> 245 */ 246 public NumberParam toNumberParam(FhirContext theContext) { 247 NumberParam retVal = new NumberParam(); 248 retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext)); 249 return retVal; 250 } 251 252 /** 253 * Returns a new param containing the same value as this param, but with the type copnverted 254 * to {@link QuantityParam}. This is useful if you are using reference parameters and want to handle 255 * chained parameters of different types in a single method. 256 * <p> 257 * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a> 258 * in the HAPI FHIR documentation for an example of how to use this method. 259 * </p> 260 */ 261 public QuantityParam toQuantityParam(FhirContext theContext) { 262 QuantityParam retVal = new QuantityParam(); 263 retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext)); 264 return retVal; 265 } 266 267 @Override 268 public String toString() { 269 ToStringBuilder b = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE); 270 if (isNotBlank(myChain)) { 271 b.append("chain", myChain); 272 } 273 b.append("value", getValue()); 274 return b.build(); 275 } 276 277 /** 278 * Returns a new param containing the same value as this param, but with the type copnverted 279 * to {@link StringParam}. This is useful if you are using reference parameters and want to handle 280 * chained parameters of different types in a single method. 281 * <p> 282 * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a> 283 * in the HAPI FHIR documentation for an example of how to use this method. 284 * </p> 285 */ 286 public StringParam toStringParam(FhirContext theContext) { 287 StringParam retVal = new StringParam(); 288 retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext)); 289 return retVal; 290 } 291 292 /** 293 * Returns a new param containing the same value as this param, but with the type copnverted 294 * to {@link TokenParam}. This is useful if you are using reference parameters and want to handle 295 * chained parameters of different types in a single method. 296 * <p> 297 * See <a href="http://jamesagnew.github.io/hapi-fhir/doc_rest_operations.html#dynamic_chains">Dynamic Chains</a> 298 * in the HAPI FHIR documentation for an example of how to use this method. 299 * </p> 300 */ 301 public TokenParam toTokenParam(FhirContext theContext) { 302 TokenParam retVal = new TokenParam(); 303 retVal.setValueAsQueryToken(theContext, null, null, getValueAsQueryToken(theContext)); 304 return retVal; 305 } 306 307 public boolean isIdPartValidLong() { 308 return isValidLong(getIdPart()); 309 } 310}