
001/* 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2025 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.util; 021 022import ca.uhn.fhir.context.BaseRuntimeChildDefinition; 023import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition; 024import ca.uhn.fhir.context.BaseRuntimeElementDefinition; 025import ca.uhn.fhir.context.FhirContext; 026import ca.uhn.fhir.context.RuntimeResourceDefinition; 027import ca.uhn.fhir.i18n.Msg; 028import ca.uhn.fhir.model.api.annotation.Description; 029import ca.uhn.fhir.model.primitive.StringDt; 030import jakarta.annotation.Nullable; 031import org.apache.commons.lang3.Validate; 032import org.hl7.fhir.instance.model.api.IBase; 033import org.hl7.fhir.instance.model.api.IBaseDatatype; 034import org.hl7.fhir.instance.model.api.IBaseParameters; 035import org.hl7.fhir.instance.model.api.IBaseReference; 036import org.hl7.fhir.instance.model.api.IBaseResource; 037import org.hl7.fhir.instance.model.api.IPrimitiveType; 038 039import java.lang.annotation.Annotation; 040import java.lang.reflect.AnnotatedElement; 041import java.math.BigDecimal; 042import java.util.ArrayList; 043import java.util.Arrays; 044import java.util.Collection; 045import java.util.List; 046import java.util.Objects; 047import java.util.Optional; 048import java.util.function.Function; 049import java.util.stream.Collectors; 050 051import static org.apache.commons.lang3.StringUtils.defaultIfBlank; 052import static org.apache.commons.lang3.StringUtils.isBlank; 053 054/** 055 * Utilities for dealing with parameters resources in a version independent way 056 */ 057public class ParametersUtil { 058 059 private ParametersUtil() {} 060 061 public static Optional<String> getNamedParameterValueAsString( 062 FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 063 Function<IPrimitiveType<?>, String> mapper = t -> defaultIfBlank(t.getValueAsString(), null); 064 return extractNamedParameterValues(theCtx, theParameters, theParameterName, mapper).stream() 065 .findFirst(); 066 } 067 068 public static List<String> getNamedParameterValuesAsString( 069 FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 070 Function<IPrimitiveType<?>, String> mapper = t -> defaultIfBlank(t.getValueAsString(), null); 071 return extractNamedParameterValues(theCtx, theParameters, theParameterName, mapper); 072 } 073 074 public static List<Integer> getNamedParameterValuesAsInteger( 075 FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 076 Function<IPrimitiveType<?>, Integer> mapper = t -> (Integer) t.getValue(); 077 return extractNamedParameterValues(theCtx, theParameters, theParameterName, mapper); 078 } 079 080 public static Optional<Integer> getNamedParameterValueAsInteger( 081 FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 082 return getNamedParameterValuesAsInteger(theCtx, theParameters, theParameterName).stream() 083 .findFirst(); 084 } 085 086 /** 087 * Returns the resource within a parameter. 088 * @param theCtx thr FHIR context 089 * @param theParameters the parameters instance where to look for the resource 090 * @param theParameterName the parameter name 091 * @return the resource 092 */ 093 public static Optional<IBaseResource> getNamedParameterResource( 094 FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 095 096 List<IBase> namedParameters = getNamedParameters(theCtx, theParameters, theParameterName); 097 return collectChildrenByNameAndType(theCtx, namedParameters, "resource", IBaseResource.class).stream() 098 .findFirst(); 099 } 100 101 private static <T extends IBase> List<T> collectChildrenByNameAndType( 102 FhirContext theCtx, List<IBase> theNamedParameters, String theChildName, Class<T> childrenType) { 103 104 List<T> collectedChildren = new ArrayList<>(); 105 106 for (IBase nextParameter : theNamedParameters) { 107 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = 108 (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass()); 109 BaseRuntimeChildDefinition resourceChild = nextParameterDef.getChildByName(theChildName); 110 List<IBase> resourceValues = resourceChild.getAccessor().getValues(nextParameter); 111 resourceValues.stream() 112 .filter(childrenType::isInstance) 113 .map(childrenType::cast) 114 .forEach(collectedChildren::add); 115 } 116 117 return collectedChildren; 118 } 119 120 /** 121 * Returns the list of parameter reference. 122 * @param theCtx thr FHIR context 123 * @param theParameters the parameters instance where to look for the reference 124 * @param theParameterName the parameter name 125 * @return the reference list 126 */ 127 public static List<IBaseReference> getNamedParameterReferences( 128 FhirContext theCtx, IBaseParameters theParameters, String theParameterName) { 129 List<IBase> namedParameters = getNamedParameters(theCtx, theParameters, theParameterName); 130 return collectChildrenByNameAndType(theCtx, namedParameters, "valueReference", IBaseReference.class); 131 } 132 133 public static Optional<IBase> getNamedParameter( 134 FhirContext theCtx, IBaseResource theParameters, String theParameterName) { 135 return getNamedParameters(theCtx, theParameters, theParameterName).stream() 136 .findFirst(); 137 } 138 139 public static List<IBase> getNamedParameters( 140 FhirContext theCtx, IBaseResource theParameters, String theParameterName) { 141 Validate.notNull(theParameters, "theParameters must not be null"); 142 RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass()); 143 BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter"); 144 List<IBase> parameterReps = parameterChild.getAccessor().getValues(theParameters); 145 146 return parameterReps.stream() 147 .filter(param -> { 148 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = 149 (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(param.getClass()); 150 BaseRuntimeChildDefinition nameChild = nextParameterDef.getChildByName("name"); 151 List<IBase> nameValues = nameChild.getAccessor().getValues(param); 152 Optional<? extends IPrimitiveType<?>> nameValue = nameValues.stream() 153 .filter(t -> t instanceof IPrimitiveType<?>) 154 .map(t -> ((IPrimitiveType<?>) t)) 155 .findFirst(); 156 return nameValue.isPresent() 157 && theParameterName.equals(nameValue.get().getValueAsString()); 158 }) 159 .collect(Collectors.toList()); 160 } 161 162 public static Optional<IBase> getParameterPart(FhirContext theCtx, IBase theParameter, String theParameterName) { 163 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = 164 (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(theParameter.getClass()); 165 BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("part"); 166 List<IBase> parts = valueChild.getAccessor().getValues(theParameter); 167 168 for (IBase nextPart : parts) { 169 Optional<IPrimitiveType> name = theCtx.newTerser().getSingleValue(nextPart, "name", IPrimitiveType.class); 170 if (name.isPresent() && theParameterName.equals(name.get().getValueAsString())) { 171 return Optional.of(nextPart); 172 } 173 } 174 175 return Optional.empty(); 176 } 177 178 public static Optional<IBase> getParameterPartValue( 179 FhirContext theCtx, IBase theParameter, String theParameterName) { 180 Optional<IBase> part = getParameterPart(theCtx, theParameter, theParameterName); 181 if (part.isPresent()) { 182 return theCtx.newTerser().getSingleValue(part.get(), "value[x]", IBase.class); 183 } else { 184 return Optional.empty(); 185 } 186 } 187 188 public static String getParameterPartValueAsString( 189 FhirContext theCtx, IBase theParameter, String theParameterName) { 190 return getParameterPartValue(theCtx, theParameter, theParameterName) 191 .map(t -> (IPrimitiveType<?>) t) 192 .map(IPrimitiveType::getValueAsString) 193 .orElse(null); 194 } 195 196 public static Optional<Integer> getParameterPartValueAsInteger( 197 FhirContext theCtx, IBase theParameter, String theParameterName) { 198 return getParameterPartValue(theCtx, theParameter, theParameterName) 199 .filter(t -> IPrimitiveType.class.isAssignableFrom(t.getClass())) 200 .map(t -> (IPrimitiveType<?>) t) 201 .map(IPrimitiveType::getValue) 202 .filter(t -> Integer.class.isAssignableFrom(t.getClass())) 203 .map(t -> (Integer) t); 204 } 205 206 private static <T> List<T> extractNamedParameterValues( 207 FhirContext theCtx, 208 IBaseParameters theParameters, 209 String theParameterName, 210 Function<IPrimitiveType<?>, T> theMapper) { 211 List<T> retVal = new ArrayList<>(); 212 213 List<IBase> namedParameters = getNamedParameters(theCtx, theParameters, theParameterName); 214 for (IBase nextParameter : namedParameters) { 215 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = 216 (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass()); 217 BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("value[x]"); 218 List<IBase> valueValues = valueChild.getAccessor().getValues(nextParameter); 219 valueValues.stream() 220 .filter(t -> t instanceof IPrimitiveType<?>) 221 .map(t -> ((IPrimitiveType<?>) t)) 222 .map(theMapper) 223 .filter(Objects::nonNull) 224 .forEach(retVal::add); 225 } 226 return retVal; 227 } 228 229 private static void addClientParameter( 230 FhirContext theContext, 231 Object theValue, 232 IBaseResource theTargetResource, 233 BaseRuntimeChildDefinition paramChild, 234 BaseRuntimeElementCompositeDefinition<?> paramChildElem, 235 String theName) { 236 Validate.notNull(theValue, "theValue must not be null"); 237 238 if (theValue instanceof IBaseResource) { 239 IBase parameter = 240 createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName); 241 paramChildElem.getChildByName("resource").getMutator().addValue(parameter, (IBaseResource) theValue); 242 } else if (theValue instanceof IBaseDatatype) { 243 IBase parameter = 244 createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName); 245 paramChildElem.getChildByName("value[x]").getMutator().addValue(parameter, (IBaseDatatype) theValue); 246 } else if (theValue instanceof Collection<?> collection) { 247 for (Object next : collection) { 248 addClientParameter(theContext, next, theTargetResource, paramChild, paramChildElem, theName); 249 } 250 } else { 251 throw new IllegalArgumentException(Msg.code(1806) + "Don't know how to handle value of type " 252 + theValue.getClass() + " for parameter " + theName); 253 } 254 } 255 256 /** 257 * Add a parameter value to a Parameters resource 258 * 259 * @param theContext The FhirContext 260 * @param theParameters The Parameters resource 261 * @param theName The parameter name 262 * @param theValue The parameter value (can be a {@link IBaseResource resource} or a {@link IBaseDatatype datatype}) 263 */ 264 public static void addParameterToParameters( 265 FhirContext theContext, IBaseParameters theParameters, String theName, Object theValue) { 266 RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters); 267 BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter"); 268 BaseRuntimeElementCompositeDefinition<?> paramChildElem = 269 (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter"); 270 271 addClientParameter(theContext, theValue, theParameters, paramChild, paramChildElem, theName); 272 } 273 274 /** 275 * Add a parameter value to a Parameters resource 276 * 277 * @param theContext The FhirContext 278 * @param theParameters The Parameters resource 279 * @param theName The parameter name 280 * @param thePrimitiveDatatype The datatype, e.g. "string", or "uri" 281 * @param theValue The value 282 */ 283 public static void addParameterToParameters( 284 FhirContext theContext, 285 IBaseParameters theParameters, 286 String theName, 287 String thePrimitiveDatatype, 288 String theValue) { 289 Validate.notBlank(thePrimitiveDatatype, "thePrimitiveDatatype must not be null or empty"); 290 291 BaseRuntimeElementDefinition<?> datatypeDef = theContext.getElementDefinition(thePrimitiveDatatype); 292 assert datatypeDef != null; 293 IPrimitiveType<?> value = (IPrimitiveType<?>) datatypeDef.newInstance(); 294 value.setValueAsString(theValue); 295 296 addParameterToParameters(theContext, theParameters, theName, value); 297 } 298 299 private static IBase createParameterRepetition( 300 FhirContext theContext, 301 IBase theTargetResource, 302 BaseRuntimeChildDefinition paramChild, 303 BaseRuntimeElementCompositeDefinition<?> paramChildElem, 304 String theName) { 305 IBase parameter = paramChildElem.newInstance(); 306 paramChild.getMutator().addValue(theTargetResource, parameter); 307 IPrimitiveType<?> value; 308 value = createString(theContext, theName); 309 paramChildElem.getChildByName("name").getMutator().addValue(parameter, value); 310 return parameter; 311 } 312 313 public static IPrimitiveType<?> createString(FhirContext theContext, String theValue) { 314 IPrimitiveType<?> value; 315 if (theContext.getVersion().getVersion().isRi()) { 316 value = (IPrimitiveType<?>) Objects.requireNonNull(theContext.getElementDefinition("string")) 317 .newInstance(theValue); 318 } else { 319 value = new StringDt(theValue); 320 } 321 return value; 322 } 323 324 public static IPrimitiveType<?> createUri(FhirContext theContext, String theValue) { 325 return (IPrimitiveType<?>) 326 Objects.requireNonNull(theContext.getElementDefinition("uri")).newInstance(theValue); 327 } 328 329 public static IPrimitiveType<?> createCode(FhirContext theContext, String theValue) { 330 return (IPrimitiveType<?>) 331 Objects.requireNonNull(theContext.getElementDefinition("code")).newInstance(theValue); 332 } 333 334 public static IBaseParameters newInstance(FhirContext theContext) { 335 Validate.notNull(theContext, "theContext must not be null"); 336 return (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance(); 337 } 338 339 public static void addParameterToParametersBoolean( 340 FhirContext theCtx, IBaseParameters theParameters, String theName, boolean theValue) { 341 addParameterToParameters(theCtx, theParameters, theName, theCtx.newPrimitiveBoolean(theValue)); 342 } 343 344 @SuppressWarnings("unchecked") 345 public static void addParameterToParametersCode( 346 FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) { 347 IPrimitiveType<String> value = (IPrimitiveType<String>) 348 Objects.requireNonNull(theCtx.getElementDefinition("code")).newInstance(); 349 value.setValue(theValue); 350 addParameterToParameters(theCtx, theParameters, theName, value); 351 } 352 353 @SuppressWarnings("unchecked") 354 public static void addParameterToParametersInteger( 355 FhirContext theCtx, IBaseParameters theParameters, String theName, int theValue) { 356 IPrimitiveType<Integer> count = (IPrimitiveType<Integer>) 357 Objects.requireNonNull(theCtx.getElementDefinition("integer")).newInstance(); 358 count.setValue(theValue); 359 addParameterToParameters(theCtx, theParameters, theName, count); 360 } 361 362 public static void addParameterToParametersLong( 363 FhirContext theCtx, IBaseParameters theParameters, String theName, long theValue) { 364 addParameterToParametersDecimal(theCtx, theParameters, theName, BigDecimal.valueOf(theValue)); 365 } 366 367 public static void addParameterToParametersDecimal( 368 FhirContext theCtx, IBaseParameters theParameters, String theName, BigDecimal theValue) { 369 IPrimitiveType<BigDecimal> count = (IPrimitiveType<BigDecimal>) 370 Objects.requireNonNull(theCtx.getElementDefinition("decimal")).newInstance(); 371 count.setValue(theValue); 372 addParameterToParameters(theCtx, theParameters, theName, count); 373 } 374 375 public static void addParameterToParametersReference( 376 FhirContext theCtx, IBaseParameters theParameters, String theName, String theReference) { 377 IBaseReference target = (IBaseReference) 378 Objects.requireNonNull(theCtx.getElementDefinition("reference")).newInstance(); 379 target.setReference(theReference); 380 addParameterToParameters(theCtx, theParameters, theName, target); 381 } 382 383 @SuppressWarnings("unchecked") 384 public static void addParameterToParametersString( 385 FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) { 386 IPrimitiveType<String> value = (IPrimitiveType<String>) 387 Objects.requireNonNull(theCtx.getElementDefinition("string")).newInstance(); 388 value.setValue(theValue); 389 addParameterToParameters(theCtx, theParameters, theName, value); 390 } 391 392 @SuppressWarnings("unchecked") 393 public static void addParameterToParametersUri( 394 FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) { 395 IPrimitiveType<String> value = (IPrimitiveType<String>) 396 Objects.requireNonNull(theCtx.getElementDefinition("uri")).newInstance(); 397 value.setValue(theValue); 398 addParameterToParameters(theCtx, theParameters, theName, value); 399 } 400 401 /** 402 * Add a parameter with no value (typically because we'll be adding sub-parameters) 403 */ 404 public static IBase addParameterToParameters( 405 FhirContext theContext, IBaseParameters theParameters, String theName) { 406 RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters); 407 BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter"); 408 BaseRuntimeElementCompositeDefinition<?> paramChildElem = 409 (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter"); 410 411 return createParameterRepetition(theContext, theParameters, paramChild, paramChildElem, theName); 412 } 413 414 public static void addPartCode(FhirContext theContext, IBase theParameter, String theName, String theCode) { 415 IPrimitiveType<String> value = (IPrimitiveType<String>) 416 Objects.requireNonNull(theContext.getElementDefinition("code")).newInstance(); 417 value.setValue(theCode); 418 419 addPart(theContext, theParameter, theName, value); 420 } 421 422 public static void addPartInteger(FhirContext theContext, IBase theParameter, String theName, Integer theInteger) { 423 IPrimitiveType<Integer> value = 424 (IPrimitiveType<Integer>) Objects.requireNonNull(theContext.getElementDefinition("integer")) 425 .newInstance(); 426 value.setValue(theInteger); 427 428 addPart(theContext, theParameter, theName, value); 429 } 430 431 public static void addPartString(FhirContext theContext, IBase theParameter, String theName, String theValue) { 432 IPrimitiveType<String> value = 433 (IPrimitiveType<String>) Objects.requireNonNull(theContext.getElementDefinition("string")) 434 .newInstance(); 435 value.setValue(theValue); 436 437 addPart(theContext, theParameter, theName, value); 438 } 439 440 public static void addPartUrl(FhirContext theContext, IBase theParameter, String theName, String theCode) { 441 IPrimitiveType<String> value = (IPrimitiveType<String>) 442 Objects.requireNonNull(theContext.getElementDefinition("url")).newInstance(); 443 value.setValue(theCode); 444 445 addPart(theContext, theParameter, theName, value); 446 } 447 448 public static void addPartBoolean(FhirContext theContext, IBase theParameter, String theName, Boolean theValue) { 449 addPart(theContext, theParameter, theName, theContext.newPrimitiveBoolean(theValue)); 450 } 451 452 public static void addPartDecimal(FhirContext theContext, IBase theParameter, String theName, Double theValue) { 453 IPrimitiveType<BigDecimal> value = (IPrimitiveType<BigDecimal>) 454 theContext.getElementDefinition("decimal").newInstance(); 455 if (theValue == null) { 456 value.setValue(null); 457 } else { 458 BigDecimal decimalValue = BigDecimal.valueOf(theValue); 459 if (decimalValue.scale() < 0) { 460 decimalValue = decimalValue.setScale(0); 461 } 462 value.setValue(decimalValue); 463 } 464 addPart(theContext, theParameter, theName, value); 465 } 466 467 public static void addPartCoding( 468 FhirContext theContext, 469 IBase theParameter, 470 String theName, 471 String theSystem, 472 String theCode, 473 String theDisplay) { 474 IBase coding = Objects.requireNonNull(theContext.getElementDefinition("coding")) 475 .newInstance(); 476 477 BaseRuntimeElementCompositeDefinition<?> codingDef = 478 (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(coding.getClass()); 479 codingDef.getChildByName("system").getMutator().addValue(coding, createUri(theContext, theSystem)); 480 codingDef.getChildByName("code").getMutator().addValue(coding, createCode(theContext, theCode)); 481 codingDef.getChildByName("display").getMutator().addValue(coding, createString(theContext, theDisplay)); 482 483 addPart(theContext, theParameter, theName, coding); 484 } 485 486 public static IBase addPart(FhirContext theContext, IBase theParameter, String theName, @Nullable IBase theValue) { 487 BaseRuntimeElementCompositeDefinition<?> def = 488 (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theParameter.getClass()); 489 BaseRuntimeChildDefinition partChild = def.getChildByName("part"); 490 491 BaseRuntimeElementCompositeDefinition<?> partChildElem = 492 (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part"); 493 IBase part = partChildElem.newInstance(); 494 partChild.getMutator().addValue(theParameter, part); 495 496 IPrimitiveType<String> name = (IPrimitiveType<String>) 497 theContext.getElementDefinition("string").newInstance(); 498 name.setValue(theName); 499 partChildElem.getChildByName("name").getMutator().addValue(part, name); 500 501 if (theValue != null) { 502 if (theValue instanceof IBaseResource) { 503 partChildElem.getChildByName("resource").getMutator().addValue(part, theValue); 504 } else { 505 partChildElem.getChildByName("value[x]").getMutator().addValue(part, theValue); 506 } 507 } 508 return part; 509 } 510 511 public static IBase createPart(FhirContext theContext, IBase thePart, String theName) { 512 BaseRuntimeElementCompositeDefinition<?> def = 513 (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(thePart.getClass()); 514 BaseRuntimeChildDefinition partChild = def.getChildByName("part"); 515 516 BaseRuntimeElementCompositeDefinition<?> partChildElem = 517 (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part"); 518 519 return createParameterRepetition(theContext, thePart, partChild, partChildElem, theName); 520 } 521 522 public static void addPartResource( 523 FhirContext theContext, IBase theParameter, String theName, IBaseResource theValue) { 524 BaseRuntimeElementCompositeDefinition<?> def = 525 (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theParameter.getClass()); 526 BaseRuntimeChildDefinition partChild = def.getChildByName("part"); 527 528 BaseRuntimeElementCompositeDefinition<?> partChildElem = 529 (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part"); 530 IBase part = partChildElem.newInstance(); 531 partChild.getMutator().addValue(theParameter, part); 532 533 IPrimitiveType<String> name = (IPrimitiveType<String>) 534 theContext.getElementDefinition("string").newInstance(); 535 name.setValue(theName); 536 partChildElem.getChildByName("name").getMutator().addValue(part, name); 537 538 partChildElem.getChildByName("resource").getMutator().addValue(part, theValue); 539 } 540 541 public static List<String> getNamedParameterPartAsString( 542 FhirContext theCtx, IBaseParameters theParameters, String thePartName, String theParameterName) { 543 return extractNamedParameterPartsAsString(theCtx, theParameters, thePartName, theParameterName); 544 } 545 546 // TODO KHS need to consolidate duplicated functionality that came in from different branches 547 private static List<String> extractNamedParameterPartsAsString( 548 FhirContext theCtx, IBaseParameters theParameters, String thePartName, String theParameterName) { 549 List<IBase> parameterReps = getParameterReps(theCtx, theParameters); 550 551 List<String> retVal = new ArrayList<>(); 552 553 for (IBase nextParameter : parameterReps) { 554 BaseRuntimeElementCompositeDefinition<?> nextParameterDef = 555 (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass()); 556 Optional<? extends IPrimitiveType<?>> nameValue = getNameValue(nextParameter, nextParameterDef); 557 if (nameValue.isEmpty() || !thePartName.equals(nameValue.get().getValueAsString())) { 558 continue; 559 } 560 561 BaseRuntimeChildDefinition partChild = nextParameterDef.getChildByName("part"); 562 List<IBase> partValues = partChild.getAccessor().getValues(nextParameter); 563 for (IBase partValue : partValues) { 564 BaseRuntimeElementCompositeDefinition<?> partParameterDef = 565 (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(partValue.getClass()); 566 Optional<? extends IPrimitiveType<?>> partNameValue = getNameValue(partValue, partParameterDef); 567 if (partNameValue.isEmpty() 568 || !theParameterName.equals(partNameValue.get().getValueAsString())) { 569 continue; 570 } 571 BaseRuntimeChildDefinition valueChild = partParameterDef.getChildByName("value[x]"); 572 List<IBase> valueValues = valueChild.getAccessor().getValues(partValue); 573 valueValues.stream() 574 .filter(t -> t instanceof IPrimitiveType<?>) 575 .map(t -> ((IPrimitiveType<String>) t)) 576 .map(t -> defaultIfBlank(t.getValueAsString(), null)) 577 .filter(Objects::nonNull) 578 .forEach(retVal::add); 579 } 580 } 581 return retVal; 582 } 583 584 private static List<IBase> getParameterReps(FhirContext theCtx, IBaseParameters theParameters) { 585 Validate.notNull(theParameters, "theParameters must not be null"); 586 RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass()); 587 BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter"); 588 return parameterChild.getAccessor().getValues(theParameters); 589 } 590 591 private static Optional<? extends IPrimitiveType<?>> getNameValue( 592 IBase nextParameter, BaseRuntimeElementCompositeDefinition<?> theNextParameterDef) { 593 BaseRuntimeChildDefinition nameChild = theNextParameterDef.getChildByName("name"); 594 List<IBase> nameValues = nameChild.getAccessor().getValues(nextParameter); 595 return nameValues.stream() 596 .filter(t -> t instanceof IPrimitiveType<?>) 597 .map(t -> ((IPrimitiveType<?>) t)) 598 .findFirst(); 599 } 600 601 @Nullable 602 public static String extractDescription(AnnotatedElement theType) { 603 Description description = theType.getAnnotation(Description.class); 604 if (description != null) { 605 return extractDescription(description); 606 } else { 607 return null; 608 } 609 } 610 611 @Nullable 612 public static String extractDescription(Description desc) { 613 String description = desc.value(); 614 if (isBlank(description)) { 615 description = desc.formalDefinition(); 616 } 617 if (isBlank(description)) { 618 description = desc.shortDefinition(); 619 } 620 return defaultIfBlank(description, null); 621 } 622 623 @Nullable 624 public static String extractShortDefinition(AnnotatedElement theType) { 625 Description description = theType.getAnnotation(Description.class); 626 if (description != null) { 627 return defaultIfBlank(description.shortDefinition(), null); 628 } else { 629 return null; 630 } 631 } 632 633 public static String extractDescription(Annotation[] theParameterAnnotations) { 634 for (Annotation next : theParameterAnnotations) { 635 if (next instanceof Description) { 636 return extractDescription((Description) next); 637 } 638 } 639 return null; 640 } 641 642 public static List<String> extractExamples(Annotation[] theParameterAnnotations) { 643 ArrayList<String> retVal = null; 644 for (Annotation next : theParameterAnnotations) { 645 if (next instanceof Description) { 646 String[] examples = ((Description) next).example(); 647 if (examples.length > 0) { 648 if (retVal == null) { 649 retVal = new ArrayList<>(); 650 } 651 retVal.addAll(Arrays.asList(examples)); 652 } 653 } 654 } 655 return retVal; 656 } 657}