fixes for support of R4B / 6.2.0 (#455)
This commit is contained in:
committed by
GitHub
parent
64aeb9b2fe
commit
2e1f5f5276
@@ -28,6 +28,10 @@ public class OnEitherVersion extends AnyNestedCondition {
|
||||
static class OnR4 {
|
||||
}
|
||||
|
||||
@Conditional(OnR4BCondition.class)
|
||||
static class OnR4B {
|
||||
}
|
||||
|
||||
@Conditional(OnR5Condition.class)
|
||||
static class OnR5 {
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package ca.uhn.fhir.jpa.starter.annotations;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
public class OnR4BCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
|
||||
String version = conditionContext.
|
||||
getEnvironment()
|
||||
.getProperty("hapi.fhir.fhir_version")
|
||||
.toUpperCase();
|
||||
|
||||
return FhirVersionEnum.R4B.name().equals(version);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package ca.uhn.fhir.jpa.starter.common;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.r4b.JpaR4BConfig;
|
||||
import ca.uhn.fhir.jpa.starter.annotations.OnR4BCondition;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
@Configuration
|
||||
@Conditional(OnR4BCondition.class)
|
||||
@Import({
|
||||
JpaR4BConfig.class,
|
||||
StarterJpaConfig.class,
|
||||
ElasticsearchConfig.class
|
||||
})
|
||||
public class FhirServerConfigR4B {
|
||||
}
|
||||
@@ -26,7 +26,6 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.mdm.MdmLinkDaoJpaImpl;
|
||||
import ca.uhn.fhir.jpa.dao.search.HSearchSortHelperImpl;
|
||||
import ca.uhn.fhir.jpa.dao.search.IHSearchSortHelper;
|
||||
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||
import ca.uhn.fhir.jpa.delete.ThreadSafeResourceDeleterSvc;
|
||||
import ca.uhn.fhir.jpa.graphql.GraphQLProvider;
|
||||
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||
@@ -423,7 +422,6 @@ public class StarterJpaConfig {
|
||||
public static IServerConformanceProvider<?> calculateConformanceProvider(IFhirSystemDao fhirSystemDao, RestfulServer fhirServer, DaoConfig daoConfig, ISearchParamRegistry searchParamRegistry, IValidationSupport theValidationSupport) {
|
||||
FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion();
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(fhirServer, fhirSystemDao, daoConfig);
|
||||
confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server");
|
||||
return confProvider;
|
||||
@@ -437,6 +435,11 @@ public class StarterJpaConfig {
|
||||
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, daoConfig, searchParamRegistry, theValidationSupport);
|
||||
confProvider.setImplementationDescription("HAPI FHIR R4 Server");
|
||||
return confProvider;
|
||||
} else if (fhirVersion == FhirVersionEnum.R4B) {
|
||||
|
||||
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, daoConfig, searchParamRegistry, theValidationSupport);
|
||||
confProvider.setImplementationDescription("HAPI FHIR R4B Server");
|
||||
return confProvider;
|
||||
} else if (fhirVersion == FhirVersionEnum.R5) {
|
||||
|
||||
JpaCapabilityStatementProvider confProvider = new JpaCapabilityStatementProvider(fhirServer, fhirSystemDao, daoConfig, searchParamRegistry, theValidationSupport);
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
package ca.uhn.fhir.jpa.starter.common.validation;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.interceptor.validation.IRepositoryValidatingRule;
|
||||
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor;
|
||||
import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingRuleBuilder;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.starter.annotations.OnR4BCondition;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import org.hl7.fhir.r4b.model.StructureDefinition;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.jpa.starter.common.validation.IRepositoryValidationInterceptorFactory.ENABLE_REPOSITORY_VALIDATING_INTERCEPTOR;
|
||||
|
||||
/**
|
||||
* This class can be customized to enable the {@link RepositoryValidatingInterceptor}
|
||||
* on this server.
|
||||
* <p>
|
||||
* The <code>enable_repository_validating_interceptor</code> property must be enabled in <code>application.yaml</code>
|
||||
* in order to use this class.
|
||||
*/
|
||||
@ConditionalOnProperty(prefix = "hapi.fhir", name = ENABLE_REPOSITORY_VALIDATING_INTERCEPTOR, havingValue = "true")
|
||||
@Configuration
|
||||
@Conditional(OnR4BCondition.class)
|
||||
public class RepositoryValidationInterceptorFactoryR4B implements IRepositoryValidationInterceptorFactory {
|
||||
|
||||
private final FhirContext fhirContext;
|
||||
private final RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder;
|
||||
private final IFhirResourceDao structureDefinitionResourceProvider;
|
||||
|
||||
public RepositoryValidationInterceptorFactoryR4B(RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder, DaoRegistry daoRegistry) {
|
||||
this.repositoryValidatingRuleBuilder = repositoryValidatingRuleBuilder;
|
||||
this.fhirContext = daoRegistry.getSystemDao().getContext();
|
||||
structureDefinitionResourceProvider = daoRegistry.getResourceDao("StructureDefinition");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions() {
|
||||
|
||||
IBundleProvider results = structureDefinitionResourceProvider.search(new SearchParameterMap().add(StructureDefinition.SP_KIND, new TokenParam("resource")));
|
||||
Map<String, List<StructureDefinition>> structureDefintions = results.getResources(0, results.size())
|
||||
.stream()
|
||||
.map(StructureDefinition.class::cast)
|
||||
.collect(Collectors.groupingBy(StructureDefinition::getType));
|
||||
|
||||
structureDefintions.forEach((key, value) -> {
|
||||
String[] urls = value.stream().map(StructureDefinition::getUrl).toArray(String[]::new);
|
||||
repositoryValidatingRuleBuilder.forResourcesOfType(key).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles();
|
||||
});
|
||||
|
||||
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RepositoryValidatingInterceptor build() {
|
||||
|
||||
// Customize the ruleBuilder here to have the rules you want! We will give a simple example
|
||||
// of enabling validation for all Patient resources
|
||||
repositoryValidatingRuleBuilder.forResourcesOfType("Patient").requireAtLeastProfile("http://hl7.org/fhir/us/core/StructureDefinition/us-core-patient").and().requireValidationToDeclaredProfiles();
|
||||
|
||||
// Do not customize below this line
|
||||
List<IRepositoryValidatingRule> rules = repositoryValidatingRuleBuilder.build();
|
||||
return new RepositoryValidatingInterceptor(fhirContext, rules);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -48,8 +48,8 @@ spring:
|
||||
# hibernate.search.backend.directory.root: target/lucenefiles
|
||||
# hibernate.search.backend.lucene_version: lucene_current
|
||||
### elastic parameters ===> see also elasticsearch section below <===
|
||||
hibernate.search.backend.type: elasticsearch
|
||||
hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiHSearchAnalysisConfigurers$HapiElasticAnalysisConfigurer
|
||||
# hibernate.search.backend.type: elasticsearch
|
||||
# hibernate.search.backend.analysis.configurer: ca.uhn.fhir.jpa.search.HapiHSearchAnalysisConfigurers$HapiElasticAnalysisConfigurer
|
||||
hapi:
|
||||
fhir:
|
||||
### This enables the swagger-ui at /fhir/swagger-ui/index.html as well as the /fhir/api-docs (see https://hapifhir.io/hapi-fhir/docs/server_plain/openapi.html)
|
||||
|
||||
120
src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4BIT.java
Normal file
120
src/test/java/ca/uhn/fhir/jpa/starter/ExampleServerR4BIT.java
Normal file
@@ -0,0 +1,120 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4b.model.Bundle;
|
||||
import org.hl7.fhir.r4b.model.Patient;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Order;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = {
|
||||
"spring.datasource.url=jdbc:h2:mem:dbr4b",
|
||||
"hapi.fhir.enable_repository_validating_interceptor=true",
|
||||
"hapi.fhir.fhir_version=r4b",
|
||||
"hapi.fhir.subscription.websocket_enabled=false",
|
||||
"hapi.fhir.mdm_enabled=false",
|
||||
"hapi.fhir.implementationguides.dk-core.name=hl7.fhir.dk.core",
|
||||
"hapi.fhir.implementationguides.dk-core.version=1.1.0",
|
||||
// Override is currently required when using MDM as the construction of the MDM
|
||||
// beans are ambiguous as they are constructed multiple places. This is evident
|
||||
// when running in a spring boot environment
|
||||
"spring.main.allow-bean-definition-overriding=true"})
|
||||
class ExampleServerR4BIT {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerR4BIT.class);
|
||||
private IGenericClient ourClient;
|
||||
private FhirContext ourCtx;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Test
|
||||
@Order(0)
|
||||
void testCreateAndRead() {
|
||||
String methodName = "testCreateAndRead";
|
||||
ourLog.info("Entering " + methodName + "()...");
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.setActive(true);
|
||||
pt.getBirthDateElement().setValueAsString("2020-01-01");
|
||||
pt.addIdentifier().setSystem("http://foo").setValue("12345");
|
||||
pt.addName().setFamily(methodName);
|
||||
IIdType id = ourClient.create().resource(pt).execute().getId();
|
||||
|
||||
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
||||
assertEquals(methodName, pt2.getName().get(0).getFamily());
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBatchPutWithIdenticalTags() {
|
||||
String batchPuts = "{\n" +
|
||||
"\t\"resourceType\": \"Bundle\",\n" +
|
||||
"\t\"id\": \"patients\",\n" +
|
||||
"\t\"type\": \"batch\",\n" +
|
||||
"\t\"entry\": [\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"request\": {\n" +
|
||||
"\t\t\t\t\"method\": \"PUT\",\n" +
|
||||
"\t\t\t\t\"url\": \"Patient/pat-1\"\n" +
|
||||
"\t\t\t},\n" +
|
||||
"\t\t\t\"resource\": {\n" +
|
||||
"\t\t\t\t\"resourceType\": \"Patient\",\n" +
|
||||
"\t\t\t\t\"id\": \"pat-1\",\n" +
|
||||
"\t\t\t\t\"meta\": {\n" +
|
||||
"\t\t\t\t\t\"tag\": [\n" +
|
||||
"\t\t\t\t\t\t{\n" +
|
||||
"\t\t\t\t\t\t\t\"system\": \"http://mysystem.org\",\n" +
|
||||
"\t\t\t\t\t\t\t\"code\": \"value2\"\n" +
|
||||
"\t\t\t\t\t\t}\n" +
|
||||
"\t\t\t\t\t]\n" +
|
||||
"\t\t\t\t}\n" +
|
||||
"\t\t\t},\n" +
|
||||
"\t\t\t\"fullUrl\": \"/Patient/pat-1\"\n" +
|
||||
"\t\t},\n" +
|
||||
"\t\t{\n" +
|
||||
"\t\t\t\"request\": {\n" +
|
||||
"\t\t\t\t\"method\": \"PUT\",\n" +
|
||||
"\t\t\t\t\"url\": \"Patient/pat-2\"\n" +
|
||||
"\t\t\t},\n" +
|
||||
"\t\t\t\"resource\": {\n" +
|
||||
"\t\t\t\t\"resourceType\": \"Patient\",\n" +
|
||||
"\t\t\t\t\"id\": \"pat-2\",\n" +
|
||||
"\t\t\t\t\"meta\": {\n" +
|
||||
"\t\t\t\t\t\"tag\": [\n" +
|
||||
"\t\t\t\t\t\t{\n" +
|
||||
"\t\t\t\t\t\t\t\"system\": \"http://mysystem.org\",\n" +
|
||||
"\t\t\t\t\t\t\t\"code\": \"value2\"\n" +
|
||||
"\t\t\t\t\t\t}\n" +
|
||||
"\t\t\t\t\t]\n" +
|
||||
"\t\t\t\t}\n" +
|
||||
"\t\t\t},\n" +
|
||||
"\t\t\t\"fullUrl\": \"/Patient/pat-2\"\n" +
|
||||
"\t\t}\n" +
|
||||
"\t]\n" +
|
||||
"}";
|
||||
Bundle bundle = FhirContext.forR4B().newJsonParser().parseResource(Bundle.class, batchPuts);
|
||||
ourClient.transaction().withBundle(bundle).execute();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
ourCtx = FhirContext.forR4B();
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user