-
Notifications
You must be signed in to change notification settings - Fork 1.3k
/
ResourceSearchUrlSvc.java
110 lines (95 loc) · 4.1 KB
/
ResourceSearchUrlSvc.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
/*-
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2024 Smile CDR, Inc.
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http:https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
package ca.uhn.fhir.jpa.search;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.dao.data.IResourceSearchUrlDao;
import ca.uhn.fhir.jpa.model.entity.ResourceSearchUrlEntity;
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import jakarta.persistence.EntityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.Date;
/**
* This service ensures uniqueness of resources during create or create-on-update
* by storing the resource searchUrl.
*
* @see SearchUrlJobMaintenanceSvcImpl which deletes stale entities
*/
@Transactional
@Service
public class ResourceSearchUrlSvc {
private static final Logger ourLog = LoggerFactory.getLogger(ResourceSearchUrlSvc.class);
private final EntityManager myEntityManager;
private final IResourceSearchUrlDao myResourceSearchUrlDao;
private final MatchUrlService myMatchUrlService;
private final FhirContext myFhirContext;
public ResourceSearchUrlSvc(
EntityManager theEntityManager,
IResourceSearchUrlDao theResourceSearchUrlDao,
MatchUrlService theMatchUrlService,
FhirContext theFhirContext) {
myEntityManager = theEntityManager;
myResourceSearchUrlDao = theResourceSearchUrlDao;
myMatchUrlService = theMatchUrlService;
myFhirContext = theFhirContext;
}
/**
* Perform removal of entries older than {@code theCutoffDate} since the create operations are done.
*/
public void deleteEntriesOlderThan(Date theCutoffDate) {
ourLog.debug("About to delete SearchUrl which are older than {}", theCutoffDate);
int deletedCount = myResourceSearchUrlDao.deleteAllWhereCreatedBefore(theCutoffDate);
ourLog.debug("Deleted {} SearchUrls", deletedCount);
}
/**
* Once a resource is updated or deleted, we can trust that future match checks will find the committed resource in the db.
* The use of the constraint table is done, and we can delete it to keep the table small.
*/
public void deleteByResId(long theResId) {
myResourceSearchUrlDao.deleteByResId(theResId);
}
/**
* We store a record of match urls with res_id so a db constraint can catch simultaneous creates that slip through.
*/
public void enforceMatchUrlResourceUniqueness(
String theResourceName, String theMatchUrl, ResourceTable theResourceTable) {
String canonicalizedUrlForStorage = createCanonicalizedUrlForStorage(theResourceName, theMatchUrl);
ResourceSearchUrlEntity searchUrlEntity =
ResourceSearchUrlEntity.from(canonicalizedUrlForStorage, theResourceTable);
// calling dao.save performs a merge operation which implies a trip to
// the database to see if the resource exists. Since we don't need the check, we avoid the trip by calling
// em.persist.
myEntityManager.persist(searchUrlEntity);
}
/**
* Provides a sanitized matchUrl to circumvent ordering matters.
*/
private String createCanonicalizedUrlForStorage(String theResourceName, String theMatchUrl) {
RuntimeResourceDefinition resourceDef = myFhirContext.getResourceDefinition(theResourceName);
SearchParameterMap matchUrlSearchParameterMap = myMatchUrlService.translateMatchUrl(theMatchUrl, resourceDef);
String canonicalizedMatchUrl = matchUrlSearchParameterMap.toNormalizedQueryString(myFhirContext);
return theResourceName + canonicalizedMatchUrl;
}
}