Work on multitenancy
This commit is contained in:
parent
d822867a4a
commit
cd06137745
|
@ -0,0 +1,76 @@
|
||||||
|
Merge branch 'master' into ja_20200206_multitenancy
|
||||||
|
|
||||||
|
# Conflicts:
|
||||||
|
# hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
|
||||||
|
# hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/SearchParamWithInlineReferencesExtractor.java
|
||||||
|
# hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceLinkExtractor.java
|
||||||
|
# hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/InlineResourceLinkResolver.java
|
||||||
|
#
|
||||||
|
# It looks like you may be committing a merge.
|
||||||
|
# If this is not correct, please remove the file
|
||||||
|
# .git/MERGE_HEAD
|
||||||
|
# and try again.
|
||||||
|
|
||||||
|
|
||||||
|
# Please enter the commit message for your changes. Lines starting
|
||||||
|
# with '#' will be ignored, and an empty message aborts the commit.
|
||||||
|
#
|
||||||
|
# On branch ja_20200206_multitenancy
|
||||||
|
# Your branch is up to date with 'origin/ja_20200206_multitenancy'.
|
||||||
|
#
|
||||||
|
# All conflicts fixed but you are still merging.
|
||||||
|
#
|
||||||
|
# Changes to be committed:
|
||||||
|
# new file: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseErrorHandler.java
|
||||||
|
# modified: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/BaseParser.java
|
||||||
|
# modified: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/JsonParser.java
|
||||||
|
# modified: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/LenientErrorHandler.java
|
||||||
|
# modified: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParseLocation.java
|
||||||
|
# modified: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/ParserState.java
|
||||||
|
# modified: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/StrictErrorHandler.java
|
||||||
|
# modified: hapi-fhir-base/src/main/java/ca/uhn/fhir/parser/json/jackson/JacksonStructure.java
|
||||||
|
# new file: hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1793-report-attr-name-in-json-parse-errors.yaml
|
||||||
|
# new file: hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1801-allow-parsing-contained-in-jpa.yaml
|
||||||
|
# new file: hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/4_3_0/1801-handle-persisted-leading-decimals.yaml
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/config/BaseConfig.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
|
||||||
|
# new file: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/TolerantJsonParser.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/DaoResourceLinkResolver.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/SearchParamWithInlineReferencesExtractor.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/util/xmlpatch/XmlPatchUtils.java
|
||||||
|
# new file: hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/TolerantJsonParserR4Test.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/BaseJpaDstu3Test.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/dstu3/FhirResourceDaoDstu3SearchCustomSearchParamTest.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/FhirResourceDaoR4SearchCustomSearchParamTest.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/subscription/resthook/SubscriptionTriggeringDstu3Test.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/config/SearchParamConfig.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/BaseSearchParamExtractor.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceIndexedSearchParams.java
|
||||||
|
# deleted: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/ResourceLinkExtractor.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/IndexedSearchParamExtractor.java
|
||||||
|
# deleted: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/InlineResourceLinkResolver.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/SearchParamMatcher.java
|
||||||
|
# modified: hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/JsonParserDstu2_1Test.java
|
||||||
|
# modified: hapi-fhir-structures-dstu2.1/src/test/java/ca/uhn/fhir/parser/XmlParserDstu2_1Test.java
|
||||||
|
# modified: hapi-fhir-structures-dstu2/src/test/java/ca/uhn/fhir/validation/ResourceValidatorDstu2Test.java
|
||||||
|
# modified: hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/JsonParserDstu3Test.java
|
||||||
|
# modified: hapi-fhir-structures-dstu3/src/test/java/ca/uhn/fhir/parser/XmlParserDstu3Test.java
|
||||||
|
# modified: hapi-fhir-structures-hl7org-dstu2/src/test/java/ca/uhn/fhir/rest/client/ClientServerValidationTestHl7OrgDstu2.java
|
||||||
|
# modified: hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/parser/JsonParserR4Test.java
|
||||||
|
# modified: hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/interceptor/ResponseSizeCapturingInterceptorTest.java
|
||||||
|
# new file: hapi-fhir-test-utilities/src/main/java/ca/uhn/fhir/test/utilities/ProxyUtil.java
|
||||||
|
# modified: hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu2016may/hapi/validation/ResourceValidatorDstu2_1Test.java
|
||||||
|
# modified: hapi-fhir-validation/src/test/java/org/hl7/fhir/dstu3/hapi/validation/ResourceValidatorDstu3Test.java
|
||||||
|
#
|
||||||
|
# Changes not staged for commit:
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirDao.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/IdHelperService.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/index/SearchParamWithInlineReferencesExtractor.java
|
||||||
|
# modified: hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/r4/PartitioningR4Test.java
|
||||||
|
# modified: hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/config/PartitionConfig.java
|
||||||
|
# modified: hapi-fhir-jpaserver-model/src/main/java/ca/uhn/fhir/jpa/model/entity/PartitionId.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/extractor/SearchParamExtractorService.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/IndexedSearchParamExtractor.java
|
||||||
|
# modified: hapi-fhir-jpaserver-searchparam/src/main/java/ca/uhn/fhir/jpa/searchparam/matcher/SearchParamMatcher.java
|
||||||
|
#
|
|
@ -998,7 +998,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
if (thePerformIndexing) {
|
if (thePerformIndexing) {
|
||||||
|
|
||||||
newParams = new ResourceIndexedSearchParams();
|
newParams = new ResourceIndexedSearchParams();
|
||||||
mySearchParamWithInlineReferencesExtractor.populateFromResource(myPartitionConfig, newParams, theUpdateTime, entity, theResource, existingParams, theRequest);
|
mySearchParamWithInlineReferencesExtractor.populateFromResource(newParams, theUpdateTime, entity, theResource, existingParams, theRequest);
|
||||||
|
|
||||||
changed = populateResourceIntoEntity(theRequest, theResource, entity, true);
|
changed = populateResourceIntoEntity(theRequest, theResource, entity, true);
|
||||||
if (changed.isChanged()) {
|
if (changed.isChanged()) {
|
||||||
|
|
|
@ -63,7 +63,6 @@ import java.util.Date;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -146,7 +145,7 @@ public class IdHelperService {
|
||||||
if (myDaoConfig.isDeleteEnabled()) {
|
if (myDaoConfig.isDeleteEnabled()) {
|
||||||
retVal = resolveResourceIdentity(thePartitionId, theResourceType, theId);
|
retVal = resolveResourceIdentity(thePartitionId, theResourceType, theId);
|
||||||
} else {
|
} else {
|
||||||
String key = stringifyForKey(thePartitionId) + "/" + theResourceType + "/" + theId;
|
String key = PartitionId.stringifyForKey(thePartitionId) + "/" + theResourceType + "/" + theId;
|
||||||
retVal = myPersistentIdCache.get(key, t -> resolveResourceIdentity(thePartitionId, theResourceType, theId));
|
retVal = myPersistentIdCache.get(key, t -> resolveResourceIdentity(thePartitionId, theResourceType, theId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -196,7 +195,7 @@ public class IdHelperService {
|
||||||
|
|
||||||
for (Iterator<String> idIterator = nextIds.iterator(); idIterator.hasNext(); ) {
|
for (Iterator<String> idIterator = nextIds.iterator(); idIterator.hasNext(); ) {
|
||||||
String nextId = idIterator.next();
|
String nextId = idIterator.next();
|
||||||
String key = stringifyForKey(thePartitionId) + "/" + nextResourceType + "/" + nextId;
|
String key = PartitionId.stringifyForKey(thePartitionId) + "/" + nextResourceType + "/" + nextId;
|
||||||
Long nextCachedPid = myPersistentIdCache.getIfPresent(key);
|
Long nextCachedPid = myPersistentIdCache.getIfPresent(key);
|
||||||
if (nextCachedPid != null) {
|
if (nextCachedPid != null) {
|
||||||
idIterator.remove();
|
idIterator.remove();
|
||||||
|
@ -221,7 +220,7 @@ public class IdHelperService {
|
||||||
Long pid = (Long) nextView[1];
|
Long pid = (Long) nextView[1];
|
||||||
retVal.add(new ResourcePersistentId(pid));
|
retVal.add(new ResourcePersistentId(pid));
|
||||||
|
|
||||||
String key = stringifyForKey(thePartitionId) + "/" + nextResourceType + "/" + forcedId;
|
String key = PartitionId.stringifyForKey(thePartitionId) + "/" + nextResourceType + "/" + forcedId;
|
||||||
myPersistentIdCache.put(key, pid);
|
myPersistentIdCache.put(key, pid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -407,14 +406,6 @@ public class IdHelperService {
|
||||||
.build();
|
.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static String stringifyForKey(PartitionId thePartitionId) {
|
|
||||||
String retVal = "(null)";
|
|
||||||
if (thePartitionId != null) {
|
|
||||||
retVal = thePartitionId.getPartitionIdStringOrNullString();
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isValidPid(IIdType theId) {
|
public static boolean isValidPid(IIdType theId) {
|
||||||
if (theId == null) {
|
if (theId == null) {
|
||||||
return false;
|
return false;
|
||||||
|
|
|
@ -30,6 +30,7 @@ import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionConfig;
|
import ca.uhn.fhir.jpa.model.config.PartitionConfig;
|
||||||
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
import ca.uhn.fhir.jpa.model.cross.ResourcePersistentId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.PartitionId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
|
@ -70,7 +71,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
@Lazy
|
@Lazy
|
||||||
public class SearchParamWithInlineReferencesExtractor {
|
public class SearchParamWithInlineReferencesExtractor {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamWithInlineReferencesExtractor.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamWithInlineReferencesExtractor.class);
|
||||||
|
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||||
|
protected EntityManager myEntityManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
private MatchResourceUrlService myMatchResourceUrlService;
|
private MatchResourceUrlService myMatchResourceUrlService;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -89,18 +91,17 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
private DaoSearchParamSynchronizer myDaoSearchParamSynchronizer;
|
private DaoSearchParamSynchronizer myDaoSearchParamSynchronizer;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
private IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||||
|
@Autowired
|
||||||
|
private PartitionConfig myPartitionConfig;
|
||||||
|
|
||||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
public void populateFromResource(ResourceIndexedSearchParams theParams, Date theUpdateTime, ResourceTable theEntity, IBaseResource theResource, ResourceIndexedSearchParams theExistingParams, RequestDetails theRequest) {
|
||||||
protected EntityManager myEntityManager;
|
|
||||||
|
|
||||||
public void populateFromResource(PartitionConfig thePartitionConfig, ResourceIndexedSearchParams theParams, Date theUpdateTime, ResourceTable theEntity, IBaseResource theResource, ResourceIndexedSearchParams theExistingParams, RequestDetails theRequest) {
|
|
||||||
extractInlineReferences(theResource, theRequest);
|
extractInlineReferences(theResource, theRequest);
|
||||||
|
|
||||||
mySearchParamExtractorService.extractFromResource(theRequest, theParams, theEntity, theResource, theUpdateTime, true);
|
mySearchParamExtractorService.extractFromResource(theEntity.getPartitionId(), theRequest, theParams, theEntity, theResource, theUpdateTime, true);
|
||||||
|
|
||||||
Set<Map.Entry<String, RuntimeSearchParam>> activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).entrySet();
|
Set<Map.Entry<String, RuntimeSearchParam>> activeSearchParams = mySearchParamRegistry.getActiveSearchParams(theEntity.getResourceType()).entrySet();
|
||||||
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.ENABLED) {
|
if (myDaoConfig.getIndexMissingFields() == DaoConfig.IndexEnabledEnum.ENABLED) {
|
||||||
theParams.findMissingSearchParams(thePartitionConfig, myDaoConfig.getModelConfig(), theEntity, activeSearchParams);
|
theParams.findMissingSearchParams(myPartitionConfig, myDaoConfig.getModelConfig(), theEntity, activeSearchParams);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -205,7 +206,6 @@ public class SearchParamWithInlineReferencesExtractor {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle references within the resource that are match URLs, for example references like "Patient?identifier=foo". These match URLs are resolved and replaced with the ID of the
|
* Handle references within the resource that are match URLs, for example references like "Patient?identifier=foo". These match URLs are resolved and replaced with the ID of the
|
||||||
* matching resource.
|
* matching resource.
|
||||||
|
|
|
@ -3,7 +3,6 @@ package ca.uhn.fhir.jpa.dao.r4;
|
||||||
import ca.uhn.fhir.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
|
||||||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionConfig;
|
import ca.uhn.fhir.jpa.model.config.PartitionConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
|
@ -81,7 +80,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
|
||||||
|
|
||||||
myPartitionConfig.setIncludePartitionInSearchHashes(new PartitionConfig().isIncludePartitionInSearchHashes());
|
myPartitionConfig.setIncludePartitionInSearchHashes(new PartitionConfig().isIncludePartitionInSearchHashes());
|
||||||
myPartitionConfig.setPartitioningEnabled(new PartitionConfig().isPartitioningEnabled());
|
myPartitionConfig.setPartitioningEnabled(new PartitionConfig().isPartitioningEnabled());
|
||||||
myPartitionConfig.setAllowReferencesAcrossPartitions(new PartitionConfig().isAllowReferencesAcrossPartitions());
|
myPartitionConfig.setAllowReferencesAcrossPartitions(new PartitionConfig().getAllowReferencesAcrossPartitions());
|
||||||
|
|
||||||
myInterceptorRegistry.unregisterInterceptorsIf(t -> t instanceof MyInterceptor);
|
myInterceptorRegistry.unregisterInterceptorsIf(t -> t instanceof MyInterceptor);
|
||||||
myInterceptor = null;
|
myInterceptor = null;
|
||||||
|
@ -140,7 +139,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate_CrossPartitionReference_ByPid_Allowed() {
|
public void testCreate_CrossPartitionReference_ByPid_Allowed() {
|
||||||
myPartitionConfig.setAllowReferencesAcrossPartitions(true);
|
myPartitionConfig.setAllowReferencesAcrossPartitions(PartitionConfig.CrossPartitionReferenceMode.ALLOWED_UNQUALIFIED);
|
||||||
|
|
||||||
// Create patient in partition 1
|
// Create patient in partition 1
|
||||||
addCreatePartition(myPartitionId, myPartitionDate);
|
addCreatePartition(myPartitionId, myPartitionDate);
|
||||||
|
@ -188,7 +187,7 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate_CrossPartitionReference_ByForcedId_Allowed() {
|
public void testCreate_CrossPartitionReference_ByForcedId_Allowed() {
|
||||||
myPartitionConfig.setAllowReferencesAcrossPartitions(true);
|
myPartitionConfig.setAllowReferencesAcrossPartitions(PartitionConfig.CrossPartitionReferenceMode.ALLOWED_UNQUALIFIED);
|
||||||
|
|
||||||
// Create patient in partition 1
|
// Create patient in partition 1
|
||||||
addCreatePartition(myPartitionId, myPartitionDate);
|
addCreatePartition(myPartitionId, myPartitionDate);
|
||||||
|
@ -238,8 +237,6 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate_SamePartitionReference_DefaultPartition_ByPid() {
|
public void testCreate_SamePartitionReference_DefaultPartition_ByPid() {
|
||||||
myPartitionConfig.setAllowReferencesAcrossPartitions(true);
|
|
||||||
|
|
||||||
// Create patient in partition NULL
|
// Create patient in partition NULL
|
||||||
addCreateNoPartitionId(myPartitionDate);
|
addCreateNoPartitionId(myPartitionDate);
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
|
@ -263,8 +260,6 @@ public class PartitioningR4Test extends BaseJpaR4SystemTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreate_SamePartitionReference_DefaultPartition_ByForcedId() {
|
public void testCreate_SamePartitionReference_DefaultPartition_ByForcedId() {
|
||||||
myPartitionConfig.setAllowReferencesAcrossPartitions(true);
|
|
||||||
|
|
||||||
// Create patient in partition NULL
|
// Create patient in partition NULL
|
||||||
addCreateNoPartitionId(myPartitionDate);
|
addCreateNoPartitionId(myPartitionDate);
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
|
|
|
@ -6,7 +6,7 @@ package ca.uhn.fhir.jpa.model.config;
|
||||||
public class PartitionConfig {
|
public class PartitionConfig {
|
||||||
|
|
||||||
private boolean myPartitioningEnabled = false;
|
private boolean myPartitioningEnabled = false;
|
||||||
private boolean myAllowReferencesAcrossPartitions = false;
|
private CrossPartitionReferenceMode myAllowReferencesAcrossPartitions = CrossPartitionReferenceMode.NOT_ALLOWED;
|
||||||
private boolean myIncludePartitionInSearchHashes = true;
|
private boolean myIncludePartitionInSearchHashes = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -54,20 +54,36 @@ public class PartitionConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should resources references be permitted to cross partition boundaries. Default is <code>false</code>.
|
* Should resources references be permitted to cross partition boundaries. Default is {@link CrossPartitionReferenceMode#NOT_ALLOWED}.
|
||||||
*
|
*
|
||||||
* @since 5.0.0
|
* @since 5.0.0
|
||||||
*/
|
*/
|
||||||
public boolean isAllowReferencesAcrossPartitions() {
|
public CrossPartitionReferenceMode getAllowReferencesAcrossPartitions() {
|
||||||
return myAllowReferencesAcrossPartitions;
|
return myAllowReferencesAcrossPartitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Should resources references be permitted to cross partition boundaries. Default is <code>false</code>.
|
* Should resources references be permitted to cross partition boundaries. Default is {@link CrossPartitionReferenceMode#NOT_ALLOWED}.
|
||||||
*
|
*
|
||||||
* @since 5.0.0
|
* @since 5.0.0
|
||||||
*/
|
*/
|
||||||
public void setAllowReferencesAcrossPartitions(boolean theAllowReferencesAcrossPartitions) {
|
public void setAllowReferencesAcrossPartitions(CrossPartitionReferenceMode theAllowReferencesAcrossPartitions) {
|
||||||
myAllowReferencesAcrossPartitions = theAllowReferencesAcrossPartitions;
|
myAllowReferencesAcrossPartitions = theAllowReferencesAcrossPartitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public enum CrossPartitionReferenceMode {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* References between resources are not allowed to cross partition boundaries
|
||||||
|
*/
|
||||||
|
NOT_ALLOWED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* References can cross partition boundaries, in a way that hides the existence of partitions to the end user
|
||||||
|
*/
|
||||||
|
ALLOWED_UNQUALIFIED
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,4 +71,15 @@ public class PartitionId implements Cloneable {
|
||||||
public String getPartitionIdStringOrNullString() {
|
public String getPartitionIdStringOrNullString() {
|
||||||
return defaultIfNull(myPartitionId, "null").toString();
|
return defaultIfNull(myPartitionId, "null").toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a string representation suitable for use as a cache key. Null aware.
|
||||||
|
*/
|
||||||
|
public static String stringifyForKey(PartitionId thePartitionId) {
|
||||||
|
String retVal = "(null)";
|
||||||
|
if (thePartitionId != null) {
|
||||||
|
retVal = thePartitionId.getPartitionIdStringOrNullString();
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.jpa.model.config.PartitionConfig;
|
||||||
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
import ca.uhn.fhir.jpa.model.cross.IResourceLookup;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
import ca.uhn.fhir.jpa.model.search.StorageProcessingMessage;
|
||||||
|
@ -64,6 +65,8 @@ public class SearchParamExtractorService {
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
@Autowired
|
@Autowired
|
||||||
private ISearchParamRegistry mySearchParamRegistry;
|
private ISearchParamRegistry mySearchParamRegistry;
|
||||||
|
@Autowired
|
||||||
|
private PartitionConfig myPartitionConfig;
|
||||||
@Autowired(required = false)
|
@Autowired(required = false)
|
||||||
private IResourceLinkResolver myResourceLinkResolver;
|
private IResourceLinkResolver myResourceLinkResolver;
|
||||||
|
|
||||||
|
@ -71,14 +74,14 @@ public class SearchParamExtractorService {
|
||||||
* This method is responsible for scanning a resource for all of the search parameter instances. I.e. for all search parameters defined for
|
* This method is responsible for scanning a resource for all of the search parameter instances. I.e. for all search parameters defined for
|
||||||
* a given resource type, it extracts the associated indexes and populates {@literal theParams}.
|
* a given resource type, it extracts the associated indexes and populates {@literal theParams}.
|
||||||
*/
|
*/
|
||||||
public void extractFromResource(RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, ResourceTable theEntity, IBaseResource theResource, Date theUpdateTime, boolean theFailOnInvalidReference) {
|
public void extractFromResource(PartitionId thePartitionId, RequestDetails theRequestDetails, ResourceIndexedSearchParams theParams, ResourceTable theEntity, IBaseResource theResource, Date theUpdateTime, boolean theFailOnInvalidReference) {
|
||||||
IBaseResource resource = normalizeResource(theResource);
|
IBaseResource resource = normalizeResource(theResource);
|
||||||
|
|
||||||
// All search parameter types except Reference
|
// All search parameter types except Reference
|
||||||
extractSearchIndexParameters(theRequestDetails, theParams, resource, theEntity);
|
extractSearchIndexParameters(theRequestDetails, theParams, resource, theEntity);
|
||||||
|
|
||||||
// Reference search parameters
|
// Reference search parameters
|
||||||
extractResourceLinks(theParams, theEntity, resource, theUpdateTime, theFailOnInvalidReference, theRequestDetails);
|
extractResourceLinks(thePartitionId, theParams, theEntity, resource, theUpdateTime, theFailOnInvalidReference, theRequestDetails);
|
||||||
|
|
||||||
theParams.setUpdatedTime(theUpdateTime);
|
theParams.setUpdatedTime(theUpdateTime);
|
||||||
}
|
}
|
||||||
|
@ -155,7 +158,7 @@ public class SearchParamExtractorService {
|
||||||
return theResource;
|
return theResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void extractResourceLinks(ResourceIndexedSearchParams theParams, ResourceTable theEntity, IBaseResource theResource, Date theUpdateTime, boolean theFailOnInvalidReference, RequestDetails theRequest) {
|
private void extractResourceLinks(PartitionId thePartitionId, ResourceIndexedSearchParams theParams, ResourceTable theEntity, IBaseResource theResource, Date theUpdateTime, boolean theFailOnInvalidReference, RequestDetails theRequest) {
|
||||||
String resourceName = myContext.getResourceDefinition(theResource).getName();
|
String resourceName = myContext.getResourceDefinition(theResource).getName();
|
||||||
|
|
||||||
ISearchParamExtractor.SearchParamSet<PathAndRef> refs = mySearchParamExtractor.extractResourceLinks(theResource);
|
ISearchParamExtractor.SearchParamSet<PathAndRef> refs = mySearchParamExtractor.extractResourceLinks(theResource);
|
||||||
|
@ -164,13 +167,13 @@ public class SearchParamExtractorService {
|
||||||
Map<String, IResourceLookup> resourceIdToResolvedTarget = new HashMap<>();
|
Map<String, IResourceLookup> resourceIdToResolvedTarget = new HashMap<>();
|
||||||
for (PathAndRef nextPathAndRef : refs) {
|
for (PathAndRef nextPathAndRef : refs) {
|
||||||
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(resourceName, nextPathAndRef.getSearchParamName());
|
RuntimeSearchParam searchParam = mySearchParamRegistry.getActiveSearchParam(resourceName, nextPathAndRef.getSearchParamName());
|
||||||
extractResourceLinks(theParams, theEntity, theUpdateTime, searchParam, nextPathAndRef, theFailOnInvalidReference, theRequest, resourceIdToResolvedTarget);
|
extractResourceLinks(thePartitionId, theParams, theEntity, theUpdateTime, searchParam, nextPathAndRef, theFailOnInvalidReference, theRequest, resourceIdToResolvedTarget);
|
||||||
}
|
}
|
||||||
|
|
||||||
theEntity.setHasLinks(theParams.myLinks.size() > 0);
|
theEntity.setHasLinks(theParams.myLinks.size() > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void extractResourceLinks(ResourceIndexedSearchParams theParams, ResourceTable theEntity, Date theUpdateTime, RuntimeSearchParam theRuntimeSearchParam, PathAndRef thePathAndRef, boolean theFailOnInvalidReference, RequestDetails theRequest, Map<String, IResourceLookup> theResourceIdToResolvedTarget) {
|
private void extractResourceLinks(PartitionId thePartitionId, ResourceIndexedSearchParams theParams, ResourceTable theEntity, Date theUpdateTime, RuntimeSearchParam theRuntimeSearchParam, PathAndRef thePathAndRef, boolean theFailOnInvalidReference, RequestDetails theRequest, Map<String, IResourceLookup> theResourceIdToResolvedTarget) {
|
||||||
IBaseReference nextReference = thePathAndRef.getRef();
|
IBaseReference nextReference = thePathAndRef.getRef();
|
||||||
IIdType nextId = nextReference.getReferenceElement();
|
IIdType nextId = nextReference.getReferenceElement();
|
||||||
String path = thePathAndRef.getPath();
|
String path = thePathAndRef.getPath();
|
||||||
|
@ -255,7 +258,7 @@ public class SearchParamExtractorService {
|
||||||
if (theFailOnInvalidReference) {
|
if (theFailOnInvalidReference) {
|
||||||
|
|
||||||
myResourceLinkResolver.validateTypeOrThrowException(type);
|
myResourceLinkResolver.validateTypeOrThrowException(type);
|
||||||
resourceLink = resolveTargetAndCreateResourceLinkOrReturnNull(theEntity, theUpdateTime, theRuntimeSearchParam, path, thePathAndRef, nextId, typeString, type, nextReference, theRequest, theResourceIdToResolvedTarget);
|
resourceLink = resolveTargetAndCreateResourceLinkOrReturnNull(thePartitionId, theEntity, theUpdateTime, theRuntimeSearchParam, path, thePathAndRef, nextId, typeString, type, nextReference, theRequest, theResourceIdToResolvedTarget);
|
||||||
if (resourceLink == null) {
|
if (resourceLink == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -272,7 +275,7 @@ public class SearchParamExtractorService {
|
||||||
theParams.myLinks.add(resourceLink);
|
theParams.myLinks.add(resourceLink);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ResourceLink resolveTargetAndCreateResourceLinkOrReturnNull(ResourceTable theEntity, Date theUpdateTime, RuntimeSearchParam nextSpDef, String theNextPathsUnsplit, PathAndRef nextPathAndRef, IIdType theNextId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest, Map<String, IResourceLookup> theResourceIdToResolvedTarget) {
|
private ResourceLink resolveTargetAndCreateResourceLinkOrReturnNull(PartitionId thePartitionId, ResourceTable theEntity, Date theUpdateTime, RuntimeSearchParam nextSpDef, String theNextPathsUnsplit, PathAndRef nextPathAndRef, IIdType theNextId, String theTypeString, Class<? extends IBaseResource> theType, IBaseReference theReference, RequestDetails theRequest, Map<String, IResourceLookup> theResourceIdToResolvedTarget) {
|
||||||
/*
|
/*
|
||||||
* We keep a cache of resolved target resources. This is good since for some resource types, there
|
* We keep a cache of resolved target resources. This is good since for some resource types, there
|
||||||
* are multiple search parameters that map to the same element path within a resource (e.g.
|
* are multiple search parameters that map to the same element path within a resource (e.g.
|
||||||
|
@ -280,16 +283,22 @@ public class SearchParamExtractorService {
|
||||||
* target any more times than we have to.
|
* target any more times than we have to.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
IResourceLookup targetResource = theResourceIdToResolvedTarget.get(theNextId.getValue());
|
PartitionId targetPartitionId = thePartitionId;
|
||||||
|
if (myPartitionConfig.isPartitioningEnabled() && myPartitionConfig.getAllowReferencesAcrossPartitions() == PartitionConfig.CrossPartitionReferenceMode.ALLOWED_UNQUALIFIED) {
|
||||||
|
targetPartitionId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
String key = PartitionId.stringifyForKey(targetPartitionId) + "/" + theNextId.getValue();
|
||||||
|
IResourceLookup targetResource = theResourceIdToResolvedTarget.get(key);
|
||||||
if (targetResource == null) {
|
if (targetResource == null) {
|
||||||
targetResource = myResourceLinkResolver.findTargetResource(nextSpDef, theNextPathsUnsplit, theNextId, theTypeString, theType, theReference, theRequest);
|
targetResource = myResourceLinkResolver.findTargetResource(targetPartitionId, nextSpDef, theNextPathsUnsplit, theNextId, theTypeString, theType, theReference, theRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetResource == null) {
|
if (targetResource == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
theResourceIdToResolvedTarget.put(theNextId.getValue(), targetResource);
|
theResourceIdToResolvedTarget.put(key, targetResource);
|
||||||
|
|
||||||
String targetResourceType = targetResource.getResourceType();
|
String targetResourceType = targetResource.getResourceType();
|
||||||
Long targetResourcePid = targetResource.getResourceId();
|
Long targetResourcePid = targetResource.getResourceId();
|
||||||
|
|
|
@ -39,7 +39,7 @@ public class IndexedSearchParamExtractor {
|
||||||
String resourceType = myContext.getResourceDefinition(theResource).getName();
|
String resourceType = myContext.getResourceDefinition(theResource).getName();
|
||||||
entity.setResourceType(resourceType);
|
entity.setResourceType(resourceType);
|
||||||
ResourceIndexedSearchParams resourceIndexedSearchParams = new ResourceIndexedSearchParams();
|
ResourceIndexedSearchParams resourceIndexedSearchParams = new ResourceIndexedSearchParams();
|
||||||
mySearchParamExtractorService.extractFromResource(theRequest, resourceIndexedSearchParams, entity, theResource, theResource.getMeta().getLastUpdated(), false);
|
mySearchParamExtractorService.extractFromResource(null, theRequest, resourceIndexedSearchParams, entity, theResource, theResource.getMeta().getLastUpdated(), false);
|
||||||
return resourceIndexedSearchParams;
|
return resourceIndexedSearchParams;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,6 @@ import ca.uhn.fhir.jpa.searchparam.extractor.ResourceIndexedSearchParams;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
public class SearchParamMatcher {
|
public class SearchParamMatcher {
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -33,9 +32,7 @@ public class SearchParamMatcher {
|
||||||
private InMemoryResourceMatcher myInMemoryResourceMatcher;
|
private InMemoryResourceMatcher myInMemoryResourceMatcher;
|
||||||
|
|
||||||
public InMemoryMatchResult match(String theCriteria, IBaseResource theResource, RequestDetails theRequest) {
|
public InMemoryMatchResult match(String theCriteria, IBaseResource theResource, RequestDetails theRequest) {
|
||||||
|
|
||||||
ResourceIndexedSearchParams resourceIndexedSearchParams = myIndexedSearchParamExtractor.extractIndexedSearchParams(theResource, theRequest);
|
ResourceIndexedSearchParams resourceIndexedSearchParams = myIndexedSearchParamExtractor.extractIndexedSearchParams(theResource, theRequest);
|
||||||
|
|
||||||
return myInMemoryResourceMatcher.match(theCriteria, theResource, resourceIndexedSearchParams);
|
return myInMemoryResourceMatcher.match(theCriteria, theResource, resourceIndexedSearchParams);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue