001package ca.uhn.fhir.util;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2018 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.BaseRuntimeChildDefinition;
024import ca.uhn.fhir.context.BaseRuntimeElementCompositeDefinition;
025import ca.uhn.fhir.context.FhirContext;
026import ca.uhn.fhir.context.RuntimeResourceDefinition;
027import ca.uhn.fhir.model.primitive.StringDt;
028import org.apache.commons.lang3.StringUtils;
029import org.apache.commons.lang3.Validate;
030import org.hl7.fhir.instance.model.api.*;
031
032import java.util.ArrayList;
033import java.util.Collection;
034import java.util.List;
035import java.util.Optional;
036
037/**
038 * Utilities for dealing with parameters resources in a version indepenedent way
039 */
040public class ParametersUtil {
041
042        public static List<String> getNamedParameterValuesAsString(FhirContext theCtx, IBaseParameters theParameters, String theParameterName) {
043                Validate.notNull(theParameters, "theParameters must not be null");
044                RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass());
045                BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter");
046                List<IBase> parameterReps = parameterChild.getAccessor().getValues(theParameters);
047
048                List<String> retVal = new ArrayList<>();
049
050                for (IBase nextParameter : parameterReps) {
051                        BaseRuntimeElementCompositeDefinition<?> nextParameterDef = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass());
052                        BaseRuntimeChildDefinition nameChild = nextParameterDef.getChildByName("name");
053                        List<IBase> nameValues = nameChild.getAccessor().getValues(nextParameter);
054                        Optional<? extends IPrimitiveType<?>> nameValue = nameValues
055                                .stream()
056                                .filter(t -> t instanceof IPrimitiveType<?>)
057                                .map(t -> ((IPrimitiveType<?>) t))
058                                .findFirst();
059                        if (!nameValue.isPresent() || !theParameterName.equals(nameValue.get().getValueAsString())) {
060                                continue;
061                        }
062
063                        BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("value[x]");
064                        List<IBase> valueValues = valueChild.getAccessor().getValues(nextParameter);
065                        valueValues
066                                .stream()
067                                .filter(t->t instanceof IPrimitiveType<?>)
068                                .map(t->((IPrimitiveType<?>)t).getValueAsString())
069                                .filter(StringUtils::isNotBlank)
070                                .forEach(retVal::add);
071
072                }
073
074                return retVal;
075        }
076
077        private static void addClientParameter(FhirContext theContext, Object theValue, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
078                if (theValue instanceof IBaseResource) {
079                        IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
080                        paramChildElem.getChildByName("resource").getMutator().addValue(parameter, (IBaseResource) theValue);
081                } else if (theValue instanceof IBaseDatatype) {
082                        IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
083                        paramChildElem.getChildByName("value[x]").getMutator().addValue(parameter, (IBaseDatatype) theValue);
084                } else if (theValue instanceof Collection) {
085                        Collection<?> collection = (Collection<?>) theValue;
086                        for (Object next : collection) {
087                                addClientParameter(theContext, next, theTargetResource, paramChild, paramChildElem, theName);
088                        }
089                } else {
090                        throw new IllegalArgumentException("Don't know how to handle value of type " + theValue.getClass() + " for parameter " + theName);
091                }
092        }
093
094        /**
095         * Add a paratemer value to a Parameters resource
096         *
097         * @param theContext    The FhirContext
098         * @param theParameters The Parameters resource
099         * @param theName       The parametr name
100         * @param theValue      The parameter value (can be a {@link IBaseResource resource} or a {@link IBaseDatatype datatype})
101         */
102        public static void addParameterToParameters(FhirContext theContext, IBaseParameters theParameters, String theName, Object theValue) {
103                RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters);
104                BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
105                BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
106
107                addClientParameter(theContext, theValue, theParameters, paramChild, paramChildElem, theName);
108        }
109
110        private static IBase createParameterRepetition(FhirContext theContext, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
111                IBase parameter = paramChildElem.newInstance();
112                paramChild.getMutator().addValue(theTargetResource, parameter);
113                IPrimitiveType<?> value;
114                value = createString(theContext, theName);
115                paramChildElem.getChildByName("name").getMutator().addValue(parameter, value);
116                return parameter;
117        }
118
119        public static IPrimitiveType<?> createString(FhirContext theContext, String theValue) {
120                IPrimitiveType<?> value;
121                if (theContext.getVersion().getVersion().isRi()) {
122                        value = (IPrimitiveType<?>) theContext.getElementDefinition("string").newInstance(theValue);
123                } else {
124                        value = new StringDt(theValue);
125                }
126                return value;
127        }
128
129        public static IBaseParameters newInstance(FhirContext theContext) {
130                Validate.notNull(theContext, "theContext must not be null");
131                return (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance();
132        }
133
134}