diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java index 7655af7..c2c7841 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/BaseJpaRestfulServer.java @@ -11,8 +11,8 @@ import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor; import ca.uhn.fhir.jpa.bulk.provider.BulkDataExportProvider; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; -import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor; import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc; +import ca.uhn.fhir.jpa.packages.PackageInstallOutcomeJson; import ca.uhn.fhir.jpa.packages.PackageInstallationSpec; import ca.uhn.fhir.jpa.partition.PartitionManagementProvider; import ca.uhn.fhir.jpa.provider.*; @@ -98,6 +98,9 @@ public class BaseJpaRestfulServer extends RestfulServer { @Autowired ApplicationContext myApplicationContext; + @Autowired(required = false) + IRepositoryValidationInterceptorFactory factory; + // These are set only if the features are enabled private CqlProviderLoader cqlProviderLoader; @@ -354,28 +357,24 @@ public class BaseJpaRestfulServer extends RestfulServer { if (appProperties.getImplementationGuides() != null) { Map guides = appProperties.getImplementationGuides(); for (Map.Entry guide : guides.entrySet()) { - packageInstallerSvc.install(new PackageInstallationSpec() - .setPackageUrl(guide.getValue().getUrl()) - .setName(guide.getValue().getName()) - .setVersion(guide.getValue().getVersion()) - .setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL)); + packageInstallerSvc.install(new PackageInstallationSpec() + .setPackageUrl(guide.getValue().getUrl()) + .setName(guide.getValue().getName()) + .setVersion(guide.getValue().getVersion()) + .setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL)); + } } + if(factory != null) { + interceptorService.registerInterceptor(factory.buildUsingStoredStructureDefinitions()); + } + + if (appProperties.getLastn_enabled()) { daoConfig.setLastNEnabled(true); } daoConfig.getModelConfig().setNormalizedQuantitySearchLevel(appProperties.getNormalized_quantity_search_level()); - - // Repository Validating Interceptor - if (Boolean.TRUE.equals(appProperties.getEnable_repository_validating_interceptor())) { - RepositoryValidationInterceptorFactory repositoryValidationInterceptorFactory = myApplicationContext.getBean(RepositoryValidationInterceptorFactory.class); - RepositoryValidatingInterceptor interceptor = repositoryValidationInterceptorFactory.build(); - interceptorService.registerInterceptor(interceptor); - } - } - - } diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java index a8cff64..e73ce18 100644 --- a/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java +++ b/src/main/java/ca/uhn/fhir/jpa/starter/FhirServerConfigCommon.java @@ -138,13 +138,6 @@ public class FhirServerConfigCommon { } - @Bean - @Lazy - public RepositoryValidationInterceptorFactory repositoryValidationInterceptorFactory() { - return new RepositoryValidationInterceptorFactory(); - } - - @Primary @Bean public HibernatePropertiesProvider jpaStarterDialectProvider(LocalContainerEntityManagerFactoryBean myEntityManagerFactory) { diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/IRepositoryValidationInterceptorFactory.java b/src/main/java/ca/uhn/fhir/jpa/starter/IRepositoryValidationInterceptorFactory.java new file mode 100644 index 0000000..13262a1 --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/IRepositoryValidationInterceptorFactory.java @@ -0,0 +1,9 @@ +package ca.uhn.fhir.jpa.starter; + +import ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor; + +public interface IRepositoryValidationInterceptorFactory { + RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions(); + + RepositoryValidatingInterceptor build(); +} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactory.java b/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactory.java deleted file mode 100644 index 0ea6652..0000000 --- a/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactory.java +++ /dev/null @@ -1,38 +0,0 @@ -package ca.uhn.fhir.jpa.starter; - -import ca.uhn.fhir.context.FhirContext; -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 org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.ApplicationContext; - -import java.util.List; - -/** - * This class can be customized to enable the {@link ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor} - * on this server. - * - * The enable_repository_validating_interceptor property must be enabled in application.yaml - * in order to use this class. - */ -public class RepositoryValidationInterceptorFactory { - - @Autowired - private ApplicationContext myApplicationContext; - @Autowired - private FhirContext myFhirContext; - - public RepositoryValidatingInterceptor build() { - RepositoryValidatingRuleBuilder ruleBuilder = myApplicationContext.getBean(RepositoryValidatingRuleBuilder.class); - - // Customize the ruleBuilder here to have the rules you want! We will give a simple example - // of enabling validation for all Patient resources - ruleBuilder.forResourcesOfType("Patient").requireValidationToDeclaredProfiles(); - - // Do not customize below this line - List rules = ruleBuilder.build(); - return new RepositoryValidatingInterceptor(myFhirContext, rules); - } - -} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryDstu3.java b/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryDstu3.java new file mode 100644 index 0000000..a68ae3e --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryDstu3.java @@ -0,0 +1,74 @@ +package ca.uhn.fhir.jpa.starter; + +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.OnDSTU3Condition; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.TokenParam; +import org.hl7.fhir.dstu3.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; + +/** + * This class can be customized to enable the {@link RepositoryValidatingInterceptor} + * on this server. + *

+ * The enable_repository_validating_interceptor property must be enabled in application.yaml + * in order to use this class. + */ +@ConditionalOnProperty(prefix = "hapi.fhir", name = "enable_repository_validating_interceptor", havingValue = "true") +@Configuration +@Conditional(OnDSTU3Condition.class) +public class RepositoryValidationInterceptorFactoryDstu3 implements IRepositoryValidationInterceptorFactory { + + private final FhirContext fhirContext; + private final RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder; + private final IFhirResourceDao structureDefinitionResourceProvider; + + public RepositoryValidationInterceptorFactoryDstu3(RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder, DaoRegistry daoRegistry) { + this.repositoryValidatingRuleBuilder = repositoryValidatingRuleBuilder; + this.fhirContext = daoRegistry.getSystemDao().getContext(); + structureDefinitionResourceProvider = daoRegistry.getResourceDao("StructureDefinition"); + + } + + public RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions() { + + IBundleProvider results = structureDefinitionResourceProvider.search(new SearchParameterMap().add(StructureDefinition.SP_KIND, new TokenParam("resource"))); + Map> structureDefintions = results.getResources(0, results.size()) + .stream() + .map(StructureDefinition.class::cast) + .collect(Collectors.groupingBy(StructureDefinition::getType)); + + structureDefintions.entrySet().forEach(structureDefinitionListEntry -> + { + String[] urls = structureDefinitionListEntry.getValue().stream().map(StructureDefinition::getUrl).toArray(String[]::new); + repositoryValidatingRuleBuilder.forResourcesOfType(structureDefinitionListEntry.getKey()).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles(); + }); + + List rules = repositoryValidatingRuleBuilder.build(); + return new RepositoryValidatingInterceptor(fhirContext, rules); + } + + 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 rules = repositoryValidatingRuleBuilder.build(); + return new RepositoryValidatingInterceptor(fhirContext, rules); + } + +} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryR4.java b/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryR4.java new file mode 100644 index 0000000..a563d3c --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryR4.java @@ -0,0 +1,76 @@ +package ca.uhn.fhir.jpa.starter; + +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.OnR4Condition; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.TokenParam; +import org.hl7.fhir.r4.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; + +/** + * This class can be customized to enable the {@link ca.uhn.fhir.jpa.interceptor.validation.RepositoryValidatingInterceptor} + * on this server. + *

+ * The enable_repository_validating_interceptor property must be enabled in application.yaml + * in order to use this class. + */ +@ConditionalOnProperty(prefix = "hapi.fhir", name = "enable_repository_validating_interceptor", havingValue = "true") +@Configuration +@Conditional(OnR4Condition.class) +public class RepositoryValidationInterceptorFactoryR4 implements IRepositoryValidationInterceptorFactory { + + private final FhirContext fhirContext; + private final RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder; + private final IFhirResourceDao structureDefinitionResourceProvider; + + public RepositoryValidationInterceptorFactoryR4(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> structureDefintions = results.getResources(0, results.size()) + .stream() + .map(StructureDefinition.class::cast) + .collect(Collectors.groupingBy(StructureDefinition::getType)); + + structureDefintions.entrySet().forEach(structureDefinitionListEntry -> + { + String[] urls = structureDefinitionListEntry.getValue().stream().map(StructureDefinition::getUrl).toArray(String[]::new); + repositoryValidatingRuleBuilder.forResourcesOfType(structureDefinitionListEntry.getKey()).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles(); + }); + + List 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 rules = repositoryValidatingRuleBuilder.build(); + return new RepositoryValidatingInterceptor(fhirContext, rules); + } + +} diff --git a/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryR5.java b/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryR5.java new file mode 100644 index 0000000..7702ef0 --- /dev/null +++ b/src/main/java/ca/uhn/fhir/jpa/starter/RepositoryValidationInterceptorFactoryR5.java @@ -0,0 +1,74 @@ +package ca.uhn.fhir.jpa.starter; + +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.OnR5Condition; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.param.TokenParam; +import org.hl7.fhir.r5.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; + +/** + * This class can be customized to enable the {@link RepositoryValidatingInterceptor} + * on this server. + *

+ * The enable_repository_validating_interceptor property must be enabled in application.yaml + * in order to use this class. + */ +@ConditionalOnProperty(prefix = "hapi.fhir", name = "enable_repository_validating_interceptor", havingValue = "true") +@Configuration +@Conditional(OnR5Condition.class) +public class RepositoryValidationInterceptorFactoryR5 implements IRepositoryValidationInterceptorFactory { + + private final FhirContext fhirContext; + private final RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder; + private final IFhirResourceDao structureDefinitionResourceProvider; + + public RepositoryValidationInterceptorFactoryR5(RepositoryValidatingRuleBuilder repositoryValidatingRuleBuilder, DaoRegistry daoRegistry) { + this.repositoryValidatingRuleBuilder = repositoryValidatingRuleBuilder; + this.fhirContext = daoRegistry.getSystemDao().getContext(); + structureDefinitionResourceProvider = daoRegistry.getResourceDao("StructureDefinition"); + + } + + public RepositoryValidatingInterceptor buildUsingStoredStructureDefinitions() { + + IBundleProvider results = structureDefinitionResourceProvider.search(new SearchParameterMap().add(StructureDefinition.SP_KIND, new TokenParam("resource"))); + Map> structureDefintions = results.getResources(0, results.size()) + .stream() + .map(StructureDefinition.class::cast) + .collect(Collectors.groupingBy(StructureDefinition::getType)); + + structureDefintions.entrySet().forEach(structureDefinitionListEntry -> + { + String[] urls = structureDefinitionListEntry.getValue().stream().map(StructureDefinition::getUrl).toArray(String[]::new); + repositoryValidatingRuleBuilder.forResourcesOfType(structureDefinitionListEntry.getKey()).requireAtLeastOneProfileOf(urls).and().requireValidationToDeclaredProfiles(); + }); + + List rules = repositoryValidatingRuleBuilder.build(); + return new RepositoryValidatingInterceptor(fhirContext, rules); + } + + 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 rules = repositoryValidatingRuleBuilder.build(); + return new RepositoryValidatingInterceptor(fhirContext, rules); + } + +}