Streamline ValidationSupportChain (#6508)
* Tests passing * Cleanup * Cleanupo * Test fixes * Test fix * Cleanup * Update hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java Co-authored-by: Ken Stevens <khstevens@gmail.com> * Update hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java Co-authored-by: Ken Stevens <khstevens@gmail.com> * Update hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/ValidationSupportChain.java Co-authored-by: Ken Stevens <khstevens@gmail.com> * Account for review comments * Spotless * Compile fix * Test fixes * Test cleanup * Test cleanup * Test fixes * Resolve fixme * Test fix * Test fixes * Test fixes * Test fixes * Fix * Test fix * Test fixes * Test fixes * HAPI version bump * Try to address intermittent --------- Co-authored-by: Ken Stevens <khstevens@gmail.com>
This commit is contained in:
parent
061390d76b
commit
362dc095ac
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -713,6 +713,8 @@ public class FhirContext {
|
||||||
"org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport";
|
"org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport";
|
||||||
String commonCodeSystemsSupportType =
|
String commonCodeSystemsSupportType =
|
||||||
"org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService";
|
"org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService";
|
||||||
|
String snapshotGeneratingType =
|
||||||
|
"org.hl7.fhir.common.hapi.validation.support.SnapshotGeneratingValidationSupport";
|
||||||
if (ReflectionUtil.typeExists(inMemoryTermSvcType)) {
|
if (ReflectionUtil.typeExists(inMemoryTermSvcType)) {
|
||||||
IValidationSupport inMemoryTermSvc = ReflectionUtil.newInstanceOrReturnNull(
|
IValidationSupport inMemoryTermSvc = ReflectionUtil.newInstanceOrReturnNull(
|
||||||
inMemoryTermSvcType,
|
inMemoryTermSvcType,
|
||||||
|
@ -724,11 +726,23 @@ public class FhirContext {
|
||||||
IValidationSupport.class,
|
IValidationSupport.class,
|
||||||
new Class<?>[] {FhirContext.class},
|
new Class<?>[] {FhirContext.class},
|
||||||
new Object[] {this});
|
new Object[] {this});
|
||||||
|
IValidationSupport snapshotGeneratingSupport = null;
|
||||||
|
if (getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
|
||||||
|
snapshotGeneratingSupport = ReflectionUtil.newInstanceOrReturnNull(
|
||||||
|
snapshotGeneratingType,
|
||||||
|
IValidationSupport.class,
|
||||||
|
new Class<?>[] {FhirContext.class},
|
||||||
|
new Object[] {this});
|
||||||
|
}
|
||||||
retVal = ReflectionUtil.newInstanceOrReturnNull(
|
retVal = ReflectionUtil.newInstanceOrReturnNull(
|
||||||
"org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain",
|
"org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain",
|
||||||
IValidationSupport.class,
|
IValidationSupport.class,
|
||||||
new Class<?>[] {IValidationSupport[].class},
|
new Class<?>[] {IValidationSupport[].class},
|
||||||
new Object[] {new IValidationSupport[] {retVal, inMemoryTermSvc, commonCodeSystemsSupport}});
|
new Object[] {
|
||||||
|
new IValidationSupport[] {
|
||||||
|
retVal, inMemoryTermSvc, commonCodeSystemsSupport, snapshotGeneratingSupport
|
||||||
|
}
|
||||||
|
});
|
||||||
assert retVal != null
|
assert retVal != null
|
||||||
: "Failed to instantiate "
|
: "Failed to instantiate "
|
||||||
+ "org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain";
|
+ "org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain";
|
||||||
|
|
|
@ -22,11 +22,26 @@ package ca.uhn.fhir.context.support;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
public class ConceptValidationOptions {
|
public class ConceptValidationOptions {
|
||||||
|
|
||||||
private boolean myValidateDisplay;
|
private boolean myValidateDisplay;
|
||||||
private boolean myInferSystem;
|
private boolean myInferSystem;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object theO) {
|
||||||
|
if (this == theO) return true;
|
||||||
|
if (!(theO instanceof ConceptValidationOptions)) return false;
|
||||||
|
ConceptValidationOptions that = (ConceptValidationOptions) theO;
|
||||||
|
return myValidateDisplay == that.myValidateDisplay && myInferSystem == that.myInferSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(myValidateDisplay, myInferSystem);
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isInferSystem() {
|
public boolean isInferSystem() {
|
||||||
return myInferSystem;
|
return myInferSystem;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,7 +23,9 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.util.ILockable;
|
import ca.uhn.fhir.util.ILockable;
|
||||||
import ca.uhn.fhir.util.ReflectionUtil;
|
import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
@ -48,6 +50,13 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
|
|
||||||
private static final Map<FhirVersionEnum, IValidationSupport> ourImplementations =
|
private static final Map<FhirVersionEnum, IValidationSupport> ourImplementations =
|
||||||
Collections.synchronizedMap(new HashMap<>());
|
Collections.synchronizedMap(new HashMap<>());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Userdata key indicating the source package ID for this package
|
||||||
|
*/
|
||||||
|
public static final String SOURCE_PACKAGE_ID =
|
||||||
|
DefaultProfileValidationSupport.class.getName() + "_SOURCE_PACKAGE_ID";
|
||||||
|
|
||||||
private final FhirContext myCtx;
|
private final FhirContext myCtx;
|
||||||
/**
|
/**
|
||||||
* This module just delegates all calls to a concrete implementation which will
|
* This module just delegates all calls to a concrete implementation which will
|
||||||
|
@ -62,7 +71,8 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
*
|
*
|
||||||
* @param theFhirContext The context to use
|
* @param theFhirContext The context to use
|
||||||
*/
|
*/
|
||||||
public DefaultProfileValidationSupport(FhirContext theFhirContext) {
|
public DefaultProfileValidationSupport(@Nonnull FhirContext theFhirContext) {
|
||||||
|
Validate.notNull(theFhirContext, "FhirContext must not be null");
|
||||||
myCtx = theFhirContext;
|
myCtx = theFhirContext;
|
||||||
|
|
||||||
IValidationSupport strategy;
|
IValidationSupport strategy;
|
||||||
|
@ -106,33 +116,45 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<IBaseResource> fetchAllConformanceResources() {
|
public List<IBaseResource> fetchAllConformanceResources() {
|
||||||
return myDelegate.fetchAllConformanceResources();
|
List<IBaseResource> retVal = myDelegate.fetchAllConformanceResources();
|
||||||
|
addPackageInformation(retVal);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T extends IBaseResource> List<T> fetchAllStructureDefinitions() {
|
public <T extends IBaseResource> List<T> fetchAllStructureDefinitions() {
|
||||||
return myDelegate.fetchAllStructureDefinitions();
|
List<T> retVal = myDelegate.fetchAllStructureDefinitions();
|
||||||
|
addPackageInformation(retVal);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public <T extends IBaseResource> List<T> fetchAllNonBaseStructureDefinitions() {
|
public <T extends IBaseResource> List<T> fetchAllNonBaseStructureDefinitions() {
|
||||||
return myDelegate.fetchAllNonBaseStructureDefinitions();
|
List<T> retVal = myDelegate.fetchAllNonBaseStructureDefinitions();
|
||||||
|
addPackageInformation(retVal);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource fetchCodeSystem(String theSystem) {
|
public IBaseResource fetchCodeSystem(String theSystem) {
|
||||||
return myDelegate.fetchCodeSystem(theSystem);
|
IBaseResource retVal = myDelegate.fetchCodeSystem(theSystem);
|
||||||
|
addPackageInformation(retVal);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource fetchStructureDefinition(String theUrl) {
|
public IBaseResource fetchStructureDefinition(String theUrl) {
|
||||||
return myDelegate.fetchStructureDefinition(theUrl);
|
IBaseResource retVal = myDelegate.fetchStructureDefinition(theUrl);
|
||||||
|
addPackageInformation(retVal);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource fetchValueSet(String theUrl) {
|
public IBaseResource fetchValueSet(String theUrl) {
|
||||||
return myDelegate.fetchValueSet(theUrl);
|
IBaseResource retVal = myDelegate.fetchValueSet(theUrl);
|
||||||
|
addPackageInformation(retVal);
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void flush() {
|
public void flush() {
|
||||||
|
@ -158,4 +180,43 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
}
|
}
|
||||||
return urlValueString;
|
return urlValueString;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private <T extends IBaseResource> void addPackageInformation(List<T> theResources) {
|
||||||
|
if (theResources != null) {
|
||||||
|
theResources.forEach(this::addPackageInformation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addPackageInformation(IBaseResource theResource) {
|
||||||
|
if (theResource != null) {
|
||||||
|
String sourcePackageId = null;
|
||||||
|
switch (myCtx.getVersion().getVersion()) {
|
||||||
|
case DSTU2:
|
||||||
|
case DSTU2_HL7ORG:
|
||||||
|
sourcePackageId = "hl7.fhir.r2.core";
|
||||||
|
break;
|
||||||
|
case DSTU2_1:
|
||||||
|
return;
|
||||||
|
case DSTU3:
|
||||||
|
sourcePackageId = "hl7.fhir.r3.core";
|
||||||
|
break;
|
||||||
|
case R4:
|
||||||
|
sourcePackageId = "hl7.fhir.r4.core";
|
||||||
|
break;
|
||||||
|
case R4B:
|
||||||
|
sourcePackageId = "hl7.fhir.r4b.core";
|
||||||
|
break;
|
||||||
|
case R5:
|
||||||
|
sourcePackageId = "hl7.fhir.r5.core";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
Validate.notNull(
|
||||||
|
sourcePackageId,
|
||||||
|
"Don't know how to handle package ID: %s",
|
||||||
|
myCtx.getVersion().getVersion());
|
||||||
|
|
||||||
|
theResource.setUserData(SOURCE_PACKAGE_ID, sourcePackageId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,6 +41,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Supplier;
|
import java.util.function.Supplier;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -116,7 +117,8 @@ public interface IValidationSupport {
|
||||||
@Nonnull String theValueSetUrlToExpand)
|
@Nonnull String theValueSetUrlToExpand)
|
||||||
throws ResourceNotFoundException {
|
throws ResourceNotFoundException {
|
||||||
Validate.notBlank(theValueSetUrlToExpand, "theValueSetUrlToExpand must not be null or blank");
|
Validate.notBlank(theValueSetUrlToExpand, "theValueSetUrlToExpand must not be null or blank");
|
||||||
IBaseResource valueSet = fetchValueSet(theValueSetUrlToExpand);
|
IBaseResource valueSet =
|
||||||
|
theValidationSupportContext.getRootValidationSupport().fetchValueSet(theValueSetUrlToExpand);
|
||||||
if (valueSet == null) {
|
if (valueSet == null) {
|
||||||
throw new ResourceNotFoundException(
|
throw new ResourceNotFoundException(
|
||||||
Msg.code(2024) + "Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSetUrlToExpand));
|
Msg.code(2024) + "Unknown ValueSet: " + UrlUtil.escapeUrlParam(theValueSetUrlToExpand));
|
||||||
|
@ -212,8 +214,8 @@ public interface IValidationSupport {
|
||||||
() -> fetchStructureDefinition(theUri), () -> fetchValueSet(theUri), () -> fetchCodeSystem(theUri)
|
() -> fetchStructureDefinition(theUri), () -> fetchValueSet(theUri), () -> fetchCodeSystem(theUri)
|
||||||
};
|
};
|
||||||
return (T) Arrays.stream(sources)
|
return (T) Arrays.stream(sources)
|
||||||
.map(t -> t.get())
|
.map(Supplier::get)
|
||||||
.filter(t -> t != null)
|
.filter(Objects::nonNull)
|
||||||
.findFirst()
|
.findFirst()
|
||||||
.orElse(null);
|
.orElse(null);
|
||||||
}
|
}
|
||||||
|
@ -792,6 +794,7 @@ public interface IValidationSupport {
|
||||||
return myValue;
|
return myValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return TYPE_STRING;
|
return TYPE_STRING;
|
||||||
}
|
}
|
||||||
|
@ -826,6 +829,7 @@ public interface IValidationSupport {
|
||||||
return myDisplay;
|
return myDisplay;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public String getType() {
|
public String getType() {
|
||||||
return TYPE_CODING;
|
return TYPE_CODING;
|
||||||
}
|
}
|
||||||
|
@ -1431,10 +1435,9 @@ public interface IValidationSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p
|
* When validating a CodeableConcept containing multiple codings, this method can be used to control whether
|
||||||
* Warning: This method's behaviour and naming is preserved for backwards compatibility, BUT the actual naming and
|
* the validator requires all codings in the CodeableConcept to be valid in order to consider the
|
||||||
* function are not aligned.
|
* CodeableConcept valid.
|
||||||
* </p
|
|
||||||
* <p>
|
* <p>
|
||||||
* See VersionSpecificWorkerContextWrapper#validateCode in hapi-fhir-validation, and the refer to the values below
|
* See VersionSpecificWorkerContextWrapper#validateCode in hapi-fhir-validation, and the refer to the values below
|
||||||
* for the behaviour associated with each value.
|
* for the behaviour associated with each value.
|
||||||
|
@ -1449,7 +1452,7 @@ public interface IValidationSupport {
|
||||||
* </p>
|
* </p>
|
||||||
* @return true or false depending on the desired coding validation behaviour.
|
* @return true or false depending on the desired coding validation behaviour.
|
||||||
*/
|
*/
|
||||||
default boolean isEnabledValidationForCodingsLogicalAnd() {
|
default boolean isCodeableConceptValidationSuccessfulIfNotAllCodingsAreValid() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.context.support;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents parameters which can be passed to the $lookup operation for codes.
|
* Represents parameters which can be passed to the $lookup operation for codes.
|
||||||
|
@ -72,4 +73,20 @@ public class LookupCodeRequest {
|
||||||
}
|
}
|
||||||
return myPropertyNames;
|
return myPropertyNames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object theO) {
|
||||||
|
if (this == theO) return true;
|
||||||
|
if (!(theO instanceof LookupCodeRequest)) return false;
|
||||||
|
LookupCodeRequest that = (LookupCodeRequest) theO;
|
||||||
|
return Objects.equals(mySystem, that.mySystem)
|
||||||
|
&& Objects.equals(myCode, that.myCode)
|
||||||
|
&& Objects.equals(myDisplayLanguage, that.myDisplayLanguage)
|
||||||
|
&& Objects.equals(myPropertyNames, that.myPropertyNames);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(mySystem, myCode, myDisplayLanguage, myPropertyNames);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class ValidationSupportContext {
|
||||||
return myCurrentlyGeneratingSnapshots;
|
return myCurrentlyGeneratingSnapshots;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isEnabledValidationForCodingsLogicalAnd() {
|
public boolean isCodeableConceptValidationSuccessfulIfNotAllCodingsAreValid() {
|
||||||
return myRootValidationSupport.isEnabledValidationForCodingsLogicalAnd();
|
return myRootValidationSupport.isCodeableConceptValidationSuccessfulIfNotAllCodingsAreValid();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,6 +21,8 @@ package ca.uhn.fhir.context.support;
|
||||||
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options for ValueSet expansion
|
* Options for ValueSet expansion
|
||||||
*
|
*
|
||||||
|
@ -126,4 +128,23 @@ public class ValueSetExpansionOptions {
|
||||||
myDisplayLanguage = theDisplayLanguage;
|
myDisplayLanguage = theDisplayLanguage;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object theO) {
|
||||||
|
if (this == theO) return true;
|
||||||
|
if (!(theO instanceof ValueSetExpansionOptions)) return false;
|
||||||
|
ValueSetExpansionOptions that = (ValueSetExpansionOptions) theO;
|
||||||
|
return myFailOnMissingCodeSystem == that.myFailOnMissingCodeSystem
|
||||||
|
&& myCount == that.myCount
|
||||||
|
&& myOffset == that.myOffset
|
||||||
|
&& myIncludeHierarchy == that.myIncludeHierarchy
|
||||||
|
&& Objects.equals(myFilter, that.myFilter)
|
||||||
|
&& Objects.equals(myDisplayLanguage, that.myDisplayLanguage);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(
|
||||||
|
myFailOnMissingCodeSystem, myCount, myOffset, myIncludeHierarchy, myFilter, myDisplayLanguage);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -342,6 +342,8 @@ public class Constants {
|
||||||
*/
|
*/
|
||||||
public static final String HIBERNATE_INTEGRATION_ENVERS_ENABLED = "hibernate.integration.envers.enabled";
|
public static final String HIBERNATE_INTEGRATION_ENVERS_ENABLED = "hibernate.integration.envers.enabled";
|
||||||
|
|
||||||
|
public static final String OPENTELEMETRY_BASE_NAME = "io.hapifhir";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CHARSET_UTF8 = StandardCharsets.UTF_8;
|
CHARSET_UTF8 = StandardCharsets.UTF_8;
|
||||||
CHARSET_US_ASCII = StandardCharsets.ISO_8859_1;
|
CHARSET_US_ASCII = StandardCharsets.ISO_8859_1;
|
||||||
|
|
|
@ -33,7 +33,7 @@ public class SleepUtil {
|
||||||
@SuppressWarnings("BusyWait")
|
@SuppressWarnings("BusyWait")
|
||||||
public void sleepAtLeast(long theMillis, boolean theLogProgress) {
|
public void sleepAtLeast(long theMillis, boolean theLogProgress) {
|
||||||
long start = System.currentTimeMillis();
|
long start = System.currentTimeMillis();
|
||||||
while (System.currentTimeMillis() <= start + theMillis) {
|
while (System.currentTimeMillis() < start + theMillis) {
|
||||||
try {
|
try {
|
||||||
long timeSinceStarted = System.currentTimeMillis() - start;
|
long timeSinceStarted = System.currentTimeMillis() - start;
|
||||||
long timeToSleep = Math.max(0, theMillis - timeSinceStarted);
|
long timeToSleep = Math.max(0, theMillis - timeSinceStarted);
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-bom</artifactId>
|
<artifactId>hapi-fhir-bom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>HAPI FHIR BOM</name>
|
<name>HAPI FHIR BOM</name>
|
||||||
|
@ -12,7 +12,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-cli</artifactId>
|
<artifactId>hapi-fhir-cli</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -40,7 +40,6 @@ import jakarta.annotation.Nonnull;
|
||||||
import jakarta.servlet.ServletException;
|
import jakarta.servlet.ServletException;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.apache.commons.io.filefilter.WildcardFileFilter;
|
import org.apache.commons.io.filefilter.WildcardFileFilter;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService;
|
import org.hl7.fhir.common.hapi.validation.support.CommonCodeSystemsTerminologyService;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.NpmPackageValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.NpmPackageValidationSupport;
|
||||||
|
@ -343,7 +342,8 @@ public class ValidatorExamples {
|
||||||
// START SNIPPET: validateSupplyProfiles
|
// START SNIPPET: validateSupplyProfiles
|
||||||
FhirContext ctx = FhirContext.forR4();
|
FhirContext ctx = FhirContext.forR4();
|
||||||
|
|
||||||
// Create a chain that will hold our modules
|
// Create a chain that will hold our modules and caches the
|
||||||
|
// values they supply
|
||||||
ValidationSupportChain supportChain = new ValidationSupportChain();
|
ValidationSupportChain supportChain = new ValidationSupportChain();
|
||||||
|
|
||||||
// DefaultProfileValidationSupport supplies base FHIR definitions. This is generally required
|
// DefaultProfileValidationSupport supplies base FHIR definitions. This is generally required
|
||||||
|
@ -368,12 +368,9 @@ public class ValidatorExamples {
|
||||||
// Add the custom definitions to the chain
|
// Add the custom definitions to the chain
|
||||||
supportChain.addValidationSupport(prePopulatedSupport);
|
supportChain.addValidationSupport(prePopulatedSupport);
|
||||||
|
|
||||||
// Wrap the chain in a cache to improve performance
|
|
||||||
CachingValidationSupport cache = new CachingValidationSupport(supportChain);
|
|
||||||
|
|
||||||
// Create a validator using the FhirInstanceValidator module. We can use this
|
// Create a validator using the FhirInstanceValidator module. We can use this
|
||||||
// validator to perform validation
|
// validator to perform validation
|
||||||
FhirInstanceValidator validatorModule = new FhirInstanceValidator(cache);
|
FhirInstanceValidator validatorModule = new FhirInstanceValidator(supportChain);
|
||||||
FhirValidator validator = ctx.newValidator().registerValidatorModule(validatorModule);
|
FhirValidator validator = ctx.newValidator().registerValidatorModule(validatorModule);
|
||||||
ValidationResult result = validator.validateWithResult(input);
|
ValidationResult result = validator.validateWithResult(input);
|
||||||
// END SNIPPET: validateSupplyProfiles
|
// END SNIPPET: validateSupplyProfiles
|
||||||
|
@ -403,12 +400,9 @@ public class ValidatorExamples {
|
||||||
remoteTermSvc.setBaseUrl("http://hapi.fhir.org/baseR4");
|
remoteTermSvc.setBaseUrl("http://hapi.fhir.org/baseR4");
|
||||||
supportChain.addValidationSupport(remoteTermSvc);
|
supportChain.addValidationSupport(remoteTermSvc);
|
||||||
|
|
||||||
// Wrap the chain in a cache to improve performance
|
|
||||||
CachingValidationSupport cache = new CachingValidationSupport(supportChain);
|
|
||||||
|
|
||||||
// Create a validator using the FhirInstanceValidator module. We can use this
|
// Create a validator using the FhirInstanceValidator module. We can use this
|
||||||
// validator to perform validation
|
// validator to perform validation
|
||||||
FhirInstanceValidator validatorModule = new FhirInstanceValidator(cache);
|
FhirInstanceValidator validatorModule = new FhirInstanceValidator(supportChain);
|
||||||
FhirValidator validator = ctx.newValidator().registerValidatorModule(validatorModule);
|
FhirValidator validator = ctx.newValidator().registerValidatorModule(validatorModule);
|
||||||
ValidationResult result = validator.validateWithResult(input);
|
ValidationResult result = validator.validateWithResult(input);
|
||||||
// END SNIPPET: validateUsingRemoteTermSvr
|
// END SNIPPET: validateUsingRemoteTermSvr
|
||||||
|
@ -462,12 +456,11 @@ public class ValidatorExamples {
|
||||||
new CommonCodeSystemsTerminologyService(ctx),
|
new CommonCodeSystemsTerminologyService(ctx),
|
||||||
new InMemoryTerminologyServerValidationSupport(ctx),
|
new InMemoryTerminologyServerValidationSupport(ctx),
|
||||||
new SnapshotGeneratingValidationSupport(ctx));
|
new SnapshotGeneratingValidationSupport(ctx));
|
||||||
CachingValidationSupport validationSupport = new CachingValidationSupport(validationSupportChain);
|
|
||||||
|
|
||||||
// Create a validator. Note that for good performance you can create as many validator objects
|
// Create a validator. Note that for good performance you can create as many validator objects
|
||||||
// as you like, but you should reuse the same validation support object in all of the,.
|
// as you like, but you should reuse the same validation support object in all of the,.
|
||||||
FhirValidator validator = ctx.newValidator();
|
FhirValidator validator = ctx.newValidator();
|
||||||
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(validationSupport);
|
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(validationSupportChain);
|
||||||
validator.registerValidatorModule(instanceValidator);
|
validator.registerValidatorModule(instanceValidator);
|
||||||
|
|
||||||
// Create a test patient to validate
|
// Create a test patient to validate
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
---
|
||||||
|
type: perf
|
||||||
|
issue: 6508
|
||||||
|
title: "The ValidationSupportChain module has been rewritten to improve validator performance. This change:
|
||||||
|
* Adds new caching capabilities to ValidationSupportChain. This is an improvement over the previous separate caching module because the chain can now remember which entries in the cache responded affirmative to `isValueSetSupported()` and will therefore be more efficient about trying entries in the chain. It also makes debugging much less confusing as there is less recursion and the caches don't use loadingCache.
|
||||||
|
* Importantly, the caching in ValidationSupportChain caches negative lookups (i.e. items that could not be found by URL) as well as positive lookups. This is a change from the historical caching behaviour.
|
||||||
|
* Changes ValidationSupportChain to never expire StructureDefinition entries in the cache, which is needed because the validator makes assumptions about structuredefinitions never changing. Fixes #6424.
|
||||||
|
* Modifies `VersionSpecificWorkerContextWrapper` so that it doesn't use a separate cache and instead relies on the caching provided by ValidationSupportChain. This class previously used a cache because it converts arbitrary versions of FHIR StructureDefinitions into the canonical version required by the validator (R5), but these converted versions are now stored in the userdata map of objects returned by and cached by ValidationSupportChain. This makes the caching more predictable since there is only one cache to track.
|
||||||
|
* Adds OpenTelemetry support to ValidationSupportChain, with metrics for tracking the cache size.
|
||||||
|
* Deprecates CachingValidationSupport since caching is now provided by ValidationSupportChain. CachingValidationSupport is now just a passthrough and should be removed from applications. It will be removed from the library in a future release.
|
||||||
|
* Removes ConceptMap caching from TermReachSvcImpl, as this caching is both redundant and inefficient as it operates within a database transaction.
|
||||||
|
|
||||||
|
These changes result in very significant performance improvements when performing validation in the JPA server. Throughput improvements of 1000% have been recorded in benchmarking use cases involving large profiles and remote terminology services enabled. Many other validation use cases should see significant improvements as well."
|
|
@ -16,6 +16,21 @@ There are a several implementations of the [IValidationSupport](/hapi-fhir/apido
|
||||||
|
|
||||||
This module can be used to combine multiple implementations together so that for every request, each support class instance in the chain is tried in sequence. Note that nearly all methods in the [IValidationSupport](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html) interface are permitted to return `null` if they are not able to service a particular method call. So for example, if a call to the [`validateCode`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html#validateCode(ca.uhn.fhir.context.support.ValidationSupportContext,ca.uhn.fhir.context.support.ConceptValidationOptions,java.lang.String,java.lang.String,java.lang.String,java.lang.String)) method is made, the validator will try each module in the chain until one of them returns a non-null response.
|
This module can be used to combine multiple implementations together so that for every request, each support class instance in the chain is tried in sequence. Note that nearly all methods in the [IValidationSupport](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html) interface are permitted to return `null` if they are not able to service a particular method call. So for example, if a call to the [`validateCode`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/support/IValidationSupport.html#validateCode(ca.uhn.fhir.context.support.ValidationSupportContext,ca.uhn.fhir.context.support.ConceptValidationOptions,java.lang.String,java.lang.String,java.lang.String,java.lang.String)) method is made, the validator will try each module in the chain until one of them returns a non-null response.
|
||||||
|
|
||||||
|
The following chaining logic is used:
|
||||||
|
|
||||||
|
* Calls to `fetchAll...` methods such as `fetchAllConformanceResources()` and `fetchAllStructureDefinitions()` will call every method in the chain in order, and aggregate the results into a single list to return.
|
||||||
|
* Calls to fetch or validate codes, such as `validateCode(...)` and `lookupCode(...)` will first test each module in the chain using the`isCodeSystemSupported(...)` or `isValueSetSupported(...)` methods (depending on whether a ValueSet URL is present in the method parameters) and will invoke any methods in the chain which return that they can handle the given CodeSystem/ValueSet URL. The first non-null value returned by a method in the chain that can support the URL will be returned to the caller.
|
||||||
|
* All other methods will invoke the method in the chain in order, and will return immediately as soon as a non-null value is returned.
|
||||||
|
|
||||||
|
The following caching logic is used if caching is enabled using `CacheConfiguration`. You can use `CacheConfiguration.disabled()` if you want to disable caching.
|
||||||
|
|
||||||
|
* Calls to fetch StructureDefinitions including `fetchAllStructureDefinitions()` and `fetchStructureDefinition(...)` are cached in a non-expiring cache. This is because the `FhirInstanceValidator` module makes assumptions that these objects will not change for the lifetime of the validator for performance reasons.
|
||||||
|
* Calls to all other `fetchAll...` methods including `fetchAllConformanceResources()` and `fetchAllSearchParameters()` cache their results in an expiring cache, but will refresh that cache asynchronously.
|
||||||
|
* Results of `generateSnapshot(...)` are not cached, as this method is generally called in contexts where the results are cached.
|
||||||
|
* Results of all other methods are stored in an expiring cache.
|
||||||
|
|
||||||
|
Note that caching functionality used to be provided by a separate provider called {@literal CachingValidationSupport} but that functionality has been moved into this class as of HAPI FHIR 8.0.0, because it is possible to provide a more efficient chain when these functions are combined.
|
||||||
|
|
||||||
# DefaultProfileValidationSupport
|
# DefaultProfileValidationSupport
|
||||||
|
|
||||||
[JavaDoc](/hapi-fhir/apidocs/hapi-fhir-base/undefined/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.html) / [Source](https://github.com/hapifhir/hapi-fhir/blob/master/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.java)
|
[JavaDoc](/hapi-fhir/apidocs/hapi-fhir-base/undefined/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.html) / [Source](https://github.com/hapifhir/hapi-fhir/blob/master/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/support/DefaultProfileValidationSupport.java)
|
||||||
|
@ -44,12 +59,6 @@ This module contains a series of HashMaps that store loaded conformance resource
|
||||||
This module can be used to load FHIR NPM Packages and supply the conformance resources within them to the validator. See [Validating Using Packages](./instance_validator.html#packages) for am example of how to use this module.
|
This module can be used to load FHIR NPM Packages and supply the conformance resources within them to the validator. See [Validating Using Packages](./instance_validator.html#packages) for am example of how to use this module.
|
||||||
|
|
||||||
|
|
||||||
# CachingValidationSupport
|
|
||||||
|
|
||||||
[JavaDoc](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.html) / [Source](https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java)
|
|
||||||
|
|
||||||
This module caches results of calls to a wrapped service implementation for a period of time. This class can be a significant help in terms of performance if you are loading conformance resources or performing terminology operations from a database or disk, but it also has value even for purely in-memory validation since validating codes against a ValueSet can require the expansion of that ValueSet.
|
|
||||||
|
|
||||||
# SnapshotGeneratingValidationSupport
|
# SnapshotGeneratingValidationSupport
|
||||||
|
|
||||||
[JavaDoc](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/SnapshotGeneratingValidationSupport.html) / [Source](https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/SnapshotGeneratingValidationSupport.java)
|
[JavaDoc](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/SnapshotGeneratingValidationSupport.html) / [Source](https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/SnapshotGeneratingValidationSupport.java)
|
||||||
|
@ -161,6 +170,12 @@ This validation support module may be placed at the end of a ValidationSupportCh
|
||||||
|
|
||||||
Note that this module must also be activated by calling [setAllowNonExistentCodeSystem(true)](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/UnknownCodeSystemWarningValidationSupport.html#setAllowNonExistentCodeSystem(boolean)) in order to specify that unknown code systems should be allowed.
|
Note that this module must also be activated by calling [setAllowNonExistentCodeSystem(true)](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/UnknownCodeSystemWarningValidationSupport.html#setAllowNonExistentCodeSystem(boolean)) in order to specify that unknown code systems should be allowed.
|
||||||
|
|
||||||
|
# CachingValidationSupport
|
||||||
|
|
||||||
|
[JavaDoc](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.html) / [Source](https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-validation/src/main/java/org/hl7/fhir/common/hapi/validation/support/CachingValidationSupport.java)
|
||||||
|
|
||||||
|
This module is deprecated and no longer provides any functionality. Caching is provided by [ValidationSupportChain](#validationsupportchain).
|
||||||
|
|
||||||
|
|
||||||
# Recipes
|
# Recipes
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -22,7 +22,6 @@ package ca.uhn.fhir.jpa.config;
|
||||||
import ca.uhn.fhir.jpa.api.IDaoRegistry;
|
import ca.uhn.fhir.jpa.api.IDaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.config.util.ResourceCountCacheUtil;
|
import ca.uhn.fhir.jpa.config.util.ResourceCountCacheUtil;
|
||||||
import ca.uhn.fhir.jpa.config.util.ValidationSupportConfigUtil;
|
|
||||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||||
import ca.uhn.fhir.jpa.dao.search.HSearchSortHelperImpl;
|
import ca.uhn.fhir.jpa.dao.search.HSearchSortHelperImpl;
|
||||||
|
@ -32,15 +31,12 @@ import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
|
|
||||||
import ca.uhn.fhir.rest.api.IResourceSupportedSvc;
|
import ca.uhn.fhir.rest.api.IResourceSupportedSvc;
|
||||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.context.annotation.Primary;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@Import({JpaConfig.class})
|
@Import({JpaConfig.class})
|
||||||
|
@ -64,12 +60,6 @@ public class HapiJpaConfig {
|
||||||
return new StaleSearchDeletingSvcImpl();
|
return new StaleSearchDeletingSvcImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Primary
|
|
||||||
@Bean
|
|
||||||
public CachingValidationSupport validationSupportChain(JpaValidationSupportChain theJpaValidationSupportChain) {
|
|
||||||
return ValidationSupportConfigUtil.newCachingValidationSupport(theJpaValidationSupportChain);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||||
return new DatabaseBackedPagingProvider();
|
return new DatabaseBackedPagingProvider();
|
||||||
|
|
|
@ -168,6 +168,7 @@ import ca.uhn.fhir.jpa.term.config.TermCodeSystemConfig;
|
||||||
import ca.uhn.fhir.jpa.util.JpaHapiTransactionService;
|
import ca.uhn.fhir.jpa.util.JpaHapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.util.MemoryCacheService;
|
import ca.uhn.fhir.jpa.util.MemoryCacheService;
|
||||||
import ca.uhn.fhir.jpa.util.PersistenceContextProvider;
|
import ca.uhn.fhir.jpa.util.PersistenceContextProvider;
|
||||||
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
|
||||||
import ca.uhn.fhir.jpa.validation.ResourceLoaderImpl;
|
import ca.uhn.fhir.jpa.validation.ResourceLoaderImpl;
|
||||||
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
import ca.uhn.fhir.jpa.validation.ValidationSettings;
|
||||||
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
|
||||||
|
@ -185,6 +186,7 @@ import ca.uhn.fhir.util.MetaTagSorterAlphabetical;
|
||||||
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
import ca.uhn.hapi.converters.canonical.VersionCanonicalizer;
|
||||||
import jakarta.annotation.Nullable;
|
import jakarta.annotation.Nullable;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.UnknownCodeSystemWarningValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.UnknownCodeSystemWarningValidationSupport;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
@ -230,11 +232,26 @@ public class JpaConfig {
|
||||||
public static final String PERSISTED_JPA_SEARCH_FIRST_PAGE_BUNDLE_PROVIDER =
|
public static final String PERSISTED_JPA_SEARCH_FIRST_PAGE_BUNDLE_PROVIDER =
|
||||||
"PersistedJpaSearchFirstPageBundleProvider";
|
"PersistedJpaSearchFirstPageBundleProvider";
|
||||||
public static final String HISTORY_BUILDER = "HistoryBuilder";
|
public static final String HISTORY_BUILDER = "HistoryBuilder";
|
||||||
|
public static final String DEFAULT_PROFILE_VALIDATION_SUPPORT = "myDefaultProfileValidationSupport";
|
||||||
private static final String HAPI_DEFAULT_SCHEDULER_GROUP = "HAPI";
|
private static final String HAPI_DEFAULT_SCHEDULER_GROUP = "HAPI";
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public JpaStorageSettings myStorageSettings;
|
public JpaStorageSettings myStorageSettings;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private FhirContext myFhirContext;
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ValidationSupportChain.CacheConfiguration validationSupportChainCacheConfiguration() {
|
||||||
|
return ValidationSupportChain.CacheConfiguration.defaultValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean(name = JpaConfig.JPA_VALIDATION_SUPPORT_CHAIN)
|
||||||
|
@Primary
|
||||||
|
public IValidationSupport jpaValidationSupportChain() {
|
||||||
|
return new JpaValidationSupportChain(myFhirContext, validationSupportChainCacheConfiguration());
|
||||||
|
}
|
||||||
|
|
||||||
@Bean("myDaoRegistry")
|
@Bean("myDaoRegistry")
|
||||||
public DaoRegistry daoRegistry() {
|
public DaoRegistry daoRegistry() {
|
||||||
return new DaoRegistry();
|
return new DaoRegistry();
|
||||||
|
|
|
@ -20,31 +20,31 @@
|
||||||
package ca.uhn.fhir.jpa.config;
|
package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
|
||||||
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
import ca.uhn.fhir.context.support.DefaultProfileValidationSupport;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
import ca.uhn.fhir.jpa.api.config.JpaStorageSettings;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.dao.JpaPersistedResourceValidationSupport;
|
import ca.uhn.fhir.jpa.dao.JpaPersistedResourceValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
|
|
||||||
import ca.uhn.fhir.jpa.validation.ValidatorPolicyAdvisor;
|
import ca.uhn.fhir.jpa.validation.ValidatorPolicyAdvisor;
|
||||||
import ca.uhn.fhir.jpa.validation.ValidatorResourceFetcher;
|
import ca.uhn.fhir.jpa.validation.ValidatorResourceFetcher;
|
||||||
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
import ca.uhn.fhir.validation.IInstanceValidatorModule;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.HapiToHl7OrgDstu2ValidatingSupportWrapper;
|
|
||||||
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
import org.springframework.context.annotation.Lazy;
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class ValidationSupportConfig {
|
public class ValidationSupportConfig {
|
||||||
@Bean(name = "myDefaultProfileValidationSupport")
|
|
||||||
public DefaultProfileValidationSupport defaultProfileValidationSupport(FhirContext theFhirContext) {
|
@Autowired
|
||||||
return new DefaultProfileValidationSupport(theFhirContext);
|
private FhirContext myFhirContext;
|
||||||
|
|
||||||
|
@Bean(name = JpaConfig.DEFAULT_PROFILE_VALIDATION_SUPPORT)
|
||||||
|
public DefaultProfileValidationSupport defaultProfileValidationSupport() {
|
||||||
|
return new DefaultProfileValidationSupport(myFhirContext);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
@ -56,11 +56,6 @@ public class ValidationSupportConfig {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean(name = JpaConfig.JPA_VALIDATION_SUPPORT_CHAIN)
|
|
||||||
public JpaValidationSupportChain jpaValidationSupportChain(FhirContext theFhirContext) {
|
|
||||||
return new JpaValidationSupportChain(theFhirContext);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean(name = JpaConfig.JPA_VALIDATION_SUPPORT)
|
@Bean(name = JpaConfig.JPA_VALIDATION_SUPPORT)
|
||||||
public IValidationSupport jpaValidationSupport(FhirContext theFhirContext) {
|
public IValidationSupport jpaValidationSupport(FhirContext theFhirContext) {
|
||||||
return new JpaPersistedResourceValidationSupport(theFhirContext);
|
return new JpaPersistedResourceValidationSupport(theFhirContext);
|
||||||
|
@ -68,26 +63,13 @@ public class ValidationSupportConfig {
|
||||||
|
|
||||||
@Bean(name = "myInstanceValidator")
|
@Bean(name = "myInstanceValidator")
|
||||||
public IInstanceValidatorModule instanceValidator(
|
public IInstanceValidatorModule instanceValidator(
|
||||||
FhirContext theFhirContext,
|
FhirContext theFhirContext, IValidationSupport theValidationSupportChain, DaoRegistry theDaoRegistry) {
|
||||||
CachingValidationSupport theCachingValidationSupport,
|
FhirInstanceValidator val = new FhirInstanceValidator(theValidationSupportChain);
|
||||||
ValidationSupportChain theValidationSupportChain,
|
val.setValidatorResourceFetcher(
|
||||||
IValidationSupport theValidationSupport,
|
jpaValidatorResourceFetcher(theFhirContext, theValidationSupportChain, theDaoRegistry));
|
||||||
DaoRegistry theDaoRegistry) {
|
val.setValidatorPolicyAdvisor(jpaValidatorPolicyAdvisor());
|
||||||
if (theFhirContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
|
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
||||||
FhirInstanceValidator val = new FhirInstanceValidator(theCachingValidationSupport);
|
return val;
|
||||||
val.setValidatorResourceFetcher(
|
|
||||||
jpaValidatorResourceFetcher(theFhirContext, theValidationSupport, theDaoRegistry));
|
|
||||||
val.setValidatorPolicyAdvisor(jpaValidatorPolicyAdvisor());
|
|
||||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
|
||||||
val.setValidationSupport(theCachingValidationSupport);
|
|
||||||
return val;
|
|
||||||
} else {
|
|
||||||
CachingValidationSupport cachingValidationSupport = new CachingValidationSupport(
|
|
||||||
new HapiToHl7OrgDstu2ValidatingSupportWrapper(theValidationSupportChain));
|
|
||||||
FhirInstanceValidator retVal = new FhirInstanceValidator(cachingValidationSupport);
|
|
||||||
retVal.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -1,43 +0,0 @@
|
||||||
/*-
|
|
||||||
* #%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://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.config.util;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChain;
|
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
|
|
||||||
public final class ValidationSupportConfigUtil {
|
|
||||||
private ValidationSupportConfigUtil() {}
|
|
||||||
|
|
||||||
public static CachingValidationSupport newCachingValidationSupport(
|
|
||||||
JpaValidationSupportChain theJpaValidationSupportChain) {
|
|
||||||
return newCachingValidationSupport(theJpaValidationSupportChain, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static CachingValidationSupport newCachingValidationSupport(
|
|
||||||
JpaValidationSupportChain theJpaValidationSupportChain,
|
|
||||||
boolean theIsEnabledValidationForCodingsLogicalAnd) {
|
|
||||||
// Short timeout for code translation because TermConceptMappingSvcImpl has its own caching
|
|
||||||
CachingValidationSupport.CacheTimeouts cacheTimeouts =
|
|
||||||
CachingValidationSupport.CacheTimeouts.defaultValues().setTranslateCodeMillis(1000);
|
|
||||||
|
|
||||||
return new CachingValidationSupport(
|
|
||||||
theJpaValidationSupportChain, cacheTimeouts, theIsEnabledValidationForCodingsLogicalAnd);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -48,6 +48,9 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZonedDateTime;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -243,8 +246,23 @@ public class HistoryBuilder {
|
||||||
Subquery<Date> pastDateSubQuery = theQuery.subquery(Date.class);
|
Subquery<Date> pastDateSubQuery = theQuery.subquery(Date.class);
|
||||||
Root<ResourceHistoryTable> subQueryResourceHistory = pastDateSubQuery.from(ResourceHistoryTable.class);
|
Root<ResourceHistoryTable> subQueryResourceHistory = pastDateSubQuery.from(ResourceHistoryTable.class);
|
||||||
Expression myUpdatedMostRecent = theCriteriaBuilder.max(subQueryResourceHistory.get("myUpdated"));
|
Expression myUpdatedMostRecent = theCriteriaBuilder.max(subQueryResourceHistory.get("myUpdated"));
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This conversion from the Date in myRangeEndInclusive into a ZonedDateTime is an experiment -
|
||||||
|
* There is an intermittent test failure in testSearchHistoryWithAtAndGtParameters() that I can't
|
||||||
|
* figure out. But I've added a ton of logging to the error it fails with and I noticed that
|
||||||
|
* we emit SQL along the lines of
|
||||||
|
* select coalesce(max(rht2_0.RES_UPDATED), timestamp with time zone '2024-10-05 18:24:48.172000000Z')
|
||||||
|
* for this date, and all other dates are in GMT so this is an experiment. If nothing changes,
|
||||||
|
* we can roll this back to
|
||||||
|
* theCriteriaBuilder.literal(myRangeStartInclusive)
|
||||||
|
* JA 20241005
|
||||||
|
*/
|
||||||
|
ZonedDateTime rangeStart =
|
||||||
|
ZonedDateTime.ofInstant(Instant.ofEpochMilli(myRangeStartInclusive.getTime()), ZoneId.of("GMT"));
|
||||||
|
|
||||||
Expression myUpdatedMostRecentOrDefault =
|
Expression myUpdatedMostRecentOrDefault =
|
||||||
theCriteriaBuilder.coalesce(myUpdatedMostRecent, theCriteriaBuilder.literal(myRangeStartInclusive));
|
theCriteriaBuilder.coalesce(myUpdatedMostRecent, theCriteriaBuilder.literal(rangeStart));
|
||||||
|
|
||||||
pastDateSubQuery
|
pastDateSubQuery
|
||||||
.select(myUpdatedMostRecentOrDefault)
|
.select(myUpdatedMostRecentOrDefault)
|
||||||
|
|
|
@ -164,6 +164,7 @@ public class JpaPersistedResourceValidationSupport implements IValidationSupport
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBaseResource fetchStructureDefinition(String theUrl) {
|
public IBaseResource fetchStructureDefinition(String theUrl) {
|
||||||
|
assert myStructureDefinitionType != null;
|
||||||
return fetchResource(myStructureDefinitionType, theUrl);
|
return fetchResource(myStructureDefinitionType, theUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -117,7 +117,6 @@ import org.hibernate.search.mapper.orm.Search;
|
||||||
import org.hibernate.search.mapper.orm.common.EntityReference;
|
import org.hibernate.search.mapper.orm.common.EntityReference;
|
||||||
import org.hibernate.search.mapper.orm.session.SearchSession;
|
import org.hibernate.search.mapper.orm.session.SearchSession;
|
||||||
import org.hibernate.search.mapper.pojo.massindexing.impl.PojoMassIndexingLoggingMonitor;
|
import org.hibernate.search.mapper.pojo.massindexing.impl.PojoMassIndexingLoggingMonitor;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
||||||
import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_40_50;
|
import org.hl7.fhir.convertors.advisors.impl.BaseAdvisor_40_50;
|
||||||
import org.hl7.fhir.convertors.context.ConversionContext40_50;
|
import org.hl7.fhir.convertors.context.ConversionContext40_50;
|
||||||
|
@ -284,9 +283,6 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
|
||||||
@Autowired
|
@Autowired
|
||||||
private HibernatePropertiesProvider myHibernatePropertiesProvider;
|
private HibernatePropertiesProvider myHibernatePropertiesProvider;
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private CachingValidationSupport myCachingValidationSupport;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private VersionCanonicalizer myVersionCanonicalizer;
|
private VersionCanonicalizer myVersionCanonicalizer;
|
||||||
|
|
||||||
|
@ -2509,9 +2505,7 @@ public class TermReadSvcImpl implements ITermReadSvc, IHasScheduledJobs {
|
||||||
* results while they test changes, which is probably a worthwhile sacrifice
|
* results while they test changes, which is probably a worthwhile sacrifice
|
||||||
*/
|
*/
|
||||||
private void afterValueSetExpansionStatusChange() {
|
private void afterValueSetExpansionStatusChange() {
|
||||||
// TODO: JA2 - Move this caching into the memorycacheservice, and only purge the
|
provideValidationSupport().invalidateCaches();
|
||||||
// relevant individual cache
|
|
||||||
myCachingValidationSupport.invalidateCaches();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized boolean isPreExpandingValueSets() {
|
private synchronized boolean isPreExpandingValueSets() {
|
||||||
|
|
|
@ -20,6 +20,9 @@
|
||||||
package ca.uhn.fhir.jpa.util;
|
package ca.uhn.fhir.jpa.util;
|
||||||
|
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
import ca.uhn.fhir.model.dstu2.resource.Subscription;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
||||||
|
@ -29,31 +32,32 @@ import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
|
||||||
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.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.subscription.SubscriptionConstants.ORDER_SUBSCRIPTION_ACTIVATING;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
|
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
|
||||||
* {@link SubscriptionStatusEnum#REQUESTED} state and prevents clients from changing the status.
|
* {@link SubscriptionStatusEnum#REQUESTED} state and prevents clients from changing the status.
|
||||||
*/
|
*/
|
||||||
public class SubscriptionsRequireManualActivationInterceptorDstu2 extends ServerOperationInterceptorAdapter {
|
@Interceptor
|
||||||
|
public class SubscriptionsRequireManualActivationInterceptorDstu2 {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("mySubscriptionDaoDstu2")
|
@Qualifier("mySubscriptionDaoDstu2")
|
||||||
private IFhirResourceDao<Subscription> myDao;
|
private IFhirResourceDao<Subscription> myDao;
|
||||||
|
|
||||||
@Override
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, order = ORDER_SUBSCRIPTION_ACTIVATING)
|
||||||
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
||||||
if (myDao.getContext().getResourceType(theResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
if (myDao.getContext().getResourceType(theResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||||
verifyStatusOk(RestOperationTypeEnum.CREATE, null, theResource);
|
verifyStatusOk(RestOperationTypeEnum.CREATE, null, theResource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, order = ORDER_SUBSCRIPTION_ACTIVATING)
|
||||||
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||||
if (myDao.getContext().getResourceType(theNewResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
if (myDao.getContext().getResourceType(theNewResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||||
verifyStatusOk(RestOperationTypeEnum.UPDATE, theOldResource, theNewResource);
|
verifyStatusOk(RestOperationTypeEnum.UPDATE, theOldResource, theNewResource);
|
||||||
|
|
|
@ -20,13 +20,15 @@
|
||||||
package ca.uhn.fhir.jpa.util;
|
package ca.uhn.fhir.jpa.util;
|
||||||
|
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
|
||||||
import org.hl7.fhir.dstu3.model.Subscription;
|
import org.hl7.fhir.dstu3.model.Subscription;
|
||||||
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
|
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionChannelType;
|
||||||
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
import org.hl7.fhir.dstu3.model.Subscription.SubscriptionStatus;
|
||||||
|
@ -34,26 +36,28 @@ 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.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.subscription.SubscriptionConstants.ORDER_SUBSCRIPTION_ACTIVATING;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
|
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
|
||||||
* {@link SubscriptionStatus#REQUESTED} state and prevents clients from changing the status.
|
* {@link SubscriptionStatus#REQUESTED} state and prevents clients from changing the status.
|
||||||
*/
|
*/
|
||||||
public class SubscriptionsRequireManualActivationInterceptorDstu3 extends ServerOperationInterceptorAdapter {
|
@Interceptor
|
||||||
|
public class SubscriptionsRequireManualActivationInterceptorDstu3 {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("mySubscriptionDaoDstu3")
|
@Qualifier("mySubscriptionDaoDstu3")
|
||||||
private IFhirResourceDao<Subscription> myDao;
|
private IFhirResourceDao<Subscription> myDao;
|
||||||
|
|
||||||
@Override
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, order = ORDER_SUBSCRIPTION_ACTIVATING)
|
||||||
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
||||||
if (myDao.getContext().getResourceType(theResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
if (myDao.getContext().getResourceType(theResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||||
verifyStatusOk(RestOperationTypeEnum.CREATE, null, theResource);
|
verifyStatusOk(RestOperationTypeEnum.CREATE, null, theResource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, order = ORDER_SUBSCRIPTION_ACTIVATING)
|
||||||
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||||
if (myDao.getContext().getResourceType(theNewResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
if (myDao.getContext().getResourceType(theNewResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||||
verifyStatusOk(RestOperationTypeEnum.UPDATE, theOldResource, theNewResource);
|
verifyStatusOk(RestOperationTypeEnum.UPDATE, theOldResource, theNewResource);
|
||||||
|
|
|
@ -20,13 +20,15 @@
|
||||||
package ca.uhn.fhir.jpa.util;
|
package ca.uhn.fhir.jpa.util;
|
||||||
|
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.Subscription;
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
import org.hl7.fhir.r4.model.Subscription.SubscriptionChannelType;
|
||||||
|
@ -34,26 +36,28 @@ import org.hl7.fhir.r4.model.Subscription.SubscriptionStatus;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.subscription.SubscriptionConstants.ORDER_SUBSCRIPTION_ACTIVATING;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
|
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
|
||||||
* {@link SubscriptionStatus#REQUESTED} state and prevents clients from changing the status.
|
* {@link SubscriptionStatus#REQUESTED} state and prevents clients from changing the status.
|
||||||
*/
|
*/
|
||||||
public class SubscriptionsRequireManualActivationInterceptorR4 extends ServerOperationInterceptorAdapter {
|
@Interceptor
|
||||||
|
public class SubscriptionsRequireManualActivationInterceptorR4 {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("mySubscriptionDaoR4")
|
@Qualifier("mySubscriptionDaoR4")
|
||||||
private IFhirResourceDao<Subscription> myDao;
|
private IFhirResourceDao<Subscription> myDao;
|
||||||
|
|
||||||
@Override
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, order = ORDER_SUBSCRIPTION_ACTIVATING)
|
||||||
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
||||||
if (myDao.getContext().getResourceType(theResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
if (myDao.getContext().getResourceType(theResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||||
verifyStatusOk(RestOperationTypeEnum.CREATE, null, theResource);
|
verifyStatusOk(RestOperationTypeEnum.CREATE, null, theResource);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, order = ORDER_SUBSCRIPTION_ACTIVATING)
|
||||||
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||||
if (myDao.getContext().getResourceType(theNewResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
if (myDao.getContext().getResourceType(theNewResource).equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||||
verifyStatusOk(RestOperationTypeEnum.UPDATE, theOldResource, theNewResource);
|
verifyStatusOk(RestOperationTypeEnum.UPDATE, theOldResource, theNewResource);
|
||||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.validation;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
|
import ca.uhn.fhir.jpa.config.JpaConfig;
|
||||||
import ca.uhn.fhir.jpa.packages.NpmJpaValidationSupport;
|
import ca.uhn.fhir.jpa.packages.NpmJpaValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermConceptMappingSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermReadSvc;
|
||||||
|
@ -39,7 +40,7 @@ public class JpaValidationSupportChain extends ValidationSupportChain {
|
||||||
private final FhirContext myFhirContext;
|
private final FhirContext myFhirContext;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myJpaValidationSupport")
|
@Qualifier(JpaConfig.JPA_VALIDATION_SUPPORT)
|
||||||
public IValidationSupport myJpaValidationSupport;
|
public IValidationSupport myJpaValidationSupport;
|
||||||
|
|
||||||
@Qualifier("myDefaultProfileValidationSupport")
|
@Qualifier("myDefaultProfileValidationSupport")
|
||||||
|
@ -64,7 +65,13 @@ public class JpaValidationSupportChain extends ValidationSupportChain {
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public JpaValidationSupportChain(FhirContext theFhirContext) {
|
public JpaValidationSupportChain(
|
||||||
|
FhirContext theFhirContext, ValidationSupportChain.CacheConfiguration theCacheConfiguration) {
|
||||||
|
super(theCacheConfiguration);
|
||||||
|
|
||||||
|
assert theFhirContext != null;
|
||||||
|
assert theCacheConfiguration != null;
|
||||||
|
|
||||||
myFhirContext = theFhirContext;
|
myFhirContext = theFhirContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,7 @@ import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.subscription.SubscriptionConstants.ORDER_SUBSCRIPTION_VALIDATING;
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
|
|
||||||
@Interceptor
|
@Interceptor
|
||||||
|
@ -92,14 +93,14 @@ public class SubscriptionValidatingInterceptor {
|
||||||
@Autowired
|
@Autowired
|
||||||
private SubscriptionChannelTypeValidatorFactory mySubscriptionChannelTypeValidatorFactory;
|
private SubscriptionChannelTypeValidatorFactory mySubscriptionChannelTypeValidatorFactory;
|
||||||
|
|
||||||
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED)
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED, order = ORDER_SUBSCRIPTION_VALIDATING)
|
||||||
public void resourcePreCreate(
|
public void resourcePreCreate(
|
||||||
IBaseResource theResource, RequestDetails theRequestDetails, RequestPartitionId theRequestPartitionId) {
|
IBaseResource theResource, RequestDetails theRequestDetails, RequestPartitionId theRequestPartitionId) {
|
||||||
validateSubmittedSubscription(
|
validateSubmittedSubscription(
|
||||||
theResource, theRequestDetails, theRequestPartitionId, Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED);
|
theResource, theRequestDetails, theRequestPartitionId, Pointcut.STORAGE_PRESTORAGE_RESOURCE_CREATED);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Hook(Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED)
|
@Hook(value = Pointcut.STORAGE_PRESTORAGE_RESOURCE_UPDATED, order = ORDER_SUBSCRIPTION_VALIDATING)
|
||||||
public void resourceUpdated(
|
public void resourceUpdated(
|
||||||
IBaseResource theOldResource,
|
IBaseResource theOldResource,
|
||||||
IBaseResource theResource,
|
IBaseResource theResource,
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -58,8 +58,6 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
|
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3TerminologyTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3TerminologyTest.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
private CachingValidationSupport myCachingValidationSupport;
|
|
||||||
@Autowired
|
|
||||||
private ITermDeferredStorageSvc myTermDeferredStorageSvc;
|
private ITermDeferredStorageSvc myTermDeferredStorageSvc;
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -69,10 +67,12 @@ public class FhirResourceDaoDstu3TerminologyTest extends BaseJpaDstu3Test {
|
||||||
TermReindexingSvcImpl.setForceSaveDeferredAlwaysForUnitTest(false);
|
TermReindexingSvcImpl.setForceSaveDeferredAlwaysForUnitTest(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void before() {
|
public void before() throws Exception {
|
||||||
|
super.before();
|
||||||
myStorageSettings.setMaximumExpansionSize(5000);
|
myStorageSettings.setMaximumExpansionSize(5000);
|
||||||
myCachingValidationSupport.invalidateCaches();
|
myValidationSupport.invalidateCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeSystem createExternalCs() {
|
private CodeSystem createExternalCs() {
|
||||||
|
|
|
@ -14,7 +14,6 @@ import ca.uhn.fhir.test.utilities.ProxyUtil;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||||
|
@ -55,8 +54,6 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IValidatorModule myValidatorModule;
|
private IValidatorModule myValidatorModule;
|
||||||
@Autowired
|
@Autowired
|
||||||
private CachingValidationSupport myValidationSupport;
|
|
||||||
@Autowired
|
|
||||||
private FhirInstanceValidator myFhirInstanceValidator;
|
private FhirInstanceValidator myFhirInstanceValidator;
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier(JpaConfig.JPA_VALIDATION_SUPPORT)
|
@Qualifier(JpaConfig.JPA_VALIDATION_SUPPORT)
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.hl7.fhir.r4.model.Library;
|
import org.hl7.fhir.r4.model.Library;
|
||||||
import org.hl7.fhir.r4.model.Measure;
|
import org.hl7.fhir.r4.model.Measure;
|
||||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Disabled;
|
import org.junit.jupiter.api.Disabled;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -38,7 +39,7 @@ import static org.mockito.Mockito.when;
|
||||||
public class JpaPersistedResourceValidationSupportFromValidationChainTest {
|
public class JpaPersistedResourceValidationSupportFromValidationChainTest {
|
||||||
private static final FhirContext ourCtx = FhirContext.forR4();
|
private static final FhirContext ourCtx = FhirContext.forR4();
|
||||||
|
|
||||||
private IValidationSupport jpaValidator;
|
private JpaPersistedResourceValidationSupport jpaValidator;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private DaoRegistry myDaoRegistry;
|
private DaoRegistry myDaoRegistry;
|
||||||
|
@ -58,6 +59,7 @@ public class JpaPersistedResourceValidationSupportFromValidationChainTest {
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
jpaValidator = new JpaPersistedResourceValidationSupport(ourCtx);
|
jpaValidator = new JpaPersistedResourceValidationSupport(ourCtx);
|
||||||
|
jpaValidator.start();
|
||||||
ReflectionTestUtils.setField(jpaValidator, "myDaoRegistry", myDaoRegistry);
|
ReflectionTestUtils.setField(jpaValidator, "myDaoRegistry", myDaoRegistry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ public class FhirResourceDaoR4TerminologyTest extends BaseJpaR4Test {
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
super.before();
|
super.before();
|
||||||
myStorageSettings.setMaximumExpansionSize(5000);
|
myStorageSettings.setMaximumExpansionSize(5000);
|
||||||
myCachingValidationSupport.invalidateCaches();
|
myValidationSupport.invalidateCaches();
|
||||||
}
|
}
|
||||||
|
|
||||||
private CodeSystem createExternalCs() {
|
private CodeSystem createExternalCs() {
|
||||||
|
|
|
@ -38,6 +38,7 @@ import ch.qos.logback.classic.Level;
|
||||||
import org.apache.commons.io.IOUtils;
|
import org.apache.commons.io.IOUtils;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.InMemoryTerminologyServerValidationSupport;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.UnknownCodeSystemWarningValidationSupport;
|
import org.hl7.fhir.common.hapi.validation.support.UnknownCodeSystemWarningValidationSupport;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
@ -2237,6 +2238,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
||||||
createStructureDefinitionInDao();
|
createStructureDefinitionInDao();
|
||||||
|
|
||||||
// execute
|
// execute
|
||||||
|
((ValidationSupportChain)myValidationSupport).invalidateExpiringCaches();
|
||||||
final String outcomePatientValidateAfterStructDef = validate(PATIENT_WITH_REAL_URL);
|
final String outcomePatientValidateAfterStructDef = validate(PATIENT_WITH_REAL_URL);
|
||||||
|
|
||||||
// verify
|
// verify
|
||||||
|
|
|
@ -169,7 +169,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
||||||
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
logAllValueSets();
|
logAllValueSets();
|
||||||
myCachingValidationSupport.invalidateCaches();
|
myValidationSupport.invalidateCaches();
|
||||||
|
|
||||||
outcome = myValidationSupport.validateCode(ctx, options, "http://cs", "child10", null, "http://vs");
|
outcome = myValidationSupport.validateCode(ctx, options, "http://cs", "child10", null, "http://vs");
|
||||||
assertNotNull(outcome);
|
assertNotNull(outcome);
|
||||||
|
@ -272,7 +272,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
||||||
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
logAllValueSets();
|
logAllValueSets();
|
||||||
myCachingValidationSupport.invalidateCaches();
|
myValidationSupport.invalidateCaches();
|
||||||
|
|
||||||
outcome = myValidationSupport.validateCode(ctx, options, "http://cs", "child10", null, "http://vs");
|
outcome = myValidationSupport.validateCode(ctx, options, "http://cs", "child10", null, "http://vs");
|
||||||
assertNotNull(outcome);
|
assertNotNull(outcome);
|
||||||
|
|
|
@ -0,0 +1,496 @@
|
||||||
|
package ca.uhn.fhir.jpa.interceptor;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
|
import ca.uhn.fhir.jpa.test.BaseJpaR4Test;
|
||||||
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.RequiredParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||||
|
import ca.uhn.fhir.rest.param.UriParam;
|
||||||
|
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||||
|
import ca.uhn.fhir.test.utilities.server.RestfulServerExtension;
|
||||||
|
import com.google.common.collect.ListMultimap;
|
||||||
|
import com.google.common.collect.MultimapBuilder;
|
||||||
|
import jakarta.annotation.Nonnull;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.RemoteTerminologyServiceValidationSupport;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.support.ValidationSupportChain;
|
||||||
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.hl7.fhir.r4.model.BooleanType;
|
||||||
|
import org.hl7.fhir.r4.model.CodeSystem;
|
||||||
|
import org.hl7.fhir.r4.model.CodeType;
|
||||||
|
import org.hl7.fhir.r4.model.CodeableConcept;
|
||||||
|
import org.hl7.fhir.r4.model.Coding;
|
||||||
|
import org.hl7.fhir.r4.model.ElementDefinition;
|
||||||
|
import org.hl7.fhir.r4.model.Enumerations;
|
||||||
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
import org.hl7.fhir.r4.model.OperationOutcome;
|
||||||
|
import org.hl7.fhir.r4.model.Parameters;
|
||||||
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
|
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
|
import org.hl7.fhir.r4.model.UriType;
|
||||||
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
|
import org.hl7.fhir.r5.utils.validation.constants.BestPracticeWarningLevel;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static java.util.Objects.requireNonNull;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This test verifies how {@link RemoteTerminologyServiceValidationSupport} interacts with
|
||||||
|
* the rest of the ValidationSupportChain. The aim here is that we should perform as few
|
||||||
|
* interactions across the network as we can, so any caching that avoids a lookup through
|
||||||
|
* the remote module is a good thing. We're also testing that we don't open more database
|
||||||
|
* connections than we need to, since every connection is a delay.
|
||||||
|
*/
|
||||||
|
public class RemoteTerminologyServiceJpaR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
private static final MyCodeSystemProvider ourCodeSystemProvider = new MyCodeSystemProvider();
|
||||||
|
private static final MyValueSetProvider ourValueSetProvider = new MyValueSetProvider();
|
||||||
|
@RegisterExtension
|
||||||
|
private static final RestfulServerExtension ourTerminologyServer = new RestfulServerExtension(FhirContext.forR4Cached())
|
||||||
|
.registerProvider(ourCodeSystemProvider)
|
||||||
|
.registerProvider(ourValueSetProvider);
|
||||||
|
@Autowired
|
||||||
|
private ValidationSupportChain myValidationSupportChain;
|
||||||
|
@Autowired
|
||||||
|
private FhirInstanceValidator myFhirInstanceValidator;
|
||||||
|
private RemoteTerminologyServiceValidationSupport myRemoteTerminologyService;
|
||||||
|
private ValidationSupportChain myInternalValidationSupport;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@BeforeEach
|
||||||
|
public void before() throws Exception {
|
||||||
|
super.before();
|
||||||
|
|
||||||
|
myFhirInstanceValidator.setBestPracticeWarningLevel(BestPracticeWarningLevel.Ignore);
|
||||||
|
|
||||||
|
List<IValidationSupport> original = myValidationSupportChain.getValidationSupports();
|
||||||
|
myInternalValidationSupport = new ValidationSupportChain(original);
|
||||||
|
|
||||||
|
myRemoteTerminologyService = new RemoteTerminologyServiceValidationSupport(myFhirContext, ourTerminologyServer.getBaseUrl());
|
||||||
|
myValidationSupportChain.addValidationSupport(0, myRemoteTerminologyService);
|
||||||
|
myValidationSupportChain.invalidateCaches();
|
||||||
|
|
||||||
|
// Warm this as it's needed once by the FhirPath evaluator on startup
|
||||||
|
// so this avoids having different connection counts depending on
|
||||||
|
// which test method is called first. This is a non-expiring cache, so
|
||||||
|
// pre-warming here isn't affecting anything meaningful.
|
||||||
|
myValidationSupportChain.fetchAllStructureDefinitions();
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
public void after() throws Exception {
|
||||||
|
myValidationSupportChain.logCacheSizes();
|
||||||
|
myValidationSupportChain.removeValidationSupport(myRemoteTerminologyService);
|
||||||
|
|
||||||
|
ourValueSetProvider.clearAll();
|
||||||
|
ourCodeSystemProvider.clearAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateSimpleCode() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setGender(Enumerations.AdministrativeGender.FEMALE);
|
||||||
|
|
||||||
|
// Test 1
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBaseOperationOutcome outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 1
|
||||||
|
Assertions.assertEquals(2, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender",
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender"
|
||||||
|
);
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/administrative-gender",
|
||||||
|
"http://hl7.org/fhir/administrative-gender"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test 2 (should rely on caches)
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 2
|
||||||
|
Assertions.assertEquals(0, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateSimpleCode_SupportedByRemoteService() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setGender(Enumerations.AdministrativeGender.FEMALE);
|
||||||
|
ourValueSetProvider.add((ValueSet) requireNonNull(myInternalValidationSupport.fetchValueSet("http://hl7.org/fhir/ValueSet/administrative-gender")));
|
||||||
|
ourCodeSystemProvider.add((CodeSystem) requireNonNull(myInternalValidationSupport.fetchCodeSystem("http://hl7.org/fhir/administrative-gender")));
|
||||||
|
|
||||||
|
// Test 1
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBaseOperationOutcome outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 1
|
||||||
|
Assertions.assertEquals(0, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender",
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender"
|
||||||
|
);
|
||||||
|
assertThat(ourValueSetProvider.myValidatedCodes).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender#http://hl7.org/fhir/administrative-gender#female"
|
||||||
|
);
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/administrative-gender"
|
||||||
|
);
|
||||||
|
assertThat(ourCodeSystemProvider.myValidatedCodes).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/administrative-gender#female#null"
|
||||||
|
);
|
||||||
|
|
||||||
|
// Test 2 (should rely on caches)
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 2
|
||||||
|
Assertions.assertEquals(0, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourValueSetProvider.myValidatedCodes).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.myValidatedCodes).asList().isEmpty();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If the remote terminology service is serving up stub ValueSet and CodeSystem
|
||||||
|
* resources, make sure we still behave in a sane way. This probably wouldn't
|
||||||
|
* happen exactly like this, but the idea here is that the server could
|
||||||
|
* serve up weird contents where our internal services couldn't determine
|
||||||
|
* the implicit system from the ValueSet.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testValidateSimpleCode_SupportedByRemoteService_EmptyValueSet() {
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setGender(Enumerations.AdministrativeGender.FEMALE);
|
||||||
|
ourValueSetProvider.add((ValueSet) new ValueSet().setUrl("http://hl7.org/fhir/ValueSet/administrative-gender").setId("gender"));
|
||||||
|
ourCodeSystemProvider.add((CodeSystem) new CodeSystem().setUrl("http://hl7.org/fhir/administrative-gender").setId("gender"));
|
||||||
|
|
||||||
|
// Test 1
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBaseOperationOutcome outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 1
|
||||||
|
Assertions.assertEquals(0, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender",
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender"
|
||||||
|
);
|
||||||
|
assertThat(ourValueSetProvider.myValidatedCodes).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/ValueSet/administrative-gender#null#female"
|
||||||
|
);
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.myValidatedCodes).asList().isEmpty();
|
||||||
|
|
||||||
|
// Test 2 (should rely on caches)
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 2
|
||||||
|
Assertions.assertEquals(0, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourValueSetProvider.myValidatedCodes).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.myValidatedCodes).asList().isEmpty();
|
||||||
|
|
||||||
|
myValidationSupportChain.logCacheSizes();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateSimpleExtension() {
|
||||||
|
// Setup
|
||||||
|
myStructureDefinitionDao.create(createFooExtensionStructureDefinition(), mySrd);
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addExtension("http://foo", new StringType("BAR"));
|
||||||
|
|
||||||
|
// Test 1
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBaseOperationOutcome outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 1
|
||||||
|
myCaptureQueriesListener.logSelectQueries();
|
||||||
|
Assertions.assertEquals(4, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
|
||||||
|
// Test 2 (should rely on caches)
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
outcome = validate(p);
|
||||||
|
assertSuccess(outcome);
|
||||||
|
|
||||||
|
// Verify 2
|
||||||
|
Assertions.assertEquals(0, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateMultipleCodings() {
|
||||||
|
// Setup
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addIdentifier()
|
||||||
|
// Valid type
|
||||||
|
.setType(new CodeableConcept().addCoding(new Coding("http://terminology.hl7.org/CodeSystem/v2-0203", "DL", null)))
|
||||||
|
.setSystem("http://my-system-1")
|
||||||
|
.setValue("1");
|
||||||
|
p.addIdentifier()
|
||||||
|
// Valid type
|
||||||
|
.setType(new CodeableConcept().addCoding(new Coding("http://terminology.hl7.org/CodeSystem/v2-0203", "PPN", null)))
|
||||||
|
.setSystem("http://my-system-2")
|
||||||
|
.setValue("2");
|
||||||
|
p.addIdentifier()
|
||||||
|
// Invalid type
|
||||||
|
.setType(new CodeableConcept().addCoding(new Coding("http://terminology.hl7.org/CodeSystem/v2-0203", "FOO", null)))
|
||||||
|
.setSystem("http://my-system-3")
|
||||||
|
.setValue("3");
|
||||||
|
|
||||||
|
// Test 1
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
IBaseOperationOutcome outcome = validate(p);
|
||||||
|
assertHasIssuesContainingMessages(outcome,
|
||||||
|
"Unknown code 'http://terminology.hl7.org/CodeSystem/v2-0203#FOO'",
|
||||||
|
"None of the codings provided are in the value set 'IdentifierType'");
|
||||||
|
|
||||||
|
// Verify 1
|
||||||
|
Assertions.assertEquals(2, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://hl7.org/fhir/ValueSet/identifier-type",
|
||||||
|
"http://hl7.org/fhir/ValueSet/identifier-type"
|
||||||
|
);
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().containsExactlyInAnyOrder(
|
||||||
|
"http://terminology.hl7.org/CodeSystem/v2-0203",
|
||||||
|
"http://terminology.hl7.org/CodeSystem/v2-0203"
|
||||||
|
);
|
||||||
|
assertEquals(0, ourValueSetProvider.myValidatedCodes.size());
|
||||||
|
assertEquals(0, ourCodeSystemProvider.myValidatedCodes.size());
|
||||||
|
|
||||||
|
// Test 2 (should rely on caches)
|
||||||
|
ourCodeSystemProvider.clearCalls();
|
||||||
|
ourValueSetProvider.clearCalls();
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
|
validate(p);
|
||||||
|
|
||||||
|
// Verify 2
|
||||||
|
Assertions.assertEquals(0, myCaptureQueriesListener.countGetConnections());
|
||||||
|
assertThat(ourValueSetProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertThat(ourCodeSystemProvider.mySearchUrls).asList().isEmpty();
|
||||||
|
assertEquals(0, ourValueSetProvider.myValidatedCodes.size());
|
||||||
|
assertEquals(0, ourCodeSystemProvider.myValidatedCodes.size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertSuccess(IBaseOperationOutcome theOutcome) {
|
||||||
|
OperationOutcome oo = (OperationOutcome) theOutcome;
|
||||||
|
assertEquals(1, oo.getIssue().size(), () -> encode(oo));
|
||||||
|
assertThat(oo.getIssue().get(0).getDiagnostics()).as(() -> encode(oo)).contains("No issues detected");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void assertHasIssuesContainingMessages(IBaseOperationOutcome theOutcome, String... theDiagnosticMessageFragments) {
|
||||||
|
OperationOutcome oo = (OperationOutcome) theOutcome;
|
||||||
|
assertEquals(theDiagnosticMessageFragments.length, oo.getIssue().size(), () -> encode(oo));
|
||||||
|
for (int i = 0; i < theDiagnosticMessageFragments.length; i++) {
|
||||||
|
assertThat(oo.getIssue().get(i).getDiagnostics()).as(() -> encode(oo)).contains(theDiagnosticMessageFragments[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private IBaseOperationOutcome validate(Patient p) {
|
||||||
|
return myPatientDao.validate(p, null, myFhirContext.newJsonParser().setPrettyPrint(true).encodeResourceToString(p), EncodingEnum.JSON, ValidationModeEnum.CREATE, null, mySrd).getOperationOutcome();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a StructureDefinition for an extension with URL <a href="http://foo">http://foo</a>
|
||||||
|
*/
|
||||||
|
@Nonnull
|
||||||
|
private static StructureDefinition createFooExtensionStructureDefinition() {
|
||||||
|
StructureDefinition sd = new StructureDefinition();
|
||||||
|
sd.setUrl("http://foo");
|
||||||
|
sd.setFhirVersion(Enumerations.FHIRVersion._4_0_1);
|
||||||
|
sd.setKind(StructureDefinition.StructureDefinitionKind.COMPLEXTYPE);
|
||||||
|
sd.setAbstract(false);
|
||||||
|
sd.addContext().setType(StructureDefinition.ExtensionContextType.ELEMENT).setExpression("Patient");
|
||||||
|
sd.setType("Extension");
|
||||||
|
sd.setBaseDefinition("http://hl7.org/fhir/StructureDefinition/Extension");
|
||||||
|
sd.setDerivation(StructureDefinition.TypeDerivationRule.CONSTRAINT);
|
||||||
|
ElementDefinition e0 = sd.getDifferential().addElement();
|
||||||
|
e0.setId("Extension");
|
||||||
|
e0.setPath("Extension");
|
||||||
|
ElementDefinition e1 = sd.getDifferential().addElement();
|
||||||
|
e1.setId("Extension.url");
|
||||||
|
e1.setPath("Extension.url");
|
||||||
|
e1.setFixed(new UriType("http://foo"));
|
||||||
|
ElementDefinition e2 = sd.getDifferential().addElement();
|
||||||
|
e2.setId("Extension.value[x]");
|
||||||
|
e2.setPath("Extension.value[x]");
|
||||||
|
e2.addType().setCode("string");
|
||||||
|
return sd;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String toValue(IPrimitiveType<String> theUrlType) {
|
||||||
|
return theUrlType != null ? theUrlType.getValue() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class MyCodeSystemProvider implements IResourceProvider {
|
||||||
|
private final ListMultimap<String, CodeSystem> myUrlToCodeSystems = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||||
|
private final List<String> mySearchUrls = new ArrayList<>();
|
||||||
|
private final List<String> myValidatedCodes = new ArrayList<>();
|
||||||
|
|
||||||
|
public void clearAll() {
|
||||||
|
myUrlToCodeSystems.clear();
|
||||||
|
clearCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCalls() {
|
||||||
|
mySearchUrls.clear();
|
||||||
|
myValidatedCodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(name = "validate-code", idempotent = true, returnParameters = {
|
||||||
|
@OperationParam(name = "result", type = BooleanType.class, min = 1),
|
||||||
|
@OperationParam(name = "message", type = StringType.class),
|
||||||
|
@OperationParam(name = "display", type = StringType.class)
|
||||||
|
})
|
||||||
|
public Parameters validateCode(
|
||||||
|
HttpServletRequest theServletRequest,
|
||||||
|
@IdParam(optional = true) IdType theId,
|
||||||
|
@OperationParam(name = "url", min = 0, max = 1) UriType theCodeSystemUrl,
|
||||||
|
@OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
|
||||||
|
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay
|
||||||
|
) {
|
||||||
|
myValidatedCodes.add(toValue(theCodeSystemUrl) + "#" + toValue(theCode) + "#" + toValue(theDisplay));
|
||||||
|
|
||||||
|
Parameters retVal = new Parameters();
|
||||||
|
retVal.addParameter("result", new BooleanType(true));
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search
|
||||||
|
public List<CodeSystem> find(@RequiredParam(name = "url") UriParam theUrlParam) {
|
||||||
|
String url = theUrlParam != null ? theUrlParam.getValue() : null;
|
||||||
|
mySearchUrls.add(url);
|
||||||
|
return myUrlToCodeSystems.get(defaultString(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return CodeSystem.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(CodeSystem theCs) {
|
||||||
|
assert theCs != null;
|
||||||
|
assert isNotBlank(theCs.getUrl());
|
||||||
|
myUrlToCodeSystems.put(theCs.getUrl(), theCs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private static class MyValueSetProvider implements IResourceProvider {
|
||||||
|
|
||||||
|
private final ListMultimap<String, ValueSet> myUrlToValueSets = MultimapBuilder.hashKeys().arrayListValues().build();
|
||||||
|
private final List<String> mySearchUrls = new ArrayList<>();
|
||||||
|
private final List<String> myValidatedCodes = new ArrayList<>();
|
||||||
|
|
||||||
|
public void clearAll() {
|
||||||
|
myUrlToValueSets.clear();
|
||||||
|
clearCalls();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void clearCalls() {
|
||||||
|
mySearchUrls.clear();
|
||||||
|
myValidatedCodes.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Operation(name = "validate-code", idempotent = true, returnParameters = {
|
||||||
|
@OperationParam(name = "result", type = BooleanType.class, min = 1),
|
||||||
|
@OperationParam(name = "message", type = StringType.class),
|
||||||
|
@OperationParam(name = "display", type = StringType.class)
|
||||||
|
})
|
||||||
|
public Parameters validateCode(
|
||||||
|
HttpServletRequest theServletRequest,
|
||||||
|
@OperationParam(name = "url", min = 0, max = 1) UriType theValueSetUrl,
|
||||||
|
@OperationParam(name = "code", min = 0, max = 1) CodeType theCode,
|
||||||
|
@OperationParam(name = "system", min = 0, max = 1) UriType theSystem,
|
||||||
|
@OperationParam(name = "display", min = 0, max = 1) StringType theDisplay,
|
||||||
|
@OperationParam(name = "valueSet") ValueSet theValueSet
|
||||||
|
) {
|
||||||
|
myValidatedCodes.add(toValue(theValueSetUrl) + "#" + toValue(theSystem) + "#" + toValue(theCode));
|
||||||
|
|
||||||
|
Parameters retVal = new Parameters();
|
||||||
|
retVal.addParameter("result", new BooleanType(true));
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Search
|
||||||
|
public List<ValueSet> find(@OptionalParam(name = "url") UriParam theUrlParam) {
|
||||||
|
String url = theUrlParam != null ? theUrlParam.getValue() : null;
|
||||||
|
mySearchUrls.add(url);
|
||||||
|
List<ValueSet> retVal = myUrlToValueSets.get(defaultString(url));
|
||||||
|
ourLog.info("Remote terminology fetch ValueSet[{}] - Found: {}", url, !retVal.isEmpty());
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
|
return ValueSet.class;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(ValueSet theVs) {
|
||||||
|
assert theVs != null;
|
||||||
|
assert isNotBlank(theVs.getUrl());
|
||||||
|
myUrlToValueSets.put(theVs.getUrl(), theVs);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -2366,18 +2366,19 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
IIdType id = idCreated.toUnqualifiedVersionless();
|
IIdType id = idCreated.toUnqualifiedVersionless();
|
||||||
|
|
||||||
for (int i = 0; i < 10; i++) {
|
for (int i = 0; i < 10; i++) {
|
||||||
sleepOneClick();
|
sleepAtLeast(100);
|
||||||
preDates.add(new Date());
|
preDates.add(new Date());
|
||||||
sleepOneClick();
|
sleepAtLeast(100);
|
||||||
patient.setId(id);
|
patient.setId(id);
|
||||||
patient.getName().get(0).getFamilyElement().setValue(methodName + "_i" + i);
|
patient.getName().get(0).getFamilyElement().setValue(methodName + "_i" + i);
|
||||||
ids.add(myPatientDao.update(patient, mySrd).getId().toUnqualified().getValue());
|
ids.add(myPatientDao.update(patient, mySrd).getId().toUnqualified().getValue());
|
||||||
sleepOneClick();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
List<String> idValues;
|
List<String> idValues;
|
||||||
|
|
||||||
|
myCaptureQueriesListener.clear();
|
||||||
idValues = searchAndReturnUnqualifiedIdValues(myServerBase + "/Patient/" + id.getIdPart() + "/_history?_at=gt" + toStr(preDates.get(0)) + "&_at=lt" + toStr(preDates.get(3)));
|
idValues = searchAndReturnUnqualifiedIdValues(myServerBase + "/Patient/" + id.getIdPart() + "/_history?_at=gt" + toStr(preDates.get(0)) + "&_at=lt" + toStr(preDates.get(3)));
|
||||||
|
myCaptureQueriesListener.logSelectQueries();
|
||||||
assertThat(idValues).as(idValues.toString()).containsExactly(ids.get(3), ids.get(2), ids.get(1), ids.get(0));
|
assertThat(idValues).as(idValues.toString()).containsExactly(ids.get(3), ids.get(2), ids.get(1), ids.get(0));
|
||||||
|
|
||||||
idValues = searchAndReturnUnqualifiedIdValues(myServerBase + "/Patient/_history?_at=gt" + toStr(preDates.get(0)) + "&_at=lt" + toStr(preDates.get(3)));
|
idValues = searchAndReturnUnqualifiedIdValues(myServerBase + "/Patient/_history?_at=gt" + toStr(preDates.get(0)) + "&_at=lt" + toStr(preDates.get(3)));
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r5;
|
package ca.uhn.fhir.jpa.dao.r5;
|
||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
|
||||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||||
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
import ca.uhn.fhir.context.support.ConceptValidationOptions;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
|
@ -17,7 +15,6 @@ import ca.uhn.fhir.jpa.util.ValueSetTestUtil;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r5.model.CodeSystem;
|
import org.hl7.fhir.r5.model.CodeSystem;
|
||||||
|
@ -38,10 +35,12 @@ import java.io.IOException;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThatExceptionOfType;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
import static org.junit.jupiter.api.Assertions.assertFalse;
|
import static org.junit.jupiter.api.Assertions.assertFalse;
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
|
|
||||||
public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
|
|
||||||
|
@ -51,7 +50,6 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ITermDeferredStorageSvc myTerminologyDeferredStorageSvc;
|
protected ITermDeferredStorageSvc myTerminologyDeferredStorageSvc;
|
||||||
|
|
||||||
private IIdType myExtensionalVsId;
|
private IIdType myExtensionalVsId;
|
||||||
|
|
||||||
@AfterEach
|
@AfterEach
|
||||||
|
@ -61,7 +59,6 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
myStorageSettings.setExpungeEnabled(new JpaStorageSettings().isExpungeEnabled());
|
myStorageSettings.setExpungeEnabled(new JpaStorageSettings().isExpungeEnabled());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
@Transactional
|
@Transactional
|
||||||
public void before02() throws IOException {
|
public void before02() throws IOException {
|
||||||
|
@ -251,7 +248,6 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See #4305
|
* See #4305
|
||||||
*/
|
*/
|
||||||
|
@ -267,7 +263,7 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
// Update valueset
|
// Update valueset
|
||||||
vs.setName("Hello");
|
vs.setName("Hello");
|
||||||
assertEquals("2", myValueSetDao.update(vs, mySrd).getId().getVersionIdPart());
|
assertEquals("2", myValueSetDao.update(vs, mySrd).getId().getVersionIdPart());
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
Optional<ResourceTable> resource = myResourceTableDao.findById(id.getIdPartAsLong());
|
Optional<ResourceTable> resource = myResourceTableDao.findById(id.getIdPartAsLong());
|
||||||
assertTrue(resource.isPresent());
|
assertTrue(resource.isPresent());
|
||||||
});
|
});
|
||||||
|
@ -287,13 +283,12 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
myValueSetDao.expunge(id, new ExpungeOptions().setExpungeDeletedResources(true).setExpungeOldVersions(true), mySrd);
|
myValueSetDao.expunge(id, new ExpungeOptions().setExpungeDeletedResources(true).setExpungeOldVersions(true), mySrd);
|
||||||
|
|
||||||
// Verify expunged
|
// Verify expunged
|
||||||
runInTransaction(()->{
|
runInTransaction(() -> {
|
||||||
Optional<ResourceTable> resource = myResourceTableDao.findById(id.getIdPartAsLong());
|
Optional<ResourceTable> resource = myResourceTableDao.findById(id.getIdPartAsLong());
|
||||||
assertFalse(resource.isPresent());
|
assertFalse(resource.isPresent());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByValueSet_ExceedsMaxSize() {
|
public void testExpandByValueSet_ExceedsMaxSize() {
|
||||||
// Add a bunch of codes
|
// Add a bunch of codes
|
||||||
|
@ -336,12 +331,12 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
myTerminologyDeferredStorageSvc.saveAllDeferred();
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
logAllValueSets();
|
logAllValueSets();
|
||||||
myCachingValidationSupport.invalidateCaches();
|
myValidationSupport.invalidateCaches();
|
||||||
|
|
||||||
// Validate code
|
// Validate code
|
||||||
|
|
||||||
ValidationSupportContext ctx = new ValidationSupportContext(myValidationSupport);
|
ValidationSupportContext ctx = new ValidationSupportContext(myValidationSupport);
|
||||||
ConceptValidationOptions options= new ConceptValidationOptions();
|
ConceptValidationOptions options = new ConceptValidationOptions();
|
||||||
IValidationSupport.CodeValidationResult outcome = myValidationSupport.validateCode(ctx, options, "http://cs", "CODE4", null, "http://vs");
|
IValidationSupport.CodeValidationResult outcome = myValidationSupport.validateCode(ctx, options, "http://cs", "CODE4", null, "http://vs");
|
||||||
assertNotNull(outcome);
|
assertNotNull(outcome);
|
||||||
assertTrue(outcome.isOk());
|
assertTrue(outcome.isOk());
|
||||||
|
@ -354,9 +349,6 @@ public class FhirResourceDaoR5ValueSetTest extends BaseJpaR5Test {
|
||||||
assertThat(expansionMessage).startsWith("ValueSet was expanded using an expansion that was pre-calculated");
|
assertThat(expansionMessage).startsWith("ValueSet was expanded using an expansion that was pre-calculated");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Autowired
|
|
||||||
protected CachingValidationSupport myCachingValidationSupport;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
|
public void testValidateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
|
||||||
IPrimitiveType<String> display = null;
|
IPrimitiveType<String> display = null;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -118,7 +118,6 @@ import ca.uhn.fhir.validation.FhirValidator;
|
||||||
import ca.uhn.fhir.validation.ValidationResult;
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
import ca.uhn.test.util.LogbackTestExtension;
|
import ca.uhn.test.util.LogbackTestExtension;
|
||||||
import jakarta.persistence.EntityManager;
|
import jakarta.persistence.EntityManager;
|
||||||
import org.hl7.fhir.common.hapi.validation.support.CachingValidationSupport;
|
|
||||||
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
@ -246,8 +245,6 @@ public abstract class BaseJpaR4Test extends BaseJpaTest implements ITestDataBuil
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ITermReadSvc myHapiTerminologySvc;
|
protected ITermReadSvc myHapiTerminologySvc;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected CachingValidationSupport myCachingValidationSupport;
|
|
||||||
@Autowired
|
|
||||||
protected ITermCodeSystemStorageSvc myTermCodeSystemStorageSvc;
|
protected ITermCodeSystemStorageSvc myTermCodeSystemStorageSvc;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected ISearchDao mySearchEntityDao;
|
protected ISearchDao mySearchEntityDao;
|
||||||
|
|
|
@ -271,6 +271,8 @@ public abstract class BaseJpaTest extends BaseTest {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IValidationSupport myJpaPersistedValidationSupport;
|
private IValidationSupport myJpaPersistedValidationSupport;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
private IValidationSupport myValidationSupport;
|
||||||
|
@Autowired
|
||||||
private FhirInstanceValidator myFhirInstanceValidator;
|
private FhirInstanceValidator myFhirInstanceValidator;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IResourceTableDao myResourceTableDao;
|
private IResourceTableDao myResourceTableDao;
|
||||||
|
@ -398,6 +400,10 @@ public abstract class BaseJpaTest extends BaseTest {
|
||||||
if (myFhirInstanceValidator != null) {
|
if (myFhirInstanceValidator != null) {
|
||||||
myFhirInstanceValidator.invalidateCaches();
|
myFhirInstanceValidator.invalidateCaches();
|
||||||
}
|
}
|
||||||
|
if (myValidationSupport != null) {
|
||||||
|
myValidationSupport.invalidateCaches();
|
||||||
|
}
|
||||||
|
|
||||||
JpaStorageSettings defaultConfig = new JpaStorageSettings();
|
JpaStorageSettings defaultConfig = new JpaStorageSettings();
|
||||||
myStorageSettings.setAdvancedHSearchIndexing(defaultConfig.isAdvancedHSearchIndexing());
|
myStorageSettings.setAdvancedHSearchIndexing(defaultConfig.isAdvancedHSearchIndexing());
|
||||||
myStorageSettings.setAllowContainsSearches(defaultConfig.isAllowContainsSearches());
|
myStorageSettings.setAllowContainsSearches(defaultConfig.isAllowContainsSearches());
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -58,4 +58,7 @@ public class SubscriptionConstants {
|
||||||
"http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-payload-content";
|
"http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-payload-content";
|
||||||
public static final String SUBSCRIPTION_TOPIC_STATUS =
|
public static final String SUBSCRIPTION_TOPIC_STATUS =
|
||||||
"http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription-status-r4";
|
"http://hl7.org/fhir/uv/subscriptions-backport/StructureDefinition/backport-subscription-status-r4";
|
||||||
|
|
||||||
|
public static final int ORDER_SUBSCRIPTION_VALIDATING = 100;
|
||||||
|
public static final int ORDER_SUBSCRIPTION_ACTIVATING = 200;
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
@ -21,7 +21,7 @@
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-caching-api</artifactId>
|
<artifactId>hapi-fhir-caching-api</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
</dependency>
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
<artifactId>hapi-fhir-serviceloaders</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../pom.xml</relativePath>
|
<relativePath>../../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
<artifactId>hapi-fhir-spring-boot-sample-client-apache</artifactId>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
<artifactId>hapi-fhir-spring-boot-samples</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-spring-boot</artifactId>
|
<artifactId>hapi-fhir-spring-boot</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -27,6 +27,8 @@ import net.ttddyy.dsproxy.QueryInfo;
|
||||||
import net.ttddyy.dsproxy.listener.MethodExecutionContext;
|
import net.ttddyy.dsproxy.listener.MethodExecutionContext;
|
||||||
import net.ttddyy.dsproxy.proxy.ParameterSetOperation;
|
import net.ttddyy.dsproxy.proxy.ParameterSetOperation;
|
||||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -38,7 +40,7 @@ import static org.apache.commons.lang3.StringUtils.trim;
|
||||||
|
|
||||||
public abstract class BaseCaptureQueriesListener
|
public abstract class BaseCaptureQueriesListener
|
||||||
implements ProxyDataSourceBuilder.SingleQueryExecution, ProxyDataSourceBuilder.SingleMethodExecution {
|
implements ProxyDataSourceBuilder.SingleQueryExecution, ProxyDataSourceBuilder.SingleMethodExecution {
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(BaseCaptureQueriesListener.class);
|
||||||
private boolean myCaptureQueryStackTrace = false;
|
private boolean myCaptureQueryStackTrace = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -112,6 +114,9 @@ public abstract class BaseCaptureQueriesListener
|
||||||
@Nullable
|
@Nullable
|
||||||
protected abstract AtomicInteger provideCommitCounter();
|
protected abstract AtomicInteger provideCommitCounter();
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
protected abstract AtomicInteger provideGetConnectionCounter();
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
protected abstract AtomicInteger provideRollbackCounter();
|
protected abstract AtomicInteger provideRollbackCounter();
|
||||||
|
|
||||||
|
@ -125,6 +130,9 @@ public abstract class BaseCaptureQueriesListener
|
||||||
case "rollback":
|
case "rollback":
|
||||||
counter = provideRollbackCounter();
|
counter = provideRollbackCounter();
|
||||||
break;
|
break;
|
||||||
|
case "getConnection":
|
||||||
|
counter = provideGetConnectionCounter();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (counter != null) {
|
if (counter != null) {
|
||||||
|
@ -132,10 +140,23 @@ public abstract class BaseCaptureQueriesListener
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the number of times the connection pool was asked for a new connection
|
||||||
|
*/
|
||||||
|
public int countGetConnections() {
|
||||||
|
return provideGetConnectionCounter().get();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the number of DB commits which have happened against connections from the pool
|
||||||
|
*/
|
||||||
public int countCommits() {
|
public int countCommits() {
|
||||||
return provideCommitCounter().get();
|
return provideCommitCounter().get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Returns the number of DB rollbacks which have happened against connections from the pool
|
||||||
|
*/
|
||||||
public int countRollbacks() {
|
public int countRollbacks() {
|
||||||
return provideRollbackCounter().get();
|
return provideRollbackCounter().get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.util;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import com.google.common.collect.Queues;
|
import com.google.common.collect.Queues;
|
||||||
import jakarta.annotation.Nonnull;
|
import jakarta.annotation.Nonnull;
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||||
import org.apache.commons.collections4.queue.CircularFifoQueue;
|
import org.apache.commons.collections4.queue.CircularFifoQueue;
|
||||||
import org.hl7.fhir.r4.model.InstantType;
|
import org.hl7.fhir.r4.model.InstantType;
|
||||||
|
@ -58,6 +59,7 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
private static final int CAPACITY = 10000;
|
private static final int CAPACITY = 10000;
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(CircularQueueCaptureQueriesListener.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(CircularQueueCaptureQueriesListener.class);
|
||||||
private Queue<SqlQuery> myQueries;
|
private Queue<SqlQuery> myQueries;
|
||||||
|
private AtomicInteger myGetConnectionCounter;
|
||||||
private AtomicInteger myCommitCounter;
|
private AtomicInteger myCommitCounter;
|
||||||
private AtomicInteger myRollbackCounter;
|
private AtomicInteger myRollbackCounter;
|
||||||
|
|
||||||
|
@ -91,6 +93,12 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
return myCommitCounter;
|
return myCommitCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected AtomicInteger provideGetConnectionCounter() {
|
||||||
|
return myGetConnectionCounter;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AtomicInteger provideRollbackCounter() {
|
protected AtomicInteger provideRollbackCounter() {
|
||||||
return myRollbackCounter;
|
return myRollbackCounter;
|
||||||
|
@ -101,6 +109,7 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
*/
|
*/
|
||||||
public void clear() {
|
public void clear() {
|
||||||
myQueries.clear();
|
myQueries.clear();
|
||||||
|
myGetConnectionCounter.set(0);
|
||||||
myCommitCounter.set(0);
|
myCommitCounter.set(0);
|
||||||
myRollbackCounter.set(0);
|
myRollbackCounter.set(0);
|
||||||
}
|
}
|
||||||
|
@ -110,6 +119,7 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
*/
|
*/
|
||||||
public void startCollecting() {
|
public void startCollecting() {
|
||||||
myQueries = Queues.synchronizedQueue(new CircularFifoQueue<>(CAPACITY));
|
myQueries = Queues.synchronizedQueue(new CircularFifoQueue<>(CAPACITY));
|
||||||
|
myGetConnectionCounter = new AtomicInteger(0);
|
||||||
myCommitCounter = new AtomicInteger(0);
|
myCommitCounter = new AtomicInteger(0);
|
||||||
myRollbackCounter = new AtomicInteger(0);
|
myRollbackCounter = new AtomicInteger(0);
|
||||||
}
|
}
|
||||||
|
@ -167,10 +177,18 @@ public class CircularQueueCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
return getQueriesMatching(thePredicate, threadName);
|
return getQueriesMatching(thePredicate, threadName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #countCommits()}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getCommitCount() {
|
public int getCommitCount() {
|
||||||
return myCommitCounter.get();
|
return myCommitCounter.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated Use {@link #countRollbacks()}
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
public int getRollbackCount() {
|
public int getRollbackCount() {
|
||||||
return myRollbackCounter.get();
|
return myRollbackCounter.get();
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
*/
|
*/
|
||||||
package ca.uhn.fhir.jpa.util;
|
package ca.uhn.fhir.jpa.util;
|
||||||
|
|
||||||
|
import jakarta.annotation.Nullable;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
@ -32,6 +33,7 @@ import java.util.stream.Collectors;
|
||||||
public class CurrentThreadCaptureQueriesListener extends BaseCaptureQueriesListener {
|
public class CurrentThreadCaptureQueriesListener extends BaseCaptureQueriesListener {
|
||||||
|
|
||||||
private static final ThreadLocal<Queue<SqlQuery>> ourQueues = new ThreadLocal<>();
|
private static final ThreadLocal<Queue<SqlQuery>> ourQueues = new ThreadLocal<>();
|
||||||
|
private static final ThreadLocal<AtomicInteger> ourGetConnections = new ThreadLocal<>();
|
||||||
private static final ThreadLocal<AtomicInteger> ourCommits = new ThreadLocal<>();
|
private static final ThreadLocal<AtomicInteger> ourCommits = new ThreadLocal<>();
|
||||||
private static final ThreadLocal<AtomicInteger> ourRollbacks = new ThreadLocal<>();
|
private static final ThreadLocal<AtomicInteger> ourRollbacks = new ThreadLocal<>();
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(CurrentThreadCaptureQueriesListener.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(CurrentThreadCaptureQueriesListener.class);
|
||||||
|
@ -46,6 +48,12 @@ public class CurrentThreadCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
return ourCommits.get();
|
return ourCommits.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected AtomicInteger provideGetConnectionCounter() {
|
||||||
|
return ourGetConnections.get();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected AtomicInteger provideRollbackCounter() {
|
protected AtomicInteger provideRollbackCounter() {
|
||||||
return ourRollbacks.get();
|
return ourRollbacks.get();
|
||||||
|
@ -57,6 +65,7 @@ public class CurrentThreadCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
public static SqlQueryList getCurrentQueueAndStopCapturing() {
|
public static SqlQueryList getCurrentQueueAndStopCapturing() {
|
||||||
Queue<SqlQuery> retVal = ourQueues.get();
|
Queue<SqlQuery> retVal = ourQueues.get();
|
||||||
ourQueues.remove();
|
ourQueues.remove();
|
||||||
|
ourGetConnections.remove();
|
||||||
ourCommits.remove();
|
ourCommits.remove();
|
||||||
ourRollbacks.remove();
|
ourRollbacks.remove();
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
|
@ -76,6 +85,7 @@ public class CurrentThreadCaptureQueriesListener extends BaseCaptureQueriesListe
|
||||||
*/
|
*/
|
||||||
public static void startCapturing() {
|
public static void startCapturing() {
|
||||||
ourQueues.set(new ArrayDeque<>());
|
ourQueues.set(new ArrayDeque<>());
|
||||||
|
ourGetConnections.set(new AtomicInteger(0));
|
||||||
ourCommits.set(new AtomicInteger(0));
|
ourCommits.set(new AtomicInteger(0));
|
||||||
ourRollbacks.set(new AtomicInteger(0));
|
ourRollbacks.set(new AtomicInteger(0));
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
package ca.uhn.fhir.jpa.validation;
|
package ca.uhn.fhir.jpa.validation;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||||
import ca.uhn.fhir.context.support.IValidationSupport;
|
import ca.uhn.fhir.context.support.IValidationSupport;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
|
@ -75,10 +76,16 @@ public class ValidatorResourceFetcher implements IValidatorResourceFetcher {
|
||||||
target = dao.read(id, (RequestDetails) appContext);
|
target = dao.read(id, (RequestDetails) appContext);
|
||||||
} catch (ResourceNotFoundException e) {
|
} catch (ResourceNotFoundException e) {
|
||||||
ourLog.info("Failed to resolve local reference: {}", theUrl);
|
ourLog.info("Failed to resolve local reference: {}", theUrl);
|
||||||
try {
|
|
||||||
target = fetchByUrl(theUrl, dao, (RequestDetails) appContext);
|
RuntimeResourceDefinition def = myFhirContext.getResourceDefinition(resourceType);
|
||||||
} catch (ResourceNotFoundException e2) {
|
if (def.getChildByName("url") != null) {
|
||||||
ourLog.info("Failed to find resource by URL: {}", theUrl);
|
try {
|
||||||
|
target = fetchByUrl(theUrl, dao, (RequestDetails) appContext);
|
||||||
|
} catch (ResourceNotFoundException e2) {
|
||||||
|
ourLog.info("Failed to find resource by URL: {}", theUrl);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -86,7 +93,7 @@ public class ValidatorResourceFetcher implements IValidatorResourceFetcher {
|
||||||
return new JsonParser(myVersionSpecificContextWrapper)
|
return new JsonParser(myVersionSpecificContextWrapper)
|
||||||
.parse(myFhirContext.newJsonParser().encodeResourceToString(target), resourceType);
|
.parse(myFhirContext.newJsonParser().encodeResourceToString(target), resourceType);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new FHIRException(Msg.code(576) + e);
|
throw new FHIRException(Msg.code(576) + e, e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>7.7.7-SNAPSHOT</version>
|
<version>7.7.8-SNAPSHOT</version>
|
||||||
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue