001package ca.uhn.fhir.util;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2020 University Health Network
008 * %%
009 * Licensed under the Apache License, Version 2.0 (the "License");
010 * you may not use this file except in compliance with the License.
011 * You may obtain a copy of the License at
012 *
013 *      http://www.apache.org/licenses/LICENSE-2.0
014 *
015 * Unless required by applicable law or agreed to in writing, software
016 * distributed under the License is distributed on an "AS IS" BASIS,
017 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
018 * See the License for the specific language governing permissions and
019 * limitations under the License.
020 * #L%
021 */
022
023import ca.uhn.fhir.context.*;
024import ca.uhn.fhir.model.primitive.StringDt;
025import org.apache.commons.lang3.StringUtils;
026import org.apache.commons.lang3.Validate;
027import org.hl7.fhir.instance.model.api.*;
028
029import java.util.ArrayList;
030import java.util.Collection;
031import java.util.List;
032import java.util.Optional;
033
034/**
035 * Utilities for dealing with parameters resources in a version indepenedent way
036 */
037public class ParametersUtil {
038
039        public static List<String> getNamedParameterValuesAsString(FhirContext theCtx, IBaseParameters theParameters, String theParameterName) {
040                Validate.notNull(theParameters, "theParameters must not be null");
041                RuntimeResourceDefinition resDef = theCtx.getResourceDefinition(theParameters.getClass());
042                BaseRuntimeChildDefinition parameterChild = resDef.getChildByName("parameter");
043                List<IBase> parameterReps = parameterChild.getAccessor().getValues(theParameters);
044
045                List<String> retVal = new ArrayList<>();
046
047                for (IBase nextParameter : parameterReps) {
048                        BaseRuntimeElementCompositeDefinition<?> nextParameterDef = (BaseRuntimeElementCompositeDefinition<?>) theCtx.getElementDefinition(nextParameter.getClass());
049                        BaseRuntimeChildDefinition nameChild = nextParameterDef.getChildByName("name");
050                        List<IBase> nameValues = nameChild.getAccessor().getValues(nextParameter);
051                        Optional<? extends IPrimitiveType<?>> nameValue = nameValues
052                                .stream()
053                                .filter(t -> t instanceof IPrimitiveType<?>)
054                                .map(t -> ((IPrimitiveType<?>) t))
055                                .findFirst();
056                        if (!nameValue.isPresent() || !theParameterName.equals(nameValue.get().getValueAsString())) {
057                                continue;
058                        }
059
060                        BaseRuntimeChildDefinition valueChild = nextParameterDef.getChildByName("value[x]");
061                        List<IBase> valueValues = valueChild.getAccessor().getValues(nextParameter);
062                        valueValues
063                                .stream()
064                                .filter(t -> t instanceof IPrimitiveType<?>)
065                                .map(t -> ((IPrimitiveType<?>) t).getValueAsString())
066                                .filter(StringUtils::isNotBlank)
067                                .forEach(retVal::add);
068
069                }
070
071                return retVal;
072        }
073
074        private static void addClientParameter(FhirContext theContext, Object theValue, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
075                Validate.notNull(theValue, "theValue must not be null");
076
077                if (theValue instanceof IBaseResource) {
078                        IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
079                        paramChildElem.getChildByName("resource").getMutator().addValue(parameter, (IBaseResource) theValue);
080                } else if (theValue instanceof IBaseDatatype) {
081                        IBase parameter = createParameterRepetition(theContext, theTargetResource, paramChild, paramChildElem, theName);
082                        paramChildElem.getChildByName("value[x]").getMutator().addValue(parameter, (IBaseDatatype) theValue);
083                } else if (theValue instanceof Collection) {
084                        Collection<?> collection = (Collection<?>) theValue;
085                        for (Object next : collection) {
086                                addClientParameter(theContext, next, theTargetResource, paramChild, paramChildElem, theName);
087                        }
088                } else {
089                        throw new IllegalArgumentException("Don't know how to handle value of type " + theValue.getClass() + " for parameter " + theName);
090                }
091        }
092
093        /**
094         * Add a paratemer value to a Parameters resource
095         *
096         * @param theContext    The FhirContext
097         * @param theParameters The Parameters resource
098         * @param theName       The parametr name
099         * @param theValue      The parameter value (can be a {@link IBaseResource resource} or a {@link IBaseDatatype datatype})
100         */
101        public static void addParameterToParameters(FhirContext theContext, IBaseParameters theParameters, String theName, Object theValue) {
102                RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters);
103                BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
104                BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
105
106                addClientParameter(theContext, theValue, theParameters, paramChild, paramChildElem, theName);
107        }
108
109        /**
110         * Add a paratemer value to a Parameters resource
111         *
112         * @param theContext           The FhirContext
113         * @param theParameters        The Parameters resource
114         * @param theName              The parameter name
115         * @param thePrimitiveDatatype The datatype, e.g. "string", or "uri"
116         * @param theValue             The value
117         */
118        public static void addParameterToParameters(FhirContext theContext, IBaseParameters theParameters, String theName, String thePrimitiveDatatype, String theValue) {
119                Validate.notBlank(thePrimitiveDatatype, "thePrimitiveDatatype must not be null or empty");
120
121                BaseRuntimeElementDefinition<?> datatypeDef = theContext.getElementDefinition(thePrimitiveDatatype);
122                IPrimitiveType<?> value = (IPrimitiveType<?>) datatypeDef.newInstance();
123                value.setValueAsString(theValue);
124
125                addParameterToParameters(theContext, theParameters, theName, value);
126        }
127
128        private static IBase createParameterRepetition(FhirContext theContext, IBaseResource theTargetResource, BaseRuntimeChildDefinition paramChild, BaseRuntimeElementCompositeDefinition<?> paramChildElem, String theName) {
129                IBase parameter = paramChildElem.newInstance();
130                paramChild.getMutator().addValue(theTargetResource, parameter);
131                IPrimitiveType<?> value;
132                value = createString(theContext, theName);
133                paramChildElem.getChildByName("name").getMutator().addValue(parameter, value);
134                return parameter;
135        }
136
137        public static IPrimitiveType<?> createString(FhirContext theContext, String theValue) {
138                IPrimitiveType<?> value;
139                if (theContext.getVersion().getVersion().isRi()) {
140                        value = (IPrimitiveType<?>) theContext.getElementDefinition("string").newInstance(theValue);
141                } else {
142                        value = new StringDt(theValue);
143                }
144                return value;
145        }
146
147        public static IPrimitiveType<?> createUri(FhirContext theContext, String theValue) {
148                IPrimitiveType<?> value = (IPrimitiveType<?>) theContext.getElementDefinition("uri").newInstance(theValue);
149                return value;
150        }
151
152        public static IPrimitiveType<?> createCode(FhirContext theContext, String theValue) {
153                IPrimitiveType<?> value = (IPrimitiveType<?>) theContext.getElementDefinition("code").newInstance(theValue);
154                return value;
155        }
156
157        public static IBaseParameters newInstance(FhirContext theContext) {
158                Validate.notNull(theContext, "theContext must not be null");
159                return (IBaseParameters) theContext.getResourceDefinition("Parameters").newInstance();
160        }
161
162        @SuppressWarnings("unchecked")
163        public static void addParameterToParametersBoolean(FhirContext theCtx, IBaseParameters theParameters, String theName, boolean theValue) {
164                IPrimitiveType<Boolean> value = (IPrimitiveType<Boolean>) theCtx.getElementDefinition("boolean").newInstance();
165                value.setValue(theValue);
166                addParameterToParameters(theCtx, theParameters, theName, value);
167        }
168
169        @SuppressWarnings("unchecked")
170        public static void addParameterToParametersCode(FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) {
171                IPrimitiveType<String> value = (IPrimitiveType<String>) theCtx.getElementDefinition("code").newInstance();
172                value.setValue(theValue);
173                addParameterToParameters(theCtx, theParameters, theName, value);
174        }
175
176        @SuppressWarnings("unchecked")
177        public static void addParameterToParametersInteger(FhirContext theCtx, IBaseParameters theParameters, String theName, int theValue) {
178                IPrimitiveType<Integer> count = (IPrimitiveType<Integer>) theCtx.getElementDefinition("integer").newInstance();
179                count.setValue(theValue);
180                addParameterToParameters(theCtx, theParameters, theName, count);
181
182        }
183
184        public static void addParameterToParametersReference(FhirContext theCtx, IBaseParameters theParameters, String theName, String theReference) {
185                IBaseReference target = (IBaseReference) theCtx.getElementDefinition("reference").newInstance();
186                target.setReference(theReference);
187                addParameterToParameters(theCtx, theParameters, theName, target);
188        }
189
190        @SuppressWarnings("unchecked")
191        public static void addParameterToParametersString(FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) {
192                IPrimitiveType<String> value = (IPrimitiveType<String>) theCtx.getElementDefinition("string").newInstance();
193                value.setValue(theValue);
194                addParameterToParameters(theCtx, theParameters, theName, value);
195        }
196
197        @SuppressWarnings("unchecked")
198        public static void addParameterToParametersUri(FhirContext theCtx, IBaseParameters theParameters, String theName, String theValue) {
199                IPrimitiveType<String> value = (IPrimitiveType<String>) theCtx.getElementDefinition("uri").newInstance();
200                value.setValue(theValue);
201                addParameterToParameters(theCtx, theParameters, theName, value);
202
203        }
204
205        /**
206         * Add a parameter with no value (typically because we'll be adding sub-parameters)
207         */
208        public static IBase addParameterToParameters(FhirContext theContext, IBaseParameters theParameters, String theName) {
209                RuntimeResourceDefinition def = theContext.getResourceDefinition(theParameters);
210                BaseRuntimeChildDefinition paramChild = def.getChildByName("parameter");
211                BaseRuntimeElementCompositeDefinition<?> paramChildElem = (BaseRuntimeElementCompositeDefinition<?>) paramChild.getChildByName("parameter");
212
213                return createParameterRepetition(theContext, theParameters, paramChild, paramChildElem, theName);
214        }
215
216        public static void addPartCode(FhirContext theContext, IBase theParameter, String theName, String theCode) {
217                IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("code").newInstance();
218                value.setValue(theCode);
219
220                addPart(theContext, theParameter, theName, value);
221        }
222
223        public static void addPartString(FhirContext theContext, IBase theParameter, String theName, String theValue) {
224                IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("string").newInstance();
225                value.setValue(theValue);
226
227                addPart(theContext, theParameter, theName, value);
228        }
229
230        public static void addPartCoding(FhirContext theContext, IBase theParameter, String theName, String theSystem, String theCode, String theDisplay) {
231                IBase coding = theContext.getElementDefinition("coding").newInstance();
232
233                BaseRuntimeElementCompositeDefinition<?> codingDef = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(coding.getClass());
234                codingDef.getChildByName("system").getMutator().addValue(coding, createUri(theContext, theSystem));
235                codingDef.getChildByName("code").getMutator().addValue(coding, createCode(theContext, theCode));
236                codingDef.getChildByName("display").getMutator().addValue(coding, createString(theContext, theDisplay));
237
238                addPart(theContext, theParameter, theName, coding);
239        }
240
241        private static void addPart(FhirContext theContext, IBase theParameter, String theName, IBase theValue) {
242                BaseRuntimeElementCompositeDefinition<?> def = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theParameter.getClass());
243                BaseRuntimeChildDefinition partChild = def.getChildByName("part");
244
245                BaseRuntimeElementCompositeDefinition<?> partChildElem = (BaseRuntimeElementCompositeDefinition<?>) partChild.getChildByName("part");
246                IBase part = partChildElem.newInstance();
247                partChild.getMutator().addValue(theParameter, part);
248
249                IPrimitiveType<String> name = (IPrimitiveType<String>) theContext.getElementDefinition("string").newInstance();
250                name.setValue(theName);
251                partChildElem.getChildByName("name").getMutator().addValue(part, name);
252
253                partChildElem.getChildByName("value[x]").getMutator().addValue(part, theValue);
254        }
255}