Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Possible duplication of resources on conditional create/update #4598

Open
wants to merge 71 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
71 commits
Select commit Hold shift + click to select a range
078dcd9
One more fix for #4467
jamesagnew Jan 26, 2023
1a9b749
Enabling massIngestionMode causes incomplete resource deletion (#4476)
epeartree Jan 30, 2023
40508a0
Provide the capability to request that the name of the subscription m…
epeartree Jan 30, 2023
882f22f
Change visibility of migration method (#4471)
nathandoef Jan 31, 2023
67ace43
Fix subscription validation not to validate partition ID when invoked…
lukedegruchy Jan 31, 2023
dd8c8a3
Reindex batch job fails when processing deleted resources. (#4482)
epeartree Feb 1, 2023
efae3b5
cleaning up checkstyle files (#4470)
markiantorno Feb 1, 2023
b1770ab
Bump core to 5.6.881 (#4496)
dotasek Feb 2, 2023
0a213a5
Issue 4486 mdm inconsistent possible match score values (#4487)
jmarchionatto Feb 2, 2023
740fec9
Revert "cleaning up checkstyle files (#4470)"
markiantorno Feb 2, 2023
c642853
core version fix
markiantorno Feb 2, 2023
a855af5
Loosen rules for id helper
tadgh Feb 2, 2023
df83d05
Merge branch 'rel_6_4' of github.com:hapifhir/hapi-fhir into rel_6_4
tadgh Feb 2, 2023
7d554d5
License
tadgh Feb 3, 2023
0996124
fix batch2 reduction step (#4499)
TipzCM Feb 3, 2023
2a963ac
Scheduled batch 2 bulk export job and binary delete (#4492)
lukedegruchy Feb 6, 2023
33f6ed3
Change bulk import test for valueUri type (#4503)
samguntersmilecdr Feb 6, 2023
e160325
CVE resolutions (#4513)
tadgh Feb 6, 2023
d08995a
Add check in scanner (#4518)
tadgh Feb 7, 2023
ca21abf
4516 create hapi fhir cli command to clear stale lock entries (#4517)
tadgh Feb 7, 2023
85ecbf1
Unable to Expunge CodeSystem (#4507)
isaacwen Feb 7, 2023
e724040
New line::
tadgh Feb 8, 2023
697bd27
Update to documentation regarding narrative generation; (#4521)
epeartree Feb 8, 2023
f321573
changed what score is set for mdmlinks that created new golden resour…
longma1 Feb 8, 2023
71ea1b4
REVERT: change to operationoutcome.html
tadgh Feb 8, 2023
6b3b954
trying to fix BulkDataExportTest testGroupBulkExportNotInGroup_DoesNo…
TipzCM Feb 8, 2023
b4778f4
fix build (#4530)
nathandoef Feb 9, 2023
3d9a318
Making narrative_generation.md reference an html snippet (#4531)
epeartree Feb 9, 2023
53252b8
fixed the issue of meta.source field inconsistently populated in subs…
Qingyixia Feb 9, 2023
fe078c2
4441 rel 6 4 bad references creation bug (#4519)
TipzCM Feb 9, 2023
f3847b1
fixed channel import null pointer exception from null header (#4534)
samguntersmilecdr Feb 9, 2023
e99aebd
Revert "fixed the issue of meta.source field inconsistently populated…
tadgh Feb 9, 2023
03ccf3e
Better error handling for when channel type is not supported (#4538)
KGJ-software Feb 10, 2023
fb0512f
Avoid logging message payloads that contain sensitive data (#4537)
michaelabuckley Feb 10, 2023
9754a72
Bulk Export Bug With Many Resources and Low Max File Size (#4506)
nathandoef Feb 10, 2023
9578610
bump ver
tadgh Feb 11, 2023
a0e4c29
License updates'
tadgh Feb 11, 2023
acfde15
Downgrade dep'
tadgh Feb 14, 2023
b2644c1
Updating version to: 6.4.1 post release.
markiantorno Feb 16, 2023
f08823b
Add javadocs and sources to our serviceloaders
tadgh Feb 17, 2023
384bea1
Merge branch 'rel_6_4' of github.com:hapifhir/hapi-fhir into rel_6_4
tadgh Feb 17, 2023
96855fb
Reset version
tadgh Feb 17, 2023
529e478
Change parent
tadgh Feb 17, 2023
23b7acf
Remove bumped version
tadgh Feb 17, 2023
71fa4f2
License fixes, new parent
tadgh Feb 17, 2023
827bbba
Updating version to: 6.4.1 post release.
markiantorno Feb 17, 2023
6b6f1e2
Fix bad creation of versionenum
tadgh Feb 17, 2023
8698abf
typedbundleprovider getallresources override (#4552)
Capt-Mac Feb 16, 2023
bbe437a
Add backport info
tadgh Feb 23, 2023
2c34bf0
Upgrade core to 5.6.97, make adjustments in hapi-fhir, and ensure tha…
lukedegruchy Feb 23, 2023
baa494c
Fix up dal test
tadgh Feb 24, 2023
b2ebdec
Address leftover code review feedback from the upgrade to core 5.6.97…
lukedegruchy Feb 24, 2023
eee6128
Exclude pinned core deps
tadgh Feb 24, 2023
4af1a50
Force pin structs
tadgh Feb 24, 2023
9ede6b3
Add model changes to IBaseCoding and related changes (#4587)
lukedegruchy Feb 24, 2023
9fe44ee
Fix changelog
tadgh Feb 24, 2023
79692df
Tidy metadata
tadgh Feb 24, 2023
d192bce
Disable intermittently failing tests. (#4593)
lukedegruchy Feb 25, 2023
d4a5153
rename tests to IT
tadgh Feb 25, 2023
2d4b8d9
Disable more intermittently failing tests (#4595)
lukedegruchy Feb 25, 2023
0ada4e7
ITify
tadgh Feb 25, 2023
97d6e30
Merge branch 'rel_6_4' of github.com:hapifhir/hapi-fhir into rel_6_4
tadgh Feb 25, 2023
6915b85
Disable yet another intermittently failing tests. (#4596)
lukedegruchy Feb 25, 2023
bd83f33
disable
tadgh Feb 25, 2023
49c548d
disables
tadgh Feb 26, 2023
b227005
Merge branch 'rel_6_4' of github.com:hapifhir/hapi-fhir into rel_6_4
tadgh Feb 26, 2023
69f2527
disables
tadgh Feb 26, 2023
31610cd
Updating version to: 6.4.2 post release.
markiantorno Feb 26, 2023
e14b289
fix version
tadgh Feb 27, 2023
1b549d8
Creating test to reproduce the issue.
Feb 27, 2023
4840a73
partial solution implementation.
Feb 27, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Prev Previous commit
Next Next commit
4441 rel 6 4 bad references creation bug (#4519)
* adding a test

* fail in the case of ref enforce on type and on write and autocreate are all true

* update to code

* removing a line

* cleanup

* removing check on urn

* changing just to trigger a build

* adding a comment to the pom

* updating test for better information

---------

Co-authored-by: leif stawnyczy <[email protected]>
  • Loading branch information
TipzCM and leif stawnyczy committed Feb 9, 2023
commit fe078c28846873814265f381ff5f484b245a3944
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
type: fix
issue: 4441
title: "Creating a resource with an invalid embedded resource reference
would not fail. Even if IsEnforceReferentialIntegrityOnWrite was enabled.
This has been fixed, and invalid references will throw.
"
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package ca.uhn.fhir.jpa.dao.index;

import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
import org.hl7.fhir.instance.model.api.IBaseResource;

public class ExtractInlineReferenceParams {
private IBaseResource myResource;
private TransactionDetails myTransactionDetails;
private RequestDetails myRequestDetails;
private boolean myFailOnInvalidReferences;

public ExtractInlineReferenceParams(
IBaseResource theResource,
TransactionDetails theTransactionDetails,
RequestDetails theRequest
) {
myResource = theResource;
myTransactionDetails = theTransactionDetails;
myRequestDetails = theRequest;
}

public IBaseResource getResource() {
return myResource;
}

public void setResource(IBaseResource theResource) {
myResource = theResource;
}

public TransactionDetails getTransactionDetails() {
return myTransactionDetails;
}

public void setTransactionDetails(TransactionDetails theTransactionDetails) {
myTransactionDetails = theTransactionDetails;
}

public RequestDetails getRequestDetails() {
return myRequestDetails;
}

public void setRequestDetails(RequestDetails theRequestDetails) {
myRequestDetails = theRequestDetails;
}

public boolean isFailOnInvalidReferences() {
return myFailOnInvalidReferences;
}

public void setFailOnInvalidReferences(boolean theFailOnInvalidReferences) {
myFailOnInvalidReferences = theFailOnInvalidReferences;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ public void setSearchParamRegistry(ISearchParamRegistry theSearchParamRegistry)
}

public void populateFromResource(RequestPartitionId theRequestPartitionId, ResourceIndexedSearchParams theParams, TransactionDetails theTransactionDetails, ResourceTable theEntity, IBaseResource theResource, ResourceIndexedSearchParams theExistingParams, RequestDetails theRequest, boolean theFailOnInvalidReference) {
extractInlineReferences(theResource, theTransactionDetails, theRequest);
ExtractInlineReferenceParams theExtractParams = new ExtractInlineReferenceParams(theResource, theTransactionDetails, theRequest);
theExtractParams.setFailOnInvalidReferences(theFailOnInvalidReference);
extractInlineReferences(theExtractParams);

mySearchParamExtractorService.extractFromResource(theRequestPartitionId, theRequest, theParams, theExistingParams, theEntity, theResource, theTransactionDetails, theFailOnInvalidReference);

Expand Down Expand Up @@ -188,16 +190,32 @@ public void setContext(FhirContext theContext) {
myContext = theContext;
}

@Deprecated
public void extractInlineReferences(
IBaseResource theResource,
TransactionDetails theTransactionDetails,
RequestDetails theRequest
) {
extractInlineReferences(new ExtractInlineReferenceParams(theResource, theTransactionDetails, theRequest));
}

/**
* 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.
*
* This method is *only* called from UPDATE path
*/
public void extractInlineReferences(IBaseResource theResource, TransactionDetails theTransactionDetails, RequestDetails theRequest) {
public void extractInlineReferences(ExtractInlineReferenceParams theParams) {
if (!myDaoConfig.isAllowInlineMatchUrlReferences()) {
return;
}
IBaseResource resource = theParams.getResource();
RequestDetails theRequest = theParams.getRequestDetails();
TransactionDetails theTransactionDetails = theParams.getTransactionDetails();

FhirTerser terser = myContext.newTerser();
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(theResource, IBaseReference.class);
List<IBaseReference> allRefs = terser.getAllPopulatedChildElementsOfType(resource, IBaseReference.class);
for (IBaseReference nextRef : allRefs) {
IIdType nextId = nextRef.getReferenceElement();
String nextIdText = nextId.getValue();
Expand Down Expand Up @@ -229,7 +247,6 @@ public void extractInlineReferences(IBaseResource theResource, TransactionDetail

JpaPid match;
if (matches.isEmpty()) {

Optional<IBasePersistedResource> placeholderOpt = myDaoResourceLinkResolver.createPlaceholderTargetIfConfiguredToDoSo(matchResourceType, nextRef, null, theRequest, theTransactionDetails);
if (placeholderOpt.isPresent()) {
match = (JpaPid) placeholderOpt.get().getPersistentId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1818,10 +1818,11 @@ private void extractResourceLinkFromReference(SearchParamSet<PathAndRef> thePara
nextId = valueRef.getResource().getIdElement();
}

if (nextId == null ||
nextId.isEmpty() ||
nextId.getValue().startsWith("urn:")) {
// Ignore placeholder references
if (
nextId == null ||
nextId.isEmpty()
) {
// Ignore placeholder references that are blank
} else if (!theWantLocalReferences && nextId.getValue().startsWith("#")) {
// Ignore local refs unless we specifically want them
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,8 +105,10 @@ public void extractFromResource(RequestPartitionId theRequestPartitionId, Reques
}

/**
* 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}.
* 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}.
*/
public void extractFromResource(RequestPartitionId theRequestPartitionId, RequestDetails theRequestDetails, ResourceIndexedSearchParams theNewParams, ResourceIndexedSearchParams theExistingParams, ResourceTable theEntity, IBaseResource theResource, TransactionDetails theTransactionDetails, boolean theFailOnInvalidReference) {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import java.util.stream.Collectors;
import java.util.concurrent.TimeUnit;

import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.awaitility.Awaitility.await;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
Expand Down Expand Up @@ -164,7 +165,9 @@ public void export_shouldExportPatientResource_whenTypeParameterOmitted() throws
HttpGet statusGet = new HttpGet(pollingLocation);
String expectedOriginalUrl = myClient.getServerBase() + "/$export";
try (CloseableHttpResponse status = ourHttpClient.execute(statusGet)) {
assertEquals(200, status.getStatusLine().getStatusCode());
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
assertTrue(isNotBlank(responseContent), responseContent);

ourLog.info(responseContent);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import ca.uhn.fhir.i18n.HapiLocalizer;
import ca.uhn.fhir.i18n.Msg;
import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
import ca.uhn.fhir.jpa.entity.Search;
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
Expand All @@ -12,6 +13,7 @@
import ca.uhn.fhir.jpa.model.util.UcumServiceUtil;
import ca.uhn.fhir.jpa.provider.BaseResourceProviderR4Test;
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
import ca.uhn.fhir.jpa.term.ZipCollectionBuilder;
import ca.uhn.fhir.jpa.test.config.TestR4Config;
import ca.uhn.fhir.jpa.util.QueryParameterUtils;
Expand All @@ -27,6 +29,7 @@
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.api.SearchTotalModeEnum;
import ca.uhn.fhir.rest.api.SummaryEnum;
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
import ca.uhn.fhir.rest.client.apache.ResourceEntity;
import ca.uhn.fhir.rest.client.api.IClientInterceptor;
import ca.uhn.fhir.rest.client.api.IGenericClient;
Expand Down Expand Up @@ -309,12 +312,10 @@ public void createResourceSearchParameter_withExpressionMetaSecurity_succeeds()

assertNotNull(id);
assertEquals("resource-security", id.getIdPart());

}

@Test
public void createSearchParameter_with2Expressions_succeeds() {

SearchParameter searchParameter = new SearchParameter();

searchParameter.setStatus(Enumerations.PublicationStatus.ACTIVE);
Expand All @@ -326,7 +327,6 @@ public void createSearchParameter_with2Expressions_succeeds() {
MethodOutcome result = myClient.create().resource(searchParameter).execute();

assertEquals(true, result.getCreated());

}

@Test
Expand Down Expand Up @@ -454,7 +454,6 @@ public void testSearchWithDateInvalid() throws IOException {
assertThat(output, containsString(MSG_PREFIX_INVALID_FORMAT + "&quot;&gt;&quot;"));
assertEquals(400, resp.getStatusLine().getStatusCode());
}

}


Expand Down Expand Up @@ -911,7 +910,7 @@ private List<String> searchAndReturnUnqualifiedVersionlessIdValues(String uri) t

@Test
@Disabled
public void test() throws IOException {
public void testMakingQuery() throws IOException {
HttpGet get = new HttpGet(myServerBase + "/QuestionnaireResponse?_count=50&status=completed&questionnaire=ARIncenterAbsRecord&_lastUpdated=%3E" + UrlUtil.escapeUrlParam("=2018-01-01") + "&context.organization=O3435");
ourLog.info("*** MAKING QUERY");
ourHttpClient.execute(get);
Expand Down Expand Up @@ -7556,6 +7555,113 @@ private void verifySinceBehaviourWhenQueriedDateBeforeTwoUpdatedDates(Long patie
assertTrue(resultIds.contains("Patient/" + patientId + "/_history/2"));
}


private static class CreateResourceInput {
boolean IsEnforceRefOnWrite;
boolean IsEnforceRefOnType;
boolean IsAutoCreatePlaceholderReferences;

public CreateResourceInput(
boolean theEnforceRefOnWrite,
boolean theEnforceRefOnType,
boolean theAutoCreatePlaceholders
) {
IsEnforceRefOnWrite = theEnforceRefOnWrite;
IsEnforceRefOnType = theEnforceRefOnType;
IsAutoCreatePlaceholderReferences = theAutoCreatePlaceholders;
}

@Override
public String toString() {
return "IsEnforceReferentialIntegrityOnWrite : "
+ IsEnforceRefOnWrite + "\n"
+ "IsEnforceReferenceTargetTypes : "
+ IsEnforceRefOnType + "\n"
+ "IsAutoCreatePlaceholderReferenceTargets : "
+ IsAutoCreatePlaceholderReferences + "\n";
}
}

private static List<CreateResourceInput> createResourceParameters() {
boolean[] bools = new boolean[] { true, false };
List<CreateResourceInput> input = new ArrayList<>();
for (boolean bool : bools) {
for (boolean bool2 : bools) {
for (boolean bool3 : bools) {
input.add(new CreateResourceInput(bool, bool2, bool3));
}
}
}
return input;
}

@ParameterizedTest
@MethodSource("createResourceParameters")
public void createResource_refIntegrityOnWriteAndRefTargetTypes_throws(CreateResourceInput theInput) {
ourLog.info(
String.format("Test case : \n%s", theInput.toString())
);

String patientStr = """
{
"resourceType": "Patient",
"managingOrganization": {
"reference": "urn:uuid:d8080e87-1842-46b4-aea0-b65803bc2897"
}
}
""";
IParser parser = myFhirContext.newJsonParser();
Patient patient = parser.parseResource(Patient.class, patientStr);

{
List<IBaseResource> orgs = myOrganizationDao
.search(new SearchParameterMap(), new SystemRequestDetails())
.getAllResources();

assertTrue(orgs == null || orgs.isEmpty());
}

boolean isEnforceRefOnWrite = myDaoConfig.isEnforceReferentialIntegrityOnWrite();
boolean isEnforceRefTargetTypes = myDaoConfig.isEnforceReferenceTargetTypes();
boolean isAutoCreatePlaceholderReferences = myDaoConfig.isAutoCreatePlaceholderReferenceTargets();

try {
// allows resources to be created even if they have local resources that do not exist
myDaoConfig.setEnforceReferentialIntegrityOnWrite(theInput.IsEnforceRefOnWrite);
// ensures target references are using the correct resource type
myDaoConfig.setEnforceReferenceTargetTypes(theInput.IsEnforceRefOnType);
// will create the resource if it does not already exist
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(theInput.IsAutoCreatePlaceholderReferences);

// should fail
DaoMethodOutcome result = myPatientDao.create(patient, new SystemRequestDetails());

// a bad reference can never create a new resource
{
List<IBaseResource> orgs = myOrganizationDao
.search(new SearchParameterMap(), new SystemRequestDetails())
.getAllResources();

assertTrue(orgs == null || orgs.isEmpty());
}

// only if all 3 are true do we expect this to fail
assertFalse(
theInput.IsAutoCreatePlaceholderReferences
&& theInput.IsEnforceRefOnType
&& theInput.IsEnforceRefOnWrite
);
} catch (InvalidRequestException ex) {
assertTrue(ex.getMessage().contains(
"Invalid resource reference"
), ex.getMessage());
} finally {
myDaoConfig.setEnforceReferentialIntegrityOnWrite(isEnforceRefOnWrite);
myDaoConfig.setEnforceReferenceTargetTypes(isEnforceRefTargetTypes);
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(isAutoCreatePlaceholderReferences);
}
}

@Test
public void searchResource_bySourceWithPreserveRequestIdDisabled_isSuccess() {
String sourceUri = "http:https://acme.org";
Expand Down Expand Up @@ -8085,5 +8191,4 @@ private static Stream<Arguments> provideParameters() {
);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -1630,7 +1630,7 @@ public void setEnforceReferentialIntegrityOnDelete(boolean theEnforceReferential
* <p>
* For example, if a patient contains a reference to managing organization <code>Organization/FOO</code>
* but FOO is not a valid ID for an organization on the server, the operation will be blocked unless
* this propery has been set to <code>false</code>
* this property has been set to <code>false</code>
* </p>
* <p>
* This property can cause confusing results for clients of the server since searches, includes,
Expand All @@ -1648,7 +1648,7 @@ public boolean isEnforceReferentialIntegrityOnWrite() {
* <p>
* For example, if a patient contains a reference to managing organization <code>Organization/FOO</code>
* but FOO is not a valid ID for an organization on the server, the operation will be blocked unless
* this propery has been set to <code>false</code>
* this property has been set to <code>false</code>
* </p>
* <p>
* This property can cause confusing results for clients of the server since searches, includes,
Expand Down
1 change: 1 addition & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<project xmlns:xsi="http:https://www.w3.org/2001/XMLSchema-instance" xmlns="http:https://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http:https://maven.apache.org/POM/4.0.0 http:https://maven.apache.org/maven-v4_0_0.xsd">

<!-- the version info -->
<modelVersion>4.0.0</modelVersion>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
Expand Down