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