001package ca.uhn.fhir.model.view;
002
003/*
004 * #%L
005 * HAPI FHIR - Core Library
006 * %%
007 * Copyright (C) 2014 - 2022 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.ConfigurationException;
026import ca.uhn.fhir.context.FhirContext;
027import ca.uhn.fhir.context.RuntimeChildDeclaredExtensionDefinition;
028import ca.uhn.fhir.context.RuntimeResourceDefinition;
029import ca.uhn.fhir.i18n.Msg;
030import org.hl7.fhir.instance.model.api.IBase;
031import org.hl7.fhir.instance.model.api.IBaseExtension;
032import org.hl7.fhir.instance.model.api.IBaseHasExtensions;
033import org.hl7.fhir.instance.model.api.IBaseHasModifierExtensions;
034import org.hl7.fhir.instance.model.api.IBaseResource;
035
036import java.util.List;
037
038public class ViewGenerator {
039
040        private FhirContext myCtx;
041
042        public ViewGenerator(FhirContext theFhirContext) {
043                myCtx = theFhirContext;
044        }
045
046        public <T extends IBaseResource> T newView(IBaseResource theResource, Class<T> theTargetType) {
047                Class<? extends IBaseResource> sourceType = theResource.getClass();
048                RuntimeResourceDefinition sourceDef = myCtx.getResourceDefinition(theResource);
049                RuntimeResourceDefinition targetDef = myCtx.getResourceDefinition(theTargetType);
050
051                if (sourceType.equals(theTargetType)) {
052                        @SuppressWarnings("unchecked")
053                        T resource = (T) theResource;
054                        return resource;
055                }
056
057                T retVal;
058                try {
059                        retVal = theTargetType.newInstance();
060                } catch (Exception e) {
061                        throw new ConfigurationException(Msg.code(1886) + "Failed to instantiate " + theTargetType, e);
062                }
063
064                copyChildren(sourceDef, (IBase) theResource, targetDef, (IBase) retVal);
065
066                return retVal;
067        }
068
069        private void copyChildren(BaseRuntimeElementCompositeDefinition<?> theSourceDef, IBase theSource, BaseRuntimeElementCompositeDefinition<?> theTargetDef, IBase theTarget) {
070                if (!theSource.isEmpty()) {
071                        List<BaseRuntimeChildDefinition> targetChildren = theTargetDef.getChildren();
072                        List<RuntimeChildDeclaredExtensionDefinition> targetExts = theTargetDef.getExtensions();
073
074                        for (BaseRuntimeChildDefinition nextChild : targetChildren) {
075
076                                String elementName = nextChild.getElementName();
077                                if (nextChild.getValidChildNames().size() > 1) {
078                                        elementName = nextChild.getValidChildNames().iterator().next();
079                                }
080
081                                BaseRuntimeChildDefinition sourceChildEquivalent = theSourceDef.getChildByNameOrThrowDataFormatException(elementName);
082                                if (sourceChildEquivalent == null) {
083                                        continue;
084                                }
085
086                                List<? extends IBase> sourceValues = sourceChildEquivalent.getAccessor().getValues(theSource);
087                                for (IBase nextElement : sourceValues) {
088                                        boolean handled = false;
089                                        if (nextElement instanceof IBaseExtension) {
090                                                String url = ((IBaseExtension<?, ?>) nextElement).getUrl();
091                                                for (RuntimeChildDeclaredExtensionDefinition nextExt : targetExts) {
092                                                        String nextTargetUrl = nextExt.getExtensionUrl();
093                                                        if (!nextTargetUrl.equals(url)) {
094                                                                continue;
095                                                        }
096                                                        addExtension(theSourceDef, theSource, theTarget, nextExt, url);
097                                                        handled = true;
098                                                }
099                                        }
100                                        if (!handled) {
101                                                nextChild.getMutator().addValue(theTarget, nextElement);
102                                        }
103                                }
104                        }
105
106                        for (RuntimeChildDeclaredExtensionDefinition nextExt : targetExts) {
107                                String url = nextExt.getExtensionUrl();
108                                addExtension(theSourceDef, theSource, theTarget, nextExt, url);
109                        }
110
111
112                }
113        }
114
115        private void addExtension(BaseRuntimeElementCompositeDefinition<?> theSourceDef, IBase theSource, IBase theTarget, RuntimeChildDeclaredExtensionDefinition nextExt, String url) {
116                RuntimeChildDeclaredExtensionDefinition sourceDeclaredExt = theSourceDef.getDeclaredExtension(url, "");
117                if (sourceDeclaredExt == null) {
118
119                        if (theSource instanceof IBaseHasExtensions) {
120                                for (IBaseExtension<?, ?> next : ((IBaseHasExtensions) theSource).getExtension()) {
121                                        if (next.getUrl().equals(url)) {
122                                                nextExt.getMutator().addValue(theTarget, next.getValue());
123                                        }
124                                }
125                        }
126                        if (theSource instanceof IBaseHasModifierExtensions) {
127                                for (IBaseExtension<?, ?> next : ((IBaseHasModifierExtensions) theSource).getModifierExtension()) {
128                                        if (next.getUrl().equals(url)) {
129                                                nextExt.getMutator().addValue(theTarget, next.getValue());
130                                        }
131                                }
132                        }
133
134                } else {
135
136                        List<? extends IBase> values = sourceDeclaredExt.getAccessor().getValues(theSource);
137                        for (IBase nextElement : values) {
138                                nextExt.getMutator().addValue(theTarget, nextElement);
139                        }
140
141                }
142        }
143}