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