001/* 002 * #%L 003 * HAPI FHIR - Core Library 004 * %% 005 * Copyright (C) 2014 - 2024 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( 069 BaseRuntimeElementCompositeDefinition<?> theSourceDef, 070 IBase theSource, 071 BaseRuntimeElementCompositeDefinition<?> theTargetDef, 072 IBase theTarget) { 073 if (!theSource.isEmpty()) { 074 List<BaseRuntimeChildDefinition> targetChildren = theTargetDef.getChildren(); 075 List<RuntimeChildDeclaredExtensionDefinition> targetExts = theTargetDef.getExtensions(); 076 077 for (BaseRuntimeChildDefinition nextChild : targetChildren) { 078 079 String elementName = nextChild.getElementName(); 080 if (nextChild.getValidChildNames().size() > 1) { 081 elementName = nextChild.getValidChildNames().iterator().next(); 082 } 083 084 BaseRuntimeChildDefinition sourceChildEquivalent = 085 theSourceDef.getChildByNameOrThrowDataFormatException(elementName); 086 if (sourceChildEquivalent == null) { 087 continue; 088 } 089 090 List<? extends IBase> sourceValues = 091 sourceChildEquivalent.getAccessor().getValues(theSource); 092 for (IBase nextElement : sourceValues) { 093 boolean handled = false; 094 if (nextElement instanceof IBaseExtension) { 095 String url = ((IBaseExtension<?, ?>) nextElement).getUrl(); 096 for (RuntimeChildDeclaredExtensionDefinition nextExt : targetExts) { 097 String nextTargetUrl = nextExt.getExtensionUrl(); 098 if (!nextTargetUrl.equals(url)) { 099 continue; 100 } 101 addExtension(theSourceDef, theSource, theTarget, nextExt, url); 102 handled = true; 103 } 104 } 105 if (!handled) { 106 nextChild.getMutator().addValue(theTarget, nextElement); 107 } 108 } 109 } 110 111 for (RuntimeChildDeclaredExtensionDefinition nextExt : targetExts) { 112 String url = nextExt.getExtensionUrl(); 113 addExtension(theSourceDef, theSource, theTarget, nextExt, url); 114 } 115 } 116 } 117 118 private void addExtension( 119 BaseRuntimeElementCompositeDefinition<?> theSourceDef, 120 IBase theSource, 121 IBase theTarget, 122 RuntimeChildDeclaredExtensionDefinition nextExt, 123 String url) { 124 RuntimeChildDeclaredExtensionDefinition sourceDeclaredExt = theSourceDef.getDeclaredExtension(url, ""); 125 if (sourceDeclaredExt == null) { 126 127 if (theSource instanceof IBaseHasExtensions) { 128 for (IBaseExtension<?, ?> next : ((IBaseHasExtensions) theSource).getExtension()) { 129 if (next.getUrl().equals(url)) { 130 nextExt.getMutator().addValue(theTarget, next.getValue()); 131 } 132 } 133 } 134 if (theSource instanceof IBaseHasModifierExtensions) { 135 for (IBaseExtension<?, ?> next : ((IBaseHasModifierExtensions) theSource).getModifierExtension()) { 136 if (next.getUrl().equals(url)) { 137 nextExt.getMutator().addValue(theTarget, next.getValue()); 138 } 139 } 140 } 141 142 } else { 143 144 List<? extends IBase> values = sourceDeclaredExt.getAccessor().getValues(theSource); 145 for (IBase nextElement : values) { 146 nextExt.getMutator().addValue(theTarget, nextElement); 147 } 148 } 149 } 150}