001package ca.uhn.fhir.context; 002 003/* 004 * #%L 005 * HAPI FHIR - Core Library 006 * %% 007 * Copyright (C) 2014 - 2016 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.lang.reflect.Field; 024import java.util.ArrayList; 025import java.util.Collections; 026import java.util.HashSet; 027import java.util.List; 028import java.util.Map; 029import java.util.Set; 030 031import org.hl7.fhir.instance.model.api.IBase; 032import org.hl7.fhir.instance.model.api.IBaseReference; 033import org.hl7.fhir.instance.model.api.IBaseResource; 034 035import ca.uhn.fhir.model.api.annotation.Child; 036import ca.uhn.fhir.model.api.annotation.Description; 037 038public class RuntimeChildResourceDefinition extends BaseRuntimeDeclaredChildDefinition { 039 040 private BaseRuntimeElementDefinition<?> myRuntimeDef; 041 private List<Class<? extends IBaseResource>> myResourceTypes; 042 private Set<String> myValidChildNames; 043 044 /** 045 * Constructor 046 */ 047 public RuntimeChildResourceDefinition(Field theField, String theElementName, Child theChildAnnotation, Description theDescriptionAnnotation, List<Class<? extends IBaseResource>> theResourceTypes) { 048 super(theField, theChildAnnotation, theDescriptionAnnotation, theElementName); 049 myResourceTypes = theResourceTypes; 050 051 if (theResourceTypes == null || theResourceTypes.isEmpty()) { 052 myResourceTypes = new ArrayList<Class<? extends IBaseResource>>(); 053 myResourceTypes.add(IBaseResource.class); 054// throw new ConfigurationException("Field '" + theField.getName() + "' on type '" + theField.getDeclaringClass().getCanonicalName() + "' has no resource types noted"); 055 } 056 } 057 058 @Override 059 public String getChildNameByDatatype(Class<? extends IBase> theDatatype) { 060 if (IBaseReference.class.isAssignableFrom(theDatatype)) { 061 return getElementName(); 062 } 063 return null; 064 } 065 066 @Override 067 public BaseRuntimeElementDefinition<?> getChildElementDefinitionByDatatype(Class<? extends IBase> theDatatype) { 068 if (IBaseReference.class.isAssignableFrom(theDatatype)) { 069 return myRuntimeDef; 070 } 071 return null; 072 } 073 074 @Override 075 public Set<String> getValidChildNames() { 076 return myValidChildNames; 077 } 078 079 @Override 080 public BaseRuntimeElementDefinition<?> getChildByName(String theName) { 081 return myRuntimeDef; 082 } 083 084 @Override 085 void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { 086 myRuntimeDef = new RuntimeResourceReferenceDefinition(getElementName(), myResourceTypes, false); 087 myRuntimeDef.sealAndInitialize(theContext, theClassToElementDefinitions); 088 089 myValidChildNames = new HashSet<String>(); 090 myValidChildNames.add(getElementName()); 091 092 /* 093 * [elementName]Resource is not actually valid FHIR but we've encountered it in the wild 094 * so we'll accept it just to be nice 095 */ 096 myValidChildNames.add(getElementName() + "Resource"); 097 098 /* 099 * Below has been disabled- We used to allow field names to contain the name of the resource 100 * that they accepted. This wasn't valid but we accepted it just to be flexible because there 101 * were some bad examples containing this. This causes conflicts with actual field names in 102 * recent definitions though, so it has been disabled as of HAPI 0.9 103 */ 104// for (Class<? extends IBaseResource> next : myResourceTypes) { 105// if (next == IResource.class) { 106// for (Entry<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> nextEntry : theClassToElementDefinitions.entrySet()) { 107// if (IResource.class.isAssignableFrom(nextEntry.getKey())) { 108// RuntimeResourceDefinition nextDef = (RuntimeResourceDefinition) nextEntry.getValue(); 109// myValidChildNames.add(getElementName() + nextDef.getName()); 110// } 111// } 112// } 113// else { 114// RuntimeResourceDefinition nextDef = (RuntimeResourceDefinition) theClassToElementDefinitions.get(next); 115// if (nextDef == null) { 116// throw new ConfigurationException("Can't find child of type: " + next.getCanonicalName() + " in " + getField().getDeclaringClass()); 117// } 118// myValidChildNames.add(getElementName() + nextDef.getName()); 119// } 120// } 121 122 myResourceTypes = Collections.unmodifiableList(myResourceTypes); 123 myValidChildNames = Collections.unmodifiableSet(myValidChildNames); 124 } 125 126 public List<Class<? extends IBaseResource>> getResourceTypes() { 127 return myResourceTypes; 128 } 129 130 @Override 131 public String toString() { 132 return getClass().getSimpleName() + "[" + getElementName() + "]"; 133 } 134}