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