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