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.util.ArrayList; 024import java.util.Collections; 025import java.util.Comparator; 026import java.util.LinkedHashMap; 027import java.util.List; 028import java.util.Map; 029 030import org.hl7.fhir.instance.model.api.IBase; 031import org.hl7.fhir.instance.model.api.IBaseResource; 032 033import ca.uhn.fhir.model.api.IResource; 034import ca.uhn.fhir.model.api.annotation.ResourceDef; 035import ca.uhn.fhir.util.UrlUtil; 036 037public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefinition<IBaseResource> { 038 039 private RuntimeResourceDefinition myBaseDefinition; 040 private FhirContext myContext; 041 private String myId; 042 private Map<String, RuntimeSearchParam> myNameToSearchParam = new LinkedHashMap<String, RuntimeSearchParam>(); 043 private IBaseResource myProfileDef; 044 private String myResourceProfile; 045 private List<RuntimeSearchParam> mySearchParams; 046 private final FhirVersionEnum myStructureVersion; 047 048 public RuntimeResourceDefinition(FhirContext theContext, String theResourceName, Class<? extends IBaseResource> theClass, ResourceDef theResourceAnnotation, boolean theStandardType) { 049 super(theResourceName, theClass, theStandardType); 050 myContext= theContext; 051 myResourceProfile = theResourceAnnotation.profile(); 052 myId = theResourceAnnotation.id(); 053 054 try { 055 IBaseResource instance = theClass.newInstance(); 056 myStructureVersion = instance.getStructureFhirVersionEnum(); 057 assert myStructureVersion != null; 058 } catch (Exception e) { 059 throw new ConfigurationException(myContext.getLocalizer().getMessage(getClass(), "nonInstantiableType", theClass.getName(), e.toString()), e); 060 } 061 062 } 063 064 public void addSearchParam(RuntimeSearchParam theParam) { 065 myNameToSearchParam.put(theParam.getName(), theParam); 066 } 067 068 /** 069 * If this definition refers to a class which extends another resource definition type, this 070 * method will return the definition of the topmost resource. For example, if this definition 071 * refers to MyPatient2, which extends MyPatient, which in turn extends Patient, this method 072 * will return the resource definition for Patient. 073 * <p> 074 * If the definition has no parent, returns <code>this</code> 075 * </p> 076 */ 077 public RuntimeResourceDefinition getBaseDefinition() { 078 return myBaseDefinition; 079 } 080 081 @Override 082 public ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum getChildType() { 083 return ChildTypeEnum.RESOURCE; 084 } 085 086 public String getId() { 087 return myId; 088 } 089 090 /** 091 * Express {@link #getImplementingClass()} as theClass (to prevent casting warnings) 092 */ 093 @SuppressWarnings("unchecked") 094 public <T> Class<T> getImplementingClass(Class<T> theClass) { 095 if (!theClass.isAssignableFrom(getImplementingClass())) { 096 throw new ConfigurationException("Unable to convert " + getImplementingClass() + " to " + theClass); 097 } 098 return (Class<T>) getImplementingClass(); 099 } 100 101 @Deprecated 102 public String getResourceProfile() { 103 return myResourceProfile; 104 } 105 106 public String getResourceProfile(String theServerBase) { 107 String profile; 108 if (!myResourceProfile.isEmpty()) { 109 profile = myResourceProfile; 110 } else if (!myId.isEmpty()) { 111 profile = myId; 112 } else { 113 return ""; 114 } 115 116 if (!UrlUtil.isValid(profile)) { 117 String resourceName = "/StructureDefinition/"; 118 if (myContext.getVersion().getVersion() == FhirVersionEnum.DSTU1) { 119 resourceName = "/Profile/"; 120 } 121 String profileWithUrl = theServerBase + resourceName + profile; 122 if (UrlUtil.isValid(profileWithUrl)) { 123 return profileWithUrl; 124 } 125 } 126 return profile; 127 } 128 129 public RuntimeSearchParam getSearchParam(String theName) { 130 return myNameToSearchParam.get(theName); 131 } 132 133 public List<RuntimeSearchParam> getSearchParams() { 134 return mySearchParams; 135 } 136 137 public FhirVersionEnum getStructureVersion() { 138 return myStructureVersion; 139 } 140 141 public boolean isBundle() { 142 return "Bundle".equals(getName()); 143 } 144 145 public boolean isStandardProfile() { 146 return myResourceProfile.startsWith("http://hl7.org/fhir/profiles"); 147 } 148 149 @Override 150 public void sealAndInitialize(FhirContext theContext, Map<Class<? extends IBase>, BaseRuntimeElementDefinition<?>> theClassToElementDefinitions) { 151 super.sealAndInitialize(theContext, theClassToElementDefinitions); 152 153 myNameToSearchParam = Collections.unmodifiableMap(myNameToSearchParam); 154 155 ArrayList<RuntimeSearchParam> searchParams = new ArrayList<RuntimeSearchParam>(myNameToSearchParam.values()); 156 Collections.sort(searchParams, new Comparator<RuntimeSearchParam>() { 157 @Override 158 public int compare(RuntimeSearchParam theArg0, RuntimeSearchParam theArg1) { 159 return theArg0.getName().compareTo(theArg1.getName()); 160 } 161 }); 162 mySearchParams = Collections.unmodifiableList(searchParams); 163 164 Class<?> target = getImplementingClass(); 165 myBaseDefinition = this; 166 do { 167 target = target.getSuperclass(); 168 if (IResource.class.isAssignableFrom(target) && target.getAnnotation(ResourceDef.class)!=null) { 169 myBaseDefinition = (RuntimeResourceDefinition) theClassToElementDefinitions.get(target); 170 } 171 } while (target.equals(Object.class)==false); 172 } 173 174 @Deprecated 175 public synchronized IBaseResource toProfile() { 176 if (myProfileDef != null) { 177 return myProfileDef; 178 } 179 180 IBaseResource retVal = myContext.getVersion().generateProfile(this, null); 181 myProfileDef = retVal; 182 183 return retVal; 184 } 185 186 public synchronized IBaseResource toProfile(String theServerBase) { 187 if (myProfileDef != null) { 188 return myProfileDef; 189 } 190 191 IBaseResource retVal = myContext.getVersion().generateProfile(this, theServerBase); 192 myProfileDef = retVal; 193 194 return retVal; 195 } 196}