View Javadoc
1   package ca.uhn.fhir.jpa.dao;
2   
3   /*-
4    * #%L
5    * HAPI FHIR JPA Server
6    * %%
7    * Copyright (C) 2014 - 2019 University Health Network
8    * %%
9    * Licensed under the Apache License, Version 2.0 (the "License");
10   * you may not use this file except in compliance with the License.
11   * You may obtain a copy of the License at
12   *
13   *      http://www.apache.org/licenses/LICENSE-2.0
14   *
15   * Unless required by applicable law or agreed to in writing, software
16   * distributed under the License is distributed on an "AS IS" BASIS,
17   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18   * See the License for the specific language governing permissions and
19   * limitations under the License.
20   * #L%
21   */
22  
23  import ca.uhn.fhir.context.FhirContext;
24  import ca.uhn.fhir.context.RuntimeResourceDefinition;
25  import ca.uhn.fhir.jpa.api.IDaoRegistry;
26  import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
27  import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
28  import org.apache.commons.lang3.Validate;
29  import org.hl7.fhir.instance.model.api.IBaseResource;
30  import org.springframework.beans.BeansException;
31  import org.springframework.beans.factory.annotation.Autowired;
32  import org.springframework.context.ApplicationContext;
33  import org.springframework.context.ApplicationContextAware;
34  
35  import javax.annotation.Nullable;
36  import java.util.*;
37  import java.util.stream.Collectors;
38  
39  public class DaoRegistry implements ApplicationContextAware, IDaoRegistry {
40  	private ApplicationContext myAppCtx;
41  
42  	@Autowired
43  	private FhirContext myContext;
44  
45  	/**
46  	 * Constructor
47  	 */
48  	public DaoRegistry() {
49  		super();
50  	}
51  
52  	private volatile Map<String, IFhirResourceDao<?>> myResourceNameToResourceDao;
53  	private volatile IFhirSystemDao<?, ?> mySystemDao;
54  
55  	private Set<String> mySupportedResourceTypes;
56  
57  	public void setSupportedResourceTypes(Collection<String> theSupportedResourceTypes) {
58  		HashSet<String> supportedResourceTypes = new HashSet<>();
59  		if (theSupportedResourceTypes != null) {
60  			supportedResourceTypes.addAll(theSupportedResourceTypes);
61  		}
62  		mySupportedResourceTypes = supportedResourceTypes;
63  		myResourceNameToResourceDao = null;
64  
65  	}
66  
67  	@Override
68  	public void setApplicationContext(ApplicationContext theApplicationContext) throws BeansException {
69  		myAppCtx = theApplicationContext;
70  	}
71  
72  	public IFhirSystemDao getSystemDao() {
73  		IFhirSystemDao retVal = mySystemDao;
74  		if (retVal == null) {
75  			retVal = myAppCtx.getBean(IFhirSystemDao.class);
76  			mySystemDao = retVal;
77  		}
78  		return retVal;
79  	}
80  
81  	/**
82  	 * @throws InvalidRequestException If the given resource type is not supported
83  	 */
84  	public IFhirResourceDao getResourceDao(String theResourceName) {
85  		init();
86  		IFhirResourceDao retVal = myResourceNameToResourceDao.get(theResourceName);
87  		if (retVal == null) {
88  			List<String> supportedResourceTypes = myResourceNameToResourceDao
89  				.keySet()
90  				.stream()
91  				.sorted()
92  				.collect(Collectors.toList());
93  			throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + theResourceName + " - Can handle: " + supportedResourceTypes);
94  		}
95  		return retVal;
96  	}
97  
98  	public <R extends IBaseResource> IFhirResourceDao<R> getResourceDao(Class<R> theResourceType) {
99  		IFhirResourceDao<R> retVal = getResourceDaoIfExists(theResourceType);
100 		Validate.notNull(retVal, "No DAO exists for resource type %s - Have: %s", theResourceType, myResourceNameToResourceDao);
101 		return retVal;
102 	}
103 
104 	/**
105 	 * Use getResourceDaoOrNull
106 	 */
107 	@Deprecated
108 	public <T extends IBaseResource> IFhirResourceDao<T> getResourceDaoIfExists(Class<T> theResourceType) {
109 		return getResourceDaoOrNull(theResourceType);
110 	}
111 
112 	@Nullable
113 	public <T extends IBaseResource> IFhirResourceDao<T> getResourceDaoOrNull(Class<T> theResourceType) {
114 		String resourceName = myContext.getResourceDefinition(theResourceType).getName();
115 		try {
116 			return (IFhirResourceDao<T>) getResourceDao(resourceName);
117 		} catch (InvalidRequestException e) {
118 			return null;
119 		}
120 	}
121 
122 	/**
123 	 * Use getResourceDaoOrNull
124 	 */
125 	@Deprecated
126 	public <T extends IBaseResource> IFhirResourceDao<T> getResourceDaoIfExists(String theResourceType) {
127 		return getResourceDaoOrNull(theResourceType);
128 	}
129 
130 	@Nullable
131 	public <T extends IBaseResource> IFhirResourceDao<T> getResourceDaoOrNull(String theResourceType) {
132 		try {
133 			return (IFhirResourceDao<T>) getResourceDao(theResourceType);
134 		} catch (InvalidRequestException e) {
135 			return null;
136 		}
137 	}
138 
139 	@Override
140 	public boolean isResourceTypeSupported(String theResourceType) {
141 		return mySupportedResourceTypes == null || mySupportedResourceTypes.contains(theResourceType);
142 	}
143 
144 	private void init() {
145 		if (myResourceNameToResourceDao != null && !myResourceNameToResourceDao.isEmpty()) {
146 			return;
147 		}
148 
149 		Map<String, IFhirResourceDao> resourceDaos = myAppCtx.getBeansOfType(IFhirResourceDao.class);
150 
151 		initializeMaps(resourceDaos.values());
152 	}
153 
154 	private void initializeMaps(Collection<IFhirResourceDao> theResourceDaos) {
155 
156 		myResourceNameToResourceDao = new HashMap<>();
157 
158 		for (IFhirResourceDao nextResourceDao : theResourceDaos) {
159 			Class resourceType = nextResourceDao.getResourceType();
160 			assert resourceType != null;
161 			RuntimeResourceDefinition nextResourceDef = myContext.getResourceDefinition(resourceType);
162 			if (mySupportedResourceTypes == null || mySupportedResourceTypes.contains(nextResourceDef.getName())) {
163 				myResourceNameToResourceDao.put(nextResourceDef.getName(), nextResourceDao);
164 			}
165 		}
166 	}
167 
168 	public void register(IFhirResourceDao theResourceDao) {
169 		RuntimeResourceDefinition resourceDef = myContext.getResourceDefinition(theResourceDao.getResourceType());
170 		String resourceName = resourceDef.getName();
171 		myResourceNameToResourceDao.put(resourceName, theResourceDao);
172 	}
173 
174 	public IFhirResourceDao getDaoOrThrowException(Class<? extends IBaseResource> theClass) {
175 		IFhirResourceDao retVal = getResourceDao(theClass);
176 		if (retVal == null) {
177 			List<String> supportedResourceNames = myResourceNameToResourceDao
178 				.keySet()
179 				.stream()
180 				.map(t -> myContext.getResourceDefinition(t).getName())
181 				.sorted()
182 				.collect(Collectors.toList());
183 			throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + myContext.getResourceDefinition(theClass).getName() + " - Can handle: " + supportedResourceNames);
184 		}
185 		return retVal;
186 	}
187 
188 	public void setResourceDaos(Collection<IFhirResourceDao> theResourceDaos) {
189 		initializeMaps(theResourceDaos);
190 	}
191 
192 	public IFhirResourceDao getSubscriptionDao() {
193 		return getResourceDao(ResourceTypeEnum.SUBSCRIPTION.getCode());
194 	}
195 
196 	public void setSupportedResourceTypes(String... theResourceTypes) {
197 		setSupportedResourceTypes(toCollection(theResourceTypes));
198 	}
199 
200 	private List<String> toCollection(String[] theResourceTypes) {
201 		List<String> retVal = null;
202 		if (theResourceTypes != null && theResourceTypes.length > 0) {
203 			retVal = Arrays.asList(theResourceTypes);
204 		}
205 		return retVal;
206 	}
207 
208 	public Set<String> getRegisteredDaoTypes() {
209 		return Collections.unmodifiableSet(myResourceNameToResourceDao.keySet());
210 	}
211 }