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