001package ca.uhn.fhir.util;
002
003/*-
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2021 Smile CDR, Inc.
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.FhirVersionEnum;
027import org.hl7.fhir.instance.model.api.IBase;
028import org.hl7.fhir.instance.model.api.IBaseExtension;
029import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
030import org.hl7.fhir.instance.model.api.IBaseMetaType;
031import org.hl7.fhir.instance.model.api.IBaseResource;
032import org.hl7.fhir.instance.model.api.IPrimitiveType;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036import java.util.List;
037
038
039public class MetaUtil {
040        private static final Logger ourLog = LoggerFactory.getLogger(MetaUtil.class);
041
042        private MetaUtil() {
043                // non-instantiable
044        }
045
046        public static String getSource(FhirContext theContext, IBaseMetaType theMeta) {
047                if (theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
048                        return getSourceR4Plus(theContext, theMeta);
049                } else if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
050                        return getSourceDstu3((IBaseHasExtensions) theMeta);
051                } else {
052                        throw new UnsupportedOperationException(MetaUtil.class.getSimpleName() + ".getSource() not supported on FHIR Version " + theContext.getVersion().getVersion());
053                }
054        }
055
056        private static String getSourceDstu3(IBaseHasExtensions theMeta) {
057                IBaseHasExtensions metaWithExtensions = theMeta;
058                List<? extends IBaseExtension<?, ?>> extensions = metaWithExtensions.getExtension();
059                for (IBaseExtension extension : extensions) {
060                        if (HapiExtensions.EXT_META_SOURCE.equals(extension.getUrl())) {
061                                IPrimitiveType<String> value = (IPrimitiveType<String>) extension.getValue();
062                                return value.getValueAsString();
063                        }
064                }
065                return null;
066        }
067
068        private static String getSourceR4Plus(FhirContext theFhirContext, IBaseMetaType theMeta) {
069                BaseRuntimeElementCompositeDefinition<?> elementDef = (BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition(theMeta.getClass());
070                BaseRuntimeChildDefinition sourceChild = elementDef.getChildByName("source");
071                if (sourceChild == null) {
072                        return null;
073                }
074                List<IBase> sourceValues = sourceChild.getAccessor().getValues(theMeta);
075                String retVal = null;
076                if (sourceValues.size() > 0) {
077                        retVal = ((IPrimitiveType<?>) sourceValues.get(0)).getValueAsString();
078                }
079                return retVal;
080        }
081
082        /**
083         * Sets the value for <code>Resource.meta.source</code> for R4+ resources, and places the value in
084         * an extension on <code>Resource.meta</code>
085         * with the URL <code>http://hapifhir.io/fhir/StructureDefinition/resource-meta-source</code> for DSTU3.
086         *
087         * @param theContext  The FhirContext object
088         * @param theResource The resource to modify
089         * @param theValue    The source URI
090         * @see <a href="http://hl7.org/fhir/resource-definitions.html#Resource.meta">Meta.source</a>
091         */
092        @SuppressWarnings("unchecked")
093        public static void setSource(FhirContext theContext, IBaseResource theResource, String theValue) {
094                if (theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R4)) {
095                        MetaUtil.setSource(theContext, theResource.getMeta(), theValue);
096                } else if (theContext.getVersion().getVersion().equals(FhirVersionEnum.DSTU3)) {
097                        IBaseExtension<?, ?> sourceExtension = ((IBaseHasExtensions) theResource.getMeta()).addExtension();
098                        sourceExtension.setUrl(HapiExtensions.EXT_META_SOURCE);
099                        IPrimitiveType<String> value = (IPrimitiveType<String>) theContext.getElementDefinition("uri").newInstance();
100                        value.setValue(theValue);
101                        sourceExtension.setValue(value);
102                } else {
103                        ourLog.debug(MetaUtil.class.getSimpleName() + ".setSource() not supported on FHIR Version " + theContext.getVersion().getVersion());
104                }
105        }
106
107        public static void setSource(FhirContext theContext, IBaseMetaType theMeta, String theValue) {
108                BaseRuntimeElementCompositeDefinition<?> elementDef = (BaseRuntimeElementCompositeDefinition<?>) theContext.getElementDefinition(theMeta.getClass());
109                BaseRuntimeChildDefinition sourceChild = elementDef.getChildByName("source");
110                List<IBase> sourceValues = sourceChild.getAccessor().getValues(theMeta);
111                IPrimitiveType<?> sourceElement;
112                if (sourceValues.size() > 0) {
113                        sourceElement = ((IPrimitiveType<?>) sourceValues.get(0));
114                } else {
115                        sourceElement = (IPrimitiveType<?>) theContext.getElementDefinition("uri").newInstance();
116                        sourceChild.getMutator().setValue(theMeta, sourceElement);
117                }
118                sourceElement.setValueAsString(theValue);
119        }
120
121}