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