Add support for R5 resources (#1416)
* Work so far on R5 support * Add support for R5 * Docs changes
This commit is contained in:
parent
808da73854
commit
60eab3ad70
|
@ -925,7 +925,7 @@ public class FhirContext {
|
|||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU3 DSTU3}
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#R4 R4}
|
||||
*
|
||||
* @since 3.0.0
|
||||
*/
|
||||
|
@ -933,6 +933,15 @@ public class FhirContext {
|
|||
return new FhirContext(FhirVersionEnum.R4);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#R5 R5}
|
||||
*
|
||||
* @since 4.0.0
|
||||
*/
|
||||
public static FhirContext forR5() {
|
||||
return new FhirContext(FhirVersionEnum.R5);
|
||||
}
|
||||
|
||||
private static Collection<Class<? extends IBaseResource>> toCollection(Class<? extends IBaseResource> theResourceType) {
|
||||
ArrayList<Class<? extends IBaseResource>> retVal = new ArrayList<>(1);
|
||||
retVal.add(theResourceType);
|
||||
|
@ -950,4 +959,5 @@ public class FhirContext {
|
|||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -42,7 +42,9 @@ public enum FhirVersionEnum {
|
|||
|
||||
DSTU3("org.hl7.fhir.dstu3.hapi.ctx.FhirDstu3", null, true, new Dstu3Version()),
|
||||
|
||||
R4("org.hl7.fhir.r4.hapi.ctx.FhirR4", null, true, new R4Version()),;
|
||||
R4("org.hl7.fhir.r4.hapi.ctx.FhirR4", null, true, new R4Version()),
|
||||
|
||||
R5("org.hl7.fhir.r5.hapi.ctx.FhirR5", null, true, new R5Version());
|
||||
|
||||
private final FhirVersionEnum myEquivalent;
|
||||
private final boolean myIsRi;
|
||||
|
@ -134,6 +136,8 @@ public enum FhirVersionEnum {
|
|||
return FhirContext.forDstu3();
|
||||
case R4:
|
||||
return FhirContext.forR4();
|
||||
case R5:
|
||||
return FhirContext.forR5();
|
||||
}
|
||||
throw new IllegalStateException("Unknown version: " + this); // should not happen
|
||||
}
|
||||
|
@ -217,4 +221,24 @@ public enum FhirVersionEnum {
|
|||
|
||||
}
|
||||
|
||||
private static class R5Version implements IVersionProvider {
|
||||
|
||||
private String myVersion;
|
||||
|
||||
R5Version() {
|
||||
try {
|
||||
Class<?> c = Class.forName("org.hl7.fhir.r5.model.Constants");
|
||||
myVersion = (String) c.getDeclaredField("VERSION").get(null);
|
||||
} catch (Exception e) {
|
||||
myVersion = "5.0.0";
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String provideVersion() {
|
||||
return myVersion;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ public class LoadingValidationSupportR4 implements org.hl7.fhir.r4.hapi.ctx.IVal
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theProfileName) {
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,65 @@
|
|||
package org.hl7.fhir.convertors;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Converter
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.dstu2.model.Resource;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
|
||||
public class NullVersionConverterAdvisor50 implements VersionConvertorAdvisor50 {
|
||||
|
||||
@Override
|
||||
public boolean ignoreEntry(Bundle.BundleEntryComponent src) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Resource convertR2(org.hl7.fhir.r5.model.Resource resource) throws FHIRException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.dstu2016may.model.Resource convertR2016May(org.hl7.fhir.r5.model.Resource resource) throws FHIRException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.dstu3.model.Resource convertR3(org.hl7.fhir.r5.model.Resource resource) throws FHIRException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r4.model.Resource convertR4(org.hl7.fhir.r5.model.Resource resource) throws FHIRException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCodeSystem(CodeSystem tgtcs, ValueSet source) throws FHIRException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem getCodeSystem(ValueSet src) throws FHIRException {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -105,6 +105,11 @@
|
|||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r5</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
|
@ -125,6 +130,11 @@
|
|||
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-r5</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>net.ttddyy</groupId>
|
||||
|
@ -676,21 +686,6 @@
|
|||
<artifactId>hapi-tinder-plugin</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<executions>
|
||||
<!--
|
||||
<execution>
|
||||
<id>build_dstu1</id>
|
||||
<goals>
|
||||
<goal>generate-jparest-server</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<version>dstu</version>
|
||||
<configPackageBase>ca.uhn.fhir.jpa.config</configPackageBase>
|
||||
<packageBase>ca.uhn.fhir.jpa.rp.dstu</packageBase>
|
||||
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-dstu1.xml</targetResourceSpringBeansFile>
|
||||
<baseResourceNames></baseResourceNames>
|
||||
</configuration>
|
||||
</execution>
|
||||
-->
|
||||
<execution>
|
||||
<id>build_dstu2</id>
|
||||
<goals>
|
||||
|
@ -737,6 +732,19 @@
|
|||
</excludeResourceNames>
|
||||
</configuration>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>build_r5</id>
|
||||
<goals>
|
||||
<goal>generate-jparest-server</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<version>r5</version>
|
||||
<configPackageBase>ca.uhn.fhir.jpa.config</configPackageBase>
|
||||
<packageBase>ca.uhn.fhir.jpa.rp.r5</packageBase>
|
||||
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-r5.xml</targetResourceSpringBeansFile>
|
||||
<baseResourceNames></baseResourceNames>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
|
||||
<dependencies>
|
||||
|
|
|
@ -9,6 +9,7 @@ import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
|||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.interceptor.JpaConsentContextServices;
|
||||
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
|
@ -211,6 +212,13 @@ public abstract class BaseConfig implements SchedulingConfigurer {
|
|||
return new JpaConsentContextServices();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Lazy
|
||||
public TerminologyUploaderProvider terminologyUploaderProvider() {
|
||||
TerminologyUploaderProvider retVal = new TerminologyUploaderProvider();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static void configureEntityManagerFactory(LocalContainerEntityManagerFactoryBean theFactory, FhirContext theCtx) {
|
||||
theFactory.setJpaDialect(hibernateJpaDialect(theCtx.getLocalizer()));
|
||||
theFactory.setPackagesToScan("ca.uhn.fhir.jpa.model.entity", "ca.uhn.fhir.jpa.entity");
|
||||
|
|
|
@ -17,7 +17,7 @@ import org.hl7.fhir.instance.hapi.validation.CachingValidationSupport;
|
|||
import org.hl7.fhir.instance.hapi.validation.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.instance.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
|
|
@ -24,7 +24,7 @@ import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
|||
import org.hl7.fhir.dstu3.hapi.validation.CachingValidationSupport;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -150,13 +150,6 @@ public class BaseDstu3Config extends BaseConfig {
|
|||
return new HapiTerminologySvcDstu3();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public TerminologyUploaderProviderDstu3 terminologyUploaderProvider() {
|
||||
TerminologyUploaderProviderDstu3 retVal = new TerminologyUploaderProviderDstu3();
|
||||
retVal.setContext(fhirContextDstu3());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(autowire = Autowire.BY_NAME, name = "myJpaValidationSupportChainDstu3")
|
||||
public IValidationSupport validationSupportChainDstu3() {
|
||||
|
|
|
@ -9,7 +9,6 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
|||
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
||||
import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4;
|
||||
import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
|
||||
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryR4;
|
||||
|
@ -27,7 +26,7 @@ import org.hl7.fhir.r4.hapi.validation.CachingValidationSupport;
|
|||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.utils.GraphQLEngine;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator.BestPracticeWarningLevel;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
@ -102,7 +101,8 @@ public class BaseR4Config extends BaseConfig {
|
|||
@Lazy
|
||||
public IValidatorModule instanceValidatorR4() {
|
||||
FhirInstanceValidator val = new FhirInstanceValidator();
|
||||
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
|
||||
IResourceValidator.BestPracticeWarningLevel level = IResourceValidator.BestPracticeWarningLevel.Warning;
|
||||
val.setBestPracticeWarningLevel(level);
|
||||
val.setValidationSupport(validationSupportChainR4());
|
||||
return val;
|
||||
}
|
||||
|
@ -165,13 +165,6 @@ public class BaseR4Config extends BaseConfig {
|
|||
return new HapiTerminologySvcR4();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public TerminologyUploaderProviderR4 terminologyUploaderProvider() {
|
||||
TerminologyUploaderProviderR4 retVal = new TerminologyUploaderProviderR4();
|
||||
retVal.setContext(fhirContextR4());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(autowire = Autowire.BY_NAME, name = "myJpaValidationSupportChainR4")
|
||||
public IValidationSupport validationSupportChainR4() {
|
||||
|
|
|
@ -0,0 +1,174 @@
|
|||
package ca.uhn.fhir.jpa.config.r5;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.ParserOptions;
|
||||
import ca.uhn.fhir.jpa.config.BaseConfig;
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
||||
import ca.uhn.fhir.jpa.dao.r5.TransactionProcessorVersionAdapterR5;
|
||||
import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR5;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryR5;
|
||||
import ca.uhn.fhir.jpa.term.HapiTerminologySvcR5;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologyLoaderSvc;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR5;
|
||||
import ca.uhn.fhir.jpa.term.TerminologyLoaderSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR5;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.hapi.rest.server.GraphQLProvider;
|
||||
import org.hl7.fhir.r5.hapi.validation.CachingValidationSupport;
|
||||
import org.hl7.fhir.r5.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.utils.GraphQLEngine;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
@Configuration
|
||||
@EnableTransactionManagement
|
||||
public class BaseR5Config extends BaseConfig {
|
||||
|
||||
@Override
|
||||
public FhirContext fhirContext() {
|
||||
return fhirContextR5();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Primary
|
||||
public FhirContext fhirContextR5() {
|
||||
FhirContext retVal = FhirContext.forR5();
|
||||
|
||||
// Don't strip versions in some places
|
||||
ParserOptions parserOptions = retVal.getParserOptions();
|
||||
parserOptions.setDontStripVersionsFromReferencesAtPaths("AuditEvent.entity.what");
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TransactionProcessor.ITransactionProcessorVersionAdapter transactionProcessorVersionFacade() {
|
||||
return new TransactionProcessorVersionAdapterR5();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TransactionProcessor<Bundle, Bundle.BundleEntryComponent> transactionProcessor() {
|
||||
return new TransactionProcessor<>();
|
||||
}
|
||||
|
||||
// @Bean(name = GRAPHQL_PROVIDER_NAME)
|
||||
// @Lazy
|
||||
// public GraphQLProvider graphQLProvider() {
|
||||
// return new GraphQLProvider(fhirContextR5(), validationSupportChainR5(), graphqlStorageServices());
|
||||
// }
|
||||
//
|
||||
// @Bean
|
||||
// @Lazy
|
||||
// public GraphQLEngine.IGraphQLStorageServices graphqlStorageServices() {
|
||||
// return new JpaStorageServices();
|
||||
// }
|
||||
|
||||
@Bean(name = "myInstanceValidatorR5")
|
||||
@Lazy
|
||||
public IValidatorModule instanceValidatorR5() {
|
||||
FhirInstanceValidator val = new FhirInstanceValidator();
|
||||
IResourceValidator.BestPracticeWarningLevel level = IResourceValidator.BestPracticeWarningLevel.Warning;
|
||||
val.setBestPracticeWarningLevel(level);
|
||||
val.setValidationSupport(validationSupportChainR5());
|
||||
return val;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JpaValidationSupportChainR5 jpaValidationSupportChain() {
|
||||
return new JpaValidationSupportChainR5();
|
||||
}
|
||||
|
||||
@Bean(name = "myJpaValidationSupportR5", autowire = Autowire.BY_NAME)
|
||||
public ca.uhn.fhir.jpa.dao.r5.IJpaValidationSupportR5 jpaValidationSupportR5() {
|
||||
ca.uhn.fhir.jpa.dao.r5.JpaValidationSupportR5 retVal = new ca.uhn.fhir.jpa.dao.r5.JpaValidationSupportR5();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "myResourceCountsCache")
|
||||
public ResourceCountCache resourceCountsCache() {
|
||||
ResourceCountCache retVal = new ResourceCountCache(() -> systemDaoR5().getResourceCounts());
|
||||
retVal.setCacheMillis(4 * DateUtils.MILLIS_PER_HOUR);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IFulltextSearchSvc searchDaoR5() {
|
||||
FulltextSearchSvcImpl searchDao = new FulltextSearchSvcImpl();
|
||||
return searchDao;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public SearchParamExtractorR5 searchParamExtractor() {
|
||||
return new SearchParamExtractorR5();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ISearchParamRegistry searchParamRegistry() {
|
||||
return new SearchParamRegistryR5();
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemDaoR5", autowire = Autowire.BY_NAME)
|
||||
public IFhirSystemDao<Bundle, org.hl7.fhir.r5.model.Meta> systemDaoR5() {
|
||||
ca.uhn.fhir.jpa.dao.r5.FhirSystemDaoR5 retVal = new ca.uhn.fhir.jpa.dao.r5.FhirSystemDaoR5();
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(name = "mySystemProviderR5")
|
||||
public ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5 systemProviderR5() {
|
||||
ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5 retVal = new ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5();
|
||||
retVal.setContext(fhirContextR5());
|
||||
retVal.setDao(systemDaoR5());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologyLoaderSvc terminologyLoaderService() {
|
||||
return new TerminologyLoaderSvcImpl();
|
||||
}
|
||||
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public IHapiTerminologySvcR5 terminologyService() {
|
||||
return new HapiTerminologySvcR5();
|
||||
}
|
||||
|
||||
@Primary
|
||||
@Bean(autowire = Autowire.BY_NAME, name = "myJpaValidationSupportChainR5")
|
||||
public IValidationSupport validationSupportChainR5() {
|
||||
return new CachingValidationSupport(jpaValidationSupportChain());
|
||||
}
|
||||
|
||||
}
|
|
@ -26,7 +26,6 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.dao.r4.MatchResourceUrlService;
|
||||
import ca.uhn.fhir.jpa.delete.DeleteConflictList;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||
|
|
|
@ -24,7 +24,7 @@ import ca.uhn.fhir.model.dstu2.resource.StructureDefinition;
|
|||
|
||||
public class FhirResourceDaoStructureDefinitionDstu2 extends FhirResourceDaoDstu2<StructureDefinition> implements IFhirResourceDaoStructureDefinition<StructureDefinition> {
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theName) {
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theName) {
|
||||
// FIXME: implement
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -24,6 +24,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
|
||||
public interface IFhirResourceDaoStructureDefinition<T extends IBaseResource> extends IFhirResourceDao<T> {
|
||||
|
||||
T generateSnapshot(T theInput, String theUrl, String theName);
|
||||
T generateSnapshot(T theInput, String theUrl, String theWebUrl, String theName);
|
||||
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
/*-
|
||||
* #%L
|
|
@ -32,7 +32,7 @@ public class FhirResourceDaoStructureDefinitionDstu3 extends FhirResourceDaoDstu
|
|||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theName) {
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theName) {
|
||||
StructureDefinition output = myValidationSupport.generateSnapshot(theInput, theUrl, theName);
|
||||
Validate.notNull(output);
|
||||
return output;
|
||||
|
|
|
@ -27,7 +27,7 @@ import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
|||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IDao;
|
||||
import ca.uhn.fhir.jpa.dao.data.IResourceIndexedCompositeStringUniqueDao;
|
||||
import ca.uhn.fhir.jpa.dao.r4.MatchResourceUrlService;
|
||||
import ca.uhn.fhir.jpa.dao.MatchResourceUrlService;
|
||||
import ca.uhn.fhir.jpa.model.entity.BaseResourceIndexedSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceLink;
|
||||
|
|
|
@ -32,8 +32,8 @@ public class FhirResourceDaoStructureDefinitionR4 extends FhirResourceDaoR4<Stru
|
|||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theName) {
|
||||
StructureDefinition output = myValidationSupport.generateSnapshot(theInput, theUrl, theName);
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theName) {
|
||||
StructureDefinition output = myValidationSupport.generateSnapshot(theInput, theUrl, theWebUrl, theName);
|
||||
Validate.notNull(output);
|
||||
return output;
|
||||
}
|
||||
|
|
|
@ -6,18 +6,11 @@ import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
|||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.conformance.ProfileUtilities;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
@ -26,7 +19,6 @@ import org.springframework.context.ApplicationContextAware;
|
|||
import javax.annotation.PostConstruct;
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.Transactional.TxType;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
|
@ -201,7 +193,7 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4, Applicat
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theProfileName) {
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class FhirResourceDaoBundleR5 extends FhirResourceDaoR5<Bundle> {
|
||||
|
||||
@Override
|
||||
protected void preProcessResourceForStorage(Bundle theResource) {
|
||||
super.preProcessResourceForStorage(theResource);
|
||||
|
||||
Set<String> allowedBundleTypes = getConfig().getBundleTypesAllowedForStorage();
|
||||
if (theResource.getType() == null || !allowedBundleTypes.contains(defaultString(theResource.getType().toCode()))) {
|
||||
String message = "Unable to store a Bundle resource on this server with a Bundle.type value of: " + (theResource.getType() != null ? theResource.getType().toCode() : "(missing)");
|
||||
throw new UnprocessableEntityException(message);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.dao.data.ITermCodeSystemDao;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.util.LogicUtil;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.CodeableConcept;
|
||||
import org.hl7.fhir.r5.model.Coding;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class FhirResourceDaoCodeSystemR5 extends FhirResourceDaoR5<CodeSystem> implements IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoCodeSystemR5.class);
|
||||
|
||||
@Autowired
|
||||
private ITermCodeSystemDao myCsDao;
|
||||
@Autowired
|
||||
private ValidationSupportChain myValidationSupport;
|
||||
|
||||
@Override
|
||||
public List<IIdType> findCodeSystemIdsContainingSystemAndCode(String theCode, String theSystem, RequestDetails theRequest) {
|
||||
List<IIdType> valueSetIds;
|
||||
Set<Long> ids = searchForIds(new SearchParameterMap(CodeSystem.SP_CODE, new TokenParam(theSystem, theCode)), theRequest);
|
||||
valueSetIds = new ArrayList<>();
|
||||
for (Long next : ids) {
|
||||
valueSetIds.add(new IdType("CodeSystem", next));
|
||||
}
|
||||
return valueSetIds;
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
@Override
|
||||
public IContextValidationSupport.LookupCodeResult lookupCode(IPrimitiveType<String> theCode, IPrimitiveType<String> theSystem, Coding theCoding, RequestDetails theRequestDetails) {
|
||||
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
|
||||
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
|
||||
|
||||
if (!haveCoding && !(haveSystem && haveCode)) {
|
||||
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate");
|
||||
}
|
||||
if (!LogicUtil.multiXor(haveCoding, (haveSystem && haveCode)) || (haveSystem != haveCode)) {
|
||||
throw new InvalidRequestException("$lookup can only validate (system AND code) OR (coding.system AND coding.code)");
|
||||
}
|
||||
|
||||
String code;
|
||||
String system;
|
||||
if (haveCoding) {
|
||||
code = theCoding.getCode();
|
||||
system = theCoding.getSystem();
|
||||
} else {
|
||||
code = theCode.getValue();
|
||||
system = theSystem.getValue();
|
||||
}
|
||||
|
||||
ourLog.info("Looking up {} / {}", system, code);
|
||||
|
||||
if (myValidationSupport.isCodeSystemSupported(getContext(), system)) {
|
||||
|
||||
ourLog.info("Code system {} is supported", system);
|
||||
IContextValidationSupport.LookupCodeResult retVal = myValidationSupport.lookupCode(getContext(), system, code);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// We didn't find it..
|
||||
return IContextValidationSupport.LookupCodeResult.notFound(system, code);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubsumesResult subsumes(IPrimitiveType<String> theCodeA, IPrimitiveType<String> theCodeB, IPrimitiveType<String> theSystem, Coding theCodingA, Coding theCodingB, RequestDetails theRequestDetails) {
|
||||
return myTerminologySvc.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preDelete(CodeSystem theResourceToDelete, ResourceTable theEntityToDelete) {
|
||||
super.preDelete(theResourceToDelete, theEntityToDelete);
|
||||
|
||||
String codeSystemUrl = theResourceToDelete.getUrl();
|
||||
if (isNotBlank(codeSystemUrl)) {
|
||||
TermCodeSystem persCs = myCsDao.findByCodeSystemUri(codeSystemUrl);
|
||||
if (persCs != null) {
|
||||
myTerminologySvc.deleteCodeSystem(persCs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
CodeSystem cs = (CodeSystem) theResource;
|
||||
addPidToResource(theEntity, theResource);
|
||||
|
||||
myTerminologySvc.storeNewCodeSystemVersionIfNeeded(org.hl7.fhir.convertors.conv40_50.CodeSystem.convertCodeSystem(cs), theEntity);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoComposition;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Composition;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
|
||||
public class FhirResourceDaoCompositionR5 extends FhirResourceDaoR5<Composition> implements IFhirResourceDaoComposition<Composition> {
|
||||
|
||||
@Override
|
||||
public IBundleProvider getDocumentForComposition(HttpServletRequest theServletRequest, IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdate, SortSpec theSort, RequestDetails theRequestDetails) {
|
||||
SearchParameterMap paramMap = new SearchParameterMap();
|
||||
if (theCount != null) {
|
||||
paramMap.setCount(theCount.getValue());
|
||||
}
|
||||
paramMap.setIncludes(Collections.singleton(IBaseResource.INCLUDE_ALL.asRecursive()));
|
||||
paramMap.setSort(theSort);
|
||||
paramMap.setLastUpdated(theLastUpdate);
|
||||
if (theId != null) {
|
||||
paramMap.add("_id", new StringParam(theId.getIdPart()));
|
||||
}
|
||||
return search(paramMap, theRequestDetails);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,173 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoConceptMap;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElement;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.term.TranslationMatch;
|
||||
import ca.uhn.fhir.jpa.term.TranslationRequest;
|
||||
import ca.uhn.fhir.jpa.term.TranslationResult;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_40_50;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class FhirResourceDaoConceptMapR5 extends FhirResourceDaoR5<ConceptMap> implements IFhirResourceDaoConceptMap<ConceptMap> {
|
||||
@Autowired
|
||||
private IHapiTerminologySvc myHapiTerminologySvc;
|
||||
|
||||
@Override
|
||||
public TranslationResult translate(TranslationRequest theTranslationRequest, RequestDetails theRequestDetails) {
|
||||
if (theTranslationRequest.hasReverse() && theTranslationRequest.getReverseAsBoolean()) {
|
||||
return buildReverseTranslationResult(myHapiTerminologySvc.translateWithReverse(theTranslationRequest));
|
||||
}
|
||||
|
||||
return buildTranslationResult(myHapiTerminologySvc.translate(theTranslationRequest));
|
||||
}
|
||||
|
||||
private TranslationResult buildTranslationResult(List<TermConceptMapGroupElementTarget> theTargets) {
|
||||
TranslationResult retVal = new TranslationResult();
|
||||
|
||||
String msg;
|
||||
if (theTargets.isEmpty()) {
|
||||
|
||||
retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(false)));
|
||||
|
||||
msg = getContext().getLocalizer().getMessage(
|
||||
FhirResourceDaoConceptMapR5.class,
|
||||
"noMatchesFound");
|
||||
|
||||
retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg)));
|
||||
|
||||
} else {
|
||||
|
||||
retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(true)));
|
||||
|
||||
msg = getContext().getLocalizer().getMessage(
|
||||
FhirResourceDaoConceptMapR5.class,
|
||||
"matchesFound");
|
||||
|
||||
retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg)));
|
||||
|
||||
TranslationMatch translationMatch;
|
||||
Set<TermConceptMapGroupElementTarget> targetsToReturn = new HashSet<>();
|
||||
for (TermConceptMapGroupElementTarget target : theTargets) {
|
||||
if (targetsToReturn.add(target)) {
|
||||
translationMatch = new TranslationMatch();
|
||||
|
||||
if (target.getEquivalence() != null) {
|
||||
translationMatch.setEquivalence(VersionConvertor_40_50.convertCode(new CodeType(target.getEquivalence().toCode())));
|
||||
}
|
||||
|
||||
translationMatch.setConcept(VersionConvertor_40_50.convertCoding(
|
||||
new Coding()
|
||||
.setCode(target.getCode())
|
||||
.setSystem(target.getSystem())
|
||||
.setVersion(target.getSystemVersion())
|
||||
.setDisplay(target.getDisplay())
|
||||
));
|
||||
|
||||
translationMatch.setSource(VersionConvertor_40_50.convertUri(new UriType(target.getConceptMapUrl())));
|
||||
|
||||
retVal.addMatch(translationMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private TranslationResult buildReverseTranslationResult(List<TermConceptMapGroupElement> theElements) {
|
||||
TranslationResult retVal = new TranslationResult();
|
||||
|
||||
String msg;
|
||||
if (theElements.isEmpty()) {
|
||||
|
||||
retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(false)));
|
||||
|
||||
msg = getContext().getLocalizer().getMessage(
|
||||
FhirResourceDaoConceptMapR5.class,
|
||||
"noMatchesFound");
|
||||
|
||||
retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg)));
|
||||
|
||||
} else {
|
||||
|
||||
retVal.setResult(VersionConvertor_40_50.convertBoolean(new BooleanType(true)));
|
||||
|
||||
msg = getContext().getLocalizer().getMessage(
|
||||
FhirResourceDaoConceptMapR5.class,
|
||||
"matchesFound");
|
||||
|
||||
retVal.setMessage(VersionConvertor_40_50.convertString(new StringType(msg)));
|
||||
|
||||
TranslationMatch translationMatch;
|
||||
Set<TermConceptMapGroupElement> elementsToReturn = new HashSet<>();
|
||||
for (TermConceptMapGroupElement element : theElements) {
|
||||
if (elementsToReturn.add(element)) {
|
||||
translationMatch = new TranslationMatch();
|
||||
|
||||
translationMatch.setConcept(VersionConvertor_40_50.convertCoding(
|
||||
new Coding()
|
||||
.setCode(element.getCode())
|
||||
.setSystem(element.getSystem())
|
||||
.setVersion(element.getSystemVersion())
|
||||
.setDisplay(element.getDisplay())
|
||||
));
|
||||
|
||||
translationMatch.setSource(VersionConvertor_40_50.convertUri(new UriType(element.getConceptMapUrl())));
|
||||
|
||||
if (element.getConceptMapGroupElementTargets().size() == 1) {
|
||||
translationMatch.setEquivalence(VersionConvertor_40_50.convertCode(new CodeType(element.getConceptMapGroupElementTargets().get(0).getEquivalence().toCode())));
|
||||
}
|
||||
|
||||
retVal.addMatch(translationMatch);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
if (retVal.getDeleted() == null) {
|
||||
ConceptMap conceptMap = (ConceptMap) theResource;
|
||||
myHapiTerminologySvc.storeTermConceptMapAndChildren(retVal, org.hl7.fhir.convertors.conv40_50.ConceptMap.convertConceptMap(conceptMap));
|
||||
} else {
|
||||
myHapiTerminologySvc.deleteConceptMapAndChildren(retVal);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoEncounter;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Encounter;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
|
||||
public class FhirResourceDaoEncounterR5 extends FhirResourceDaoR5<Encounter> implements IFhirResourceDaoEncounter<Encounter> {
|
||||
|
||||
@Override
|
||||
public IBundleProvider encounterInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
|
||||
SearchParameterMap paramMap = new SearchParameterMap();
|
||||
if (theCount != null) {
|
||||
paramMap.setCount(theCount.getValue());
|
||||
}
|
||||
|
||||
// paramMap.setRevIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
|
||||
paramMap.setIncludes(Collections.singleton(IBaseResource.INCLUDE_ALL.asRecursive()));
|
||||
paramMap.setEverythingMode(theId != null ? EverythingModeEnum.ENCOUNTER_INSTANCE : EverythingModeEnum.ENCOUNTER_TYPE);
|
||||
paramMap.setSort(theSort);
|
||||
paramMap.setLastUpdated(theLastUpdated);
|
||||
if (theId != null) {
|
||||
paramMap.add("_id", new StringParam(theId.getIdPart()));
|
||||
}
|
||||
IBundleProvider retVal = search(paramMap);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider encounterTypeEverything(HttpServletRequest theServletRequest, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
|
||||
return encounterInstanceEverything(theServletRequest, null, theCount, theLastUpdated, theSort);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoMessageHeader;
|
||||
import org.hl7.fhir.r5.model.MessageHeader;
|
||||
|
||||
public class FhirResourceDaoMessageHeaderR5 extends FhirResourceDaoR5<MessageHeader> implements IFhirResourceDaoMessageHeader<MessageHeader> {
|
||||
// nothing right now
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
|
||||
public class FhirResourceDaoPatientR5 extends FhirResourceDaoR5<Patient> implements IFhirResourceDaoPatient<Patient> {
|
||||
|
||||
private IBundleProvider doEverythingOperation(IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative, RequestDetails theRequest) {
|
||||
SearchParameterMap paramMap = new SearchParameterMap();
|
||||
if (theCount != null) {
|
||||
paramMap.setCount(theCount.getValue());
|
||||
}
|
||||
if (theContent != null) {
|
||||
paramMap.add(Constants.PARAM_CONTENT, theContent);
|
||||
}
|
||||
if (theNarrative != null) {
|
||||
paramMap.add(Constants.PARAM_TEXT, theNarrative);
|
||||
}
|
||||
paramMap.setIncludes(Collections.singleton(IBaseResource.INCLUDE_ALL.asRecursive()));
|
||||
paramMap.setEverythingMode(theId != null ? EverythingModeEnum.PATIENT_INSTANCE : EverythingModeEnum.PATIENT_TYPE);
|
||||
paramMap.setSort(theSort);
|
||||
paramMap.setLastUpdated(theLastUpdated);
|
||||
if (theId != null) {
|
||||
paramMap.add("_id", new StringParam(theId.getIdPart()));
|
||||
}
|
||||
|
||||
if (!isPagingProviderDatabaseBacked(theRequest)) {
|
||||
paramMap.setLoadSynchronous(true);
|
||||
}
|
||||
|
||||
return mySearchCoordinatorSvc.registerSearch(this, paramMap, getResourceName(), new CacheControlDirective().parse(theRequest.getHeaders(Constants.HEADER_CACHE_CONTROL)), theRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative, RequestDetails theRequestDetails) {
|
||||
return doEverythingOperation(theId, theCount, theLastUpdated, theSort, theContent, theNarrative, theRequestDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, IPrimitiveType<Integer> theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative, RequestDetails theRequestDetails) {
|
||||
return doEverythingOperation(null, theCount, theLastUpdated, theSort, theContent, theNarrative, theRequestDetails);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.r5.model.QuestionnaireResponse;
|
||||
|
||||
public class FhirResourceDaoQuestionnaireResponseR5 extends FhirResourceDaoR5<QuestionnaireResponse> {
|
||||
|
||||
|
||||
// @Override
|
||||
// protected void validateResourceForStorage(QuestionnaireResponse theResource, ResourceTable theEntityToSave, RequestDetails theRequestDetails) {
|
||||
// super.validateResourceForStorage(theResource, theEntityToSave, theRequestDetails);
|
||||
// if (!myValidateResponses) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// if (theResource == null || theResource.getQuestionnaire() == null || theResource.getQuestionnaire().getReference() == null || theResource.getQuestionnaire().getReference().isEmpty()) {
|
||||
// return;
|
||||
// }
|
||||
//
|
||||
// FhirValidator val = getContext().newValidator();
|
||||
// val.setValidateAgainstStandardSchema(false);
|
||||
// val.setValidateAgainstStandardSchematron(false);
|
||||
//
|
||||
// val.registerValidatorModule(myQuestionnaireResponseValidatorR5);
|
||||
//
|
||||
// ValidationResult result = val.validateWithResult(getContext().newJsonParser().parseResource(getContext().newJsonParser().encodeResourceToString(theResource)));
|
||||
// if (!result.isSuccessful()) {
|
||||
// IBaseOperationOutcome oo = getContext().newJsonParser().parseResource(OperationOutcome.class, getContext().newJsonParser().encodeResourceToString(result.toOperationOutcome()));
|
||||
// throw new UnprocessableEntityException(getContext(), oo);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// public class JpaResourceLoader implements IResourceLoader {
|
||||
//
|
||||
// private RequestDetails myRequestDetails;
|
||||
//
|
||||
// public JpaResourceLoader(RequestDetails theRequestDetails) {
|
||||
// super();
|
||||
// myRequestDetails = theRequestDetails;
|
||||
// }
|
||||
//
|
||||
// @Override
|
||||
// public <T extends IBaseResource> T load(Class<T> theType, IIdType theId) throws ResourceNotFoundException {
|
||||
//
|
||||
// /*
|
||||
// * The QuestionnaireResponse validator uses RI structures, so for now we need to convert between that and HAPI
|
||||
// * structures. This is a bit hackish, but hopefully it will go away at some point.
|
||||
// */
|
||||
// if ("ValueSet".equals(theType.getSimpleName())) {
|
||||
// IFhirResourceDao<ValueSet> dao = getDao(ValueSet.class);
|
||||
// ValueSet in = dao.read(theId, myRequestDetails);
|
||||
// return (T) in;
|
||||
// } else if ("Questionnaire".equals(theType.getSimpleName())) {
|
||||
// IFhirResourceDao<Questionnaire> dao = getDao(Questionnaire.class);
|
||||
// Questionnaire vs = dao.read(theId, myRequestDetails);
|
||||
// return (T) vs;
|
||||
// } else {
|
||||
// // Should not happen, validator will only ask for these two
|
||||
// throw new IllegalStateException("Unexpected request to load resource of type " + theType);
|
||||
// }
|
||||
//
|
||||
// }
|
||||
//
|
||||
// }
|
||||
|
||||
}
|
|
@ -0,0 +1,163 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.delete.DeleteConflictList;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.IValidationContext;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.IssueSeverity;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome.OperationOutcomeIssueComponent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class FhirResourceDaoR5<T extends IAnyResource> extends BaseHapiFhirResourceDao<T> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR5.class);
|
||||
|
||||
@Autowired()
|
||||
@Qualifier("myInstanceValidatorR5")
|
||||
private IValidatorModule myInstanceValidator;
|
||||
|
||||
@Override
|
||||
protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage, String theCode) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
OperationOutcomeIssueComponent issue = oo.addIssue();
|
||||
issue.getSeverityElement().setValueAsString(theSeverity);
|
||||
issue.setDiagnostics(theMessage);
|
||||
try {
|
||||
issue.setCode(OperationOutcome.IssueType.fromCode(theCode));
|
||||
} catch (FHIRException e) {
|
||||
ourLog.error("Unknown code: {}", theCode);
|
||||
}
|
||||
return oo;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile, RequestDetails theRequest) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, theResource, null, theId);
|
||||
notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
|
||||
|
||||
if (theMode == ValidationModeEnum.DELETE) {
|
||||
if (theId == null || theId.hasIdPart() == false) {
|
||||
throw new InvalidRequestException("No ID supplied. ID is required when validating with mode=DELETE");
|
||||
}
|
||||
final ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
||||
|
||||
// Validate that there are no resources pointing to the candidate that
|
||||
// would prevent deletion
|
||||
DeleteConflictList deleteConflicts = new DeleteConflictList();
|
||||
if (myDaoConfig.isEnforceReferentialIntegrityOnDelete()) {
|
||||
myDeleteConflictService.validateOkToDelete(deleteConflicts, entity, true, theRequest);
|
||||
}
|
||||
myDeleteConflictService.validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
|
||||
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue().setSeverity(IssueSeverity.INFORMATION).setDiagnostics("Ok to delete");
|
||||
return new MethodOutcome(new IdType(theId.getValue()), oo);
|
||||
}
|
||||
|
||||
FhirValidator validator = getContext().newValidator();
|
||||
|
||||
validator.registerValidatorModule(myInstanceValidator);
|
||||
|
||||
validator.registerValidatorModule(new IdChecker(theMode));
|
||||
|
||||
IBaseResource resourceToValidateById = null;
|
||||
if (theId != null && theId.hasResourceType() && theId.hasIdPart()) {
|
||||
Class<? extends IBaseResource> type = getContext().getResourceDefinition(theId.getResourceType()).getImplementingClass();
|
||||
IFhirResourceDao<? extends IBaseResource> dao = getDao(type);
|
||||
resourceToValidateById = dao.read(theId, theRequest);
|
||||
}
|
||||
|
||||
ValidationResult result;
|
||||
if (theResource == null) {
|
||||
if (resourceToValidateById != null) {
|
||||
result = validator.validateWithResult(resourceToValidateById);
|
||||
} else {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "cantValidateWithNoResource");
|
||||
throw new InvalidRequestException(msg);
|
||||
}
|
||||
} else if (isNotBlank(theRawResource)) {
|
||||
result = validator.validateWithResult(theRawResource);
|
||||
} else {
|
||||
result = validator.validateWithResult(theResource);
|
||||
}
|
||||
|
||||
if (result.isSuccessful()) {
|
||||
MethodOutcome retVal = new MethodOutcome();
|
||||
retVal.setOperationOutcome(result.toOperationOutcome());
|
||||
return retVal;
|
||||
} else {
|
||||
throw new PreconditionFailedException("Validation failed", result.toOperationOutcome());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private class IdChecker implements IValidatorModule {
|
||||
|
||||
private ValidationModeEnum myMode;
|
||||
|
||||
public IdChecker(ValidationModeEnum theMode) {
|
||||
myMode = theMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validateResource(IValidationContext<IBaseResource> theCtx) {
|
||||
boolean hasId = theCtx.getResource().getIdElement().hasIdPart();
|
||||
if (myMode == ValidationModeEnum.CREATE) {
|
||||
if (hasId) {
|
||||
throw new UnprocessableEntityException("Resource has an ID - ID must not be populated for a FHIR create");
|
||||
}
|
||||
} else if (myMode == ValidationModeEnum.UPDATE) {
|
||||
if (hasId == false) {
|
||||
throw new UnprocessableEntityException("Resource has no ID - ID must be populated for a FHIR update");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,155 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSearchParameter;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.BaseSearchParamExtractor;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.utils.FHIRLexer;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class FhirResourceDaoSearchParameterR5 extends FhirResourceDaoR5<SearchParameter> implements IFhirResourceDaoSearchParameter<SearchParameter> {
|
||||
|
||||
public static final DefaultProfileValidationSupport VALIDATION_SUPPORT = new DefaultProfileValidationSupport();
|
||||
@Autowired
|
||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
|
||||
protected void markAffectedResources(SearchParameter theResource) {
|
||||
Boolean reindex = theResource != null ? CURRENTLY_REINDEXING.get(theResource) : null;
|
||||
String expression = theResource != null ? theResource.getExpression() : null;
|
||||
markResourcesMatchingExpressionAsNeedingReindexing(reindex, expression);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void postPersist(ResourceTable theEntity, SearchParameter theResource) {
|
||||
super.postPersist(theEntity, theResource);
|
||||
markAffectedResources(theResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void postUpdate(ResourceTable theEntity, SearchParameter theResource) {
|
||||
super.postUpdate(theEntity, theResource);
|
||||
markAffectedResources(theResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preDelete(SearchParameter theResourceToDelete, ResourceTable theEntityToDelete) {
|
||||
super.preDelete(theResourceToDelete, theEntityToDelete);
|
||||
markAffectedResources(theResourceToDelete);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateResourceForStorage(SearchParameter theResource, ResourceTable theEntityToSave) {
|
||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||
|
||||
Enum<?> status = theResource.getStatus();
|
||||
List<CodeType> base = theResource.getBase();
|
||||
String expression = theResource.getExpression();
|
||||
FhirContext context = getContext();
|
||||
Enum<?> type = theResource.getType();
|
||||
|
||||
FhirResourceDaoSearchParameterR5.validateSearchParam(type, status, base, expression, context, getConfig());
|
||||
}
|
||||
|
||||
public static void validateSearchParam(Enum<?> theType, Enum<?> theStatus, List<? extends IPrimitiveType> theBase, String theExpression, FhirContext theContext, DaoConfig theDaoConfig) {
|
||||
if (theStatus == null) {
|
||||
throw new UnprocessableEntityException("SearchParameter.status is missing or invalid");
|
||||
}
|
||||
|
||||
if (ElementUtil.isEmpty(theBase) && (theType == null || !Enumerations.SearchParamType.COMPOSITE.name().equals(theType.name()))) {
|
||||
throw new UnprocessableEntityException("SearchParameter.base is missing");
|
||||
}
|
||||
|
||||
if (theType != null && theType.name().equals(Enumerations.SearchParamType.COMPOSITE.name()) && isBlank(theExpression)) {
|
||||
|
||||
// this is ok
|
||||
|
||||
} else if (isBlank(theExpression)) {
|
||||
|
||||
throw new UnprocessableEntityException("SearchParameter.expression is missing");
|
||||
|
||||
} else {
|
||||
|
||||
theExpression = theExpression.trim();
|
||||
|
||||
if (!theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.R5)) {
|
||||
String[] expressionSplit = BaseSearchParamExtractor.SPLIT.split(theExpression);
|
||||
for (String nextPath : expressionSplit) {
|
||||
nextPath = nextPath.trim();
|
||||
|
||||
int dotIdx = nextPath.indexOf('.');
|
||||
if (dotIdx == -1) {
|
||||
throw new UnprocessableEntityException("Invalid SearchParameter.expression value \"" + nextPath + "\". Must start with a resource name");
|
||||
}
|
||||
|
||||
String resourceName = nextPath.substring(0, dotIdx);
|
||||
try {
|
||||
theContext.getResourceDefinition(resourceName);
|
||||
} catch (DataFormatException e) {
|
||||
throw new UnprocessableEntityException("Invalid SearchParameter.expression value \"" + nextPath + "\": " + e.getMessage());
|
||||
}
|
||||
|
||||
if (theContext.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
|
||||
if (theDaoConfig.isValidateSearchParameterExpressionsOnSave()) {
|
||||
IBaseResource temporaryInstance = theContext.getResourceDefinition(resourceName).newInstance();
|
||||
try {
|
||||
theContext.newFluentPath().evaluate(temporaryInstance, nextPath, IBase.class);
|
||||
} catch (Exception e) {
|
||||
String msg = theContext.getLocalizer().getMessage(FhirResourceDaoSearchParameterR5.class, "invalidSearchParamExpression", nextPath, e.getMessage());
|
||||
throw new UnprocessableEntityException(msg, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
FHIRPathEngine fhirPathEngine = new FHIRPathEngine(new HapiWorkerContext(theContext, VALIDATION_SUPPORT));
|
||||
try {
|
||||
fhirPathEngine.parse(theExpression);
|
||||
} catch (FHIRLexer.FHIRLexerException e) {
|
||||
throw new UnprocessableEntityException("Invalid SearchParameter.expression value \"" + theExpression + "\": " + e.getMessage());
|
||||
}
|
||||
|
||||
}
|
||||
} // if have expression
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoStructureDefinition;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class FhirResourceDaoStructureDefinitionR5 extends FhirResourceDaoR5<StructureDefinition> implements IFhirResourceDaoStructureDefinition<StructureDefinition> {
|
||||
|
||||
@Autowired
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theName) {
|
||||
StructureDefinition output = myValidationSupport.generateSnapshot(theInput, theUrl, theWebUrl, theName);
|
||||
Validate.notNull(output);
|
||||
return output;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISubscriptionTableDao;
|
||||
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.model.Subscription;
|
||||
import org.hl7.fhir.r5.model.Subscription.SubscriptionChannelType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class FhirResourceDaoSubscriptionR5 extends FhirResourceDaoR5<Subscription> implements IFhirResourceDaoSubscription<Subscription> {
|
||||
|
||||
@Autowired
|
||||
private ISubscriptionTableDao mySubscriptionTableDao;
|
||||
|
||||
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
|
||||
SubscriptionTable subscriptionEntity = new SubscriptionTable();
|
||||
subscriptionEntity.setCreated(new Date());
|
||||
subscriptionEntity.setSubscriptionResource(theEntity);
|
||||
myEntityManager.persist(subscriptionEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId, RequestDetails theRequest) {
|
||||
ResourceTable entity = readEntityLatestVersion(theId, theRequest);
|
||||
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
|
||||
if (table == null) {
|
||||
return null;
|
||||
}
|
||||
return table.getId();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void postPersist(ResourceTable theEntity, Subscription theSubscription) {
|
||||
super.postPersist(theEntity, theSubscription);
|
||||
|
||||
createSubscriptionTable(theEntity, theSubscription);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
if (theDeletedTimestampOrNull != null) {
|
||||
Long subscriptionId = getSubscriptionTablePidForSubscriptionResource(theEntity.getIdDt(), theRequest);
|
||||
if (subscriptionId != null) {
|
||||
mySubscriptionTableDao.deleteAllForSubscription(retVal);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
protected void validateChannelEndpoint(Subscription theResource) {
|
||||
if (isBlank(theResource.getChannel().getEndpoint())) {
|
||||
throw new UnprocessableEntityException("Rest-hook subscriptions must have Subscription.channel.endpoint defined");
|
||||
}
|
||||
}
|
||||
|
||||
protected void validateChannelPayload(Subscription theResource) {
|
||||
if (!isBlank(theResource.getChannel().getPayload()) && EncodingEnum.forContentType(theResource.getChannel().getPayload()) == null) {
|
||||
throw new UnprocessableEntityException("Invalid value for Subscription.channel.payload: " + theResource.getChannel().getPayload());
|
||||
}
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
|
||||
if (theResource.getStatus() == null) {
|
||||
throw new UnprocessableEntityException("Can not process submitted Subscription - Subscription.status must be populated on this server");
|
||||
}
|
||||
|
||||
switch (theResource.getStatus()) {
|
||||
case REQUESTED:
|
||||
case ACTIVE:
|
||||
break;
|
||||
case ERROR:
|
||||
case OFF:
|
||||
case NULL:
|
||||
return null;
|
||||
}
|
||||
|
||||
String query = theResource.getCriteria();
|
||||
if (isBlank(query)) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be populated");
|
||||
}
|
||||
|
||||
int sep = query.indexOf('?');
|
||||
if (sep <= 1) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
||||
}
|
||||
|
||||
String resType = query.substring(0, sep);
|
||||
if (resType.contains("/")) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
|
||||
}
|
||||
|
||||
if (theResource.getChannel().getType() == null) {
|
||||
throw new UnprocessableEntityException("Subscription.channel.type must be populated");
|
||||
} else if (theResource.getChannel().getType() == SubscriptionChannelType.RESTHOOK) {
|
||||
validateChannelPayload(theResource);
|
||||
validateChannelEndpoint(theResource);
|
||||
}
|
||||
|
||||
RuntimeResourceDefinition resDef;
|
||||
try {
|
||||
resDef = getContext().getResourceDefinition(resType);
|
||||
} catch (DataFormatException e) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resType);
|
||||
}
|
||||
return resDef;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave) {
|
||||
super.validateResourceForStorage(theResource, theEntityToSave);
|
||||
|
||||
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
|
||||
if (resDef == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
|
||||
if (dao == null) {
|
||||
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resDef);
|
||||
}
|
||||
|
||||
if (theResource.getChannel().getType() == null) {
|
||||
throw new UnprocessableEntityException("Subscription.channel.type must be populated on this server");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,325 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
import ca.uhn.fhir.jpa.util.LogicUtil;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.ElementUtil;
|
||||
import org.apache.commons.codec.binary.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetFilterComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.FilterOperator;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5<ValueSet> implements IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> {
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologySvc myHapiTerminologySvc;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainR5")
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
@Autowired
|
||||
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
|
||||
|
||||
@Override
|
||||
public ValueSet expand(IIdType theId, String theFilter, RequestDetails theRequestDetails) {
|
||||
ValueSet source = read(theId, theRequestDetails);
|
||||
return expand(source, theFilter);
|
||||
}
|
||||
|
||||
private ValueSet doExpand(ValueSet theSource) {
|
||||
|
||||
/*
|
||||
* If all of the code systems are supported by the HAPI FHIR terminology service, let's
|
||||
* use that as it's more efficient.
|
||||
*/
|
||||
|
||||
boolean allSystemsAreSuppportedByTerminologyService = true;
|
||||
for (ConceptSetComponent next : theSource.getCompose().getInclude()) {
|
||||
if (!isBlank(next.getSystem()) && !myTerminologySvc.supportsSystem(next.getSystem())) {
|
||||
allSystemsAreSuppportedByTerminologyService = false;
|
||||
}
|
||||
}
|
||||
for (ConceptSetComponent next : theSource.getCompose().getExclude()) {
|
||||
if (!isBlank(next.getSystem()) && !myTerminologySvc.supportsSystem(next.getSystem())) {
|
||||
allSystemsAreSuppportedByTerminologyService = false;
|
||||
}
|
||||
}
|
||||
if (allSystemsAreSuppportedByTerminologyService) {
|
||||
return (ValueSet) myTerminologySvc.expandValueSet(theSource);
|
||||
}
|
||||
|
||||
HapiWorkerContext workerContext = new HapiWorkerContext(getContext(), myValidationSupport);
|
||||
|
||||
ValueSetExpansionOutcome outcome = workerContext.expand(theSource, null);
|
||||
|
||||
ValueSet retVal = outcome.getValueset();
|
||||
retVal.setStatus(PublicationStatus.ACTIVE);
|
||||
|
||||
return retVal;
|
||||
|
||||
// ValueSetExpansionComponent expansion = outcome.getValueset().getExpansion();
|
||||
//
|
||||
// ValueSet retVal = new ValueSet();
|
||||
// retVal.getMeta().setLastUpdated(new Date());
|
||||
// retVal.setExpansion(expansion);
|
||||
// return retVal;
|
||||
}
|
||||
|
||||
private void validateIncludes(String name, List<ConceptSetComponent> listToValidate) {
|
||||
for (ConceptSetComponent nextExclude : listToValidate) {
|
||||
if (isBlank(nextExclude.getSystem()) && !ElementUtil.isEmpty(nextExclude.getConcept(), nextExclude.getFilter())) {
|
||||
throw new InvalidRequestException("ValueSet contains " + name + " criteria with no system defined");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expandByIdentifier(String theUri, String theFilter) {
|
||||
if (isBlank(theUri)) {
|
||||
throw new InvalidRequestException("URI must not be blank or missing");
|
||||
}
|
||||
|
||||
ValueSet source = new ValueSet();
|
||||
|
||||
source.getCompose().addInclude().addValueSet(theUri);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
ConceptSetComponent include = source.getCompose().addInclude();
|
||||
ConceptSetFilterComponent filter = include.addFilter();
|
||||
filter.setProperty("display");
|
||||
filter.setOp(FilterOperator.EQUAL);
|
||||
filter.setValue(theFilter);
|
||||
}
|
||||
|
||||
ValueSet retVal = doExpand(source);
|
||||
return retVal;
|
||||
|
||||
// if (defaultValueSet != null) {
|
||||
// source = getContext().newJsonParser().parseResource(ValueSet.class, getContext().newJsonParser().encodeResourceToString(defaultValueSet));
|
||||
// } else {
|
||||
// IBundleProvider ids = search(ValueSet.SP_URL, new UriParam(theUri));
|
||||
// if (ids.size() == 0) {
|
||||
// throw new InvalidRequestException("Unknown ValueSet URI: " + theUri);
|
||||
// }
|
||||
// source = (ValueSet) ids.getResources(0, 1).get(0);
|
||||
// }
|
||||
//
|
||||
// return expand(defaultValueSet, theFilter);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet expand(ValueSet source, String theFilter) {
|
||||
ValueSet toExpand = new ValueSet();
|
||||
|
||||
// for (UriType next : source.getCompose().getInclude()) {
|
||||
// ConceptSetComponent include = toExpand.getCompose().addInclude();
|
||||
// include.setSystem(next.getValue());
|
||||
// addFilterIfPresent(theFilter, include);
|
||||
// }
|
||||
|
||||
for (ConceptSetComponent next : source.getCompose().getInclude()) {
|
||||
toExpand.getCompose().addInclude(next);
|
||||
addFilterIfPresent(theFilter, next);
|
||||
}
|
||||
|
||||
if (toExpand.getCompose().isEmpty()) {
|
||||
throw new InvalidRequestException("ValueSet does not have any compose.include or compose.import values, can not expand");
|
||||
}
|
||||
|
||||
toExpand.getCompose().getExclude().addAll(source.getCompose().getExclude());
|
||||
|
||||
ValueSet retVal = doExpand(toExpand);
|
||||
|
||||
if (isNotBlank(theFilter)) {
|
||||
applyFilter(retVal.getExpansion().getTotalElement(), retVal.getExpansion().getContains(), theFilter);
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
private void applyFilter(IntegerType theTotalElement, List<ValueSetExpansionContainsComponent> theContains, String theFilter) {
|
||||
|
||||
for (int idx = 0; idx < theContains.size(); idx++) {
|
||||
ValueSetExpansionContainsComponent next = theContains.get(idx);
|
||||
if (isBlank(next.getDisplay()) || !org.apache.commons.lang3.StringUtils.containsIgnoreCase(next.getDisplay(), theFilter)) {
|
||||
theContains.remove(idx);
|
||||
idx--;
|
||||
if (theTotalElement.getValue() != null) {
|
||||
theTotalElement.setValue(theTotalElement.getValue() - 1);
|
||||
}
|
||||
}
|
||||
applyFilter(theTotalElement, next.getContains(), theFilter);
|
||||
}
|
||||
}
|
||||
|
||||
private void addFilterIfPresent(String theFilter, ConceptSetComponent include) {
|
||||
if (ElementUtil.isEmpty(include.getConcept())) {
|
||||
if (isNotBlank(theFilter)) {
|
||||
include.addFilter().setProperty("display").setOp(FilterOperator.EQUAL).setValue(theFilter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidateCodeResult validateCode(IPrimitiveType<String> theValueSetIdentifier, IIdType theId, IPrimitiveType<String> theCode,
|
||||
IPrimitiveType<String> theSystem, IPrimitiveType<String> theDisplay, Coding theCoding,
|
||||
CodeableConcept theCodeableConcept, RequestDetails theRequestDetails) {
|
||||
|
||||
List<IIdType> valueSetIds = Collections.emptyList();
|
||||
|
||||
boolean haveCodeableConcept = theCodeableConcept != null && theCodeableConcept.getCoding().size() > 0;
|
||||
boolean haveCoding = theCoding != null && theCoding.isEmpty() == false;
|
||||
boolean haveCode = theCode != null && theCode.isEmpty() == false;
|
||||
|
||||
if (!haveCodeableConcept && !haveCoding && !haveCode) {
|
||||
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate");
|
||||
}
|
||||
if (!LogicUtil.multiXor(haveCodeableConcept, haveCoding, haveCode)) {
|
||||
throw new InvalidRequestException("$validate-code can only validate (system AND code) OR (coding) OR (codeableConcept)");
|
||||
}
|
||||
|
||||
boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false;
|
||||
ValueSet vs = null;
|
||||
if (theId != null) {
|
||||
vs = read(theId, theRequestDetails);
|
||||
} else if (haveIdentifierParam) {
|
||||
vs = myValidationSupport.fetchResource(getContext(), ValueSet.class, theValueSetIdentifier.getValue());
|
||||
if (vs == null) {
|
||||
throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue());
|
||||
}
|
||||
} else {
|
||||
if (theCode == null || theCode.isEmpty()) {
|
||||
throw new InvalidRequestException("Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.");
|
||||
}
|
||||
// String code = theCode.getValue();
|
||||
// String system = toStringOrNull(theSystem);
|
||||
IContextValidationSupport.LookupCodeResult result = myCodeSystemDao.lookupCode(theCode, theSystem, null, null);
|
||||
if (result.isFound()) {
|
||||
ValidateCodeResult retVal = new ValidateCodeResult(true, "Found code", result.getCodeDisplay());
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
if (vs != null) {
|
||||
ValueSet expansion = doExpand(vs);
|
||||
List<ValueSetExpansionContainsComponent> contains = expansion.getExpansion().getContains();
|
||||
ValidateCodeResult result = validateCodeIsInContains(contains, toStringOrNull(theSystem), toStringOrNull(theCode), theCoding, theCodeableConcept);
|
||||
if (result != null) {
|
||||
if (theDisplay != null && isNotBlank(theDisplay.getValue()) && isNotBlank(result.getDisplay())) {
|
||||
if (!theDisplay.getValue().equals(result.getDisplay())) {
|
||||
return new ValidateCodeResult(false, "Display for code does not match", result.getDisplay());
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
return new ValidateCodeResult(false, "Code not found", null);
|
||||
|
||||
}
|
||||
|
||||
private String toStringOrNull(IPrimitiveType<String> thePrimitive) {
|
||||
return thePrimitive != null ? thePrimitive.getValue() : null;
|
||||
}
|
||||
|
||||
private ValidateCodeResult validateCodeIsInContains(List<ValueSetExpansionContainsComponent> contains, String theSystem, String theCode,
|
||||
Coding theCoding, CodeableConcept theCodeableConcept) {
|
||||
for (ValueSetExpansionContainsComponent nextCode : contains) {
|
||||
ValidateCodeResult result = validateCodeIsInContains(nextCode.getContains(), theSystem, theCode, theCoding, theCodeableConcept);
|
||||
if (result != null) {
|
||||
return result;
|
||||
}
|
||||
|
||||
String system = nextCode.getSystem();
|
||||
String code = nextCode.getCode();
|
||||
|
||||
if (isNotBlank(theCode)) {
|
||||
if (theCode.equals(code) && (isBlank(theSystem) || theSystem.equals(system))) {
|
||||
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
|
||||
}
|
||||
} else if (theCoding != null) {
|
||||
if (StringUtils.equals(system, theCoding.getSystem()) && StringUtils.equals(code, theCoding.getCode())) {
|
||||
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
|
||||
}
|
||||
} else {
|
||||
for (Coding next : theCodeableConcept.getCoding()) {
|
||||
if (StringUtils.equals(system, next.getSystem()) && StringUtils.equals(code, next.getCode())) {
|
||||
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void purgeCaches() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||
|
||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
||||
if (retVal.getDeleted() == null) {
|
||||
ValueSet valueSet = (ValueSet) theResource;
|
||||
myHapiTerminologySvc.storeTermValueSetAndChildren(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet));
|
||||
} else {
|
||||
myHapiTerminologySvc.deleteValueSetAndChildren(retVal);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.FhirResourceDaoMessageHeaderDstu2;
|
||||
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
||||
import ca.uhn.fhir.jpa.model.entity.TagDefinition;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r5.model.Meta;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.TypedQuery;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class FhirSystemDaoR5 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoR5.class);
|
||||
|
||||
@Autowired
|
||||
private TransactionProcessor<Bundle, BundleEntryComponent> myTransactionProcessor;
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
myTransactionProcessor.setDao(this);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Meta metaGetOperation(RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails);
|
||||
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
|
||||
|
||||
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
|
||||
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
|
||||
List<TagDefinition> tagDefinitions = q.getResultList();
|
||||
|
||||
return toMeta(tagDefinitions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseBundle processMessage(RequestDetails theRequestDetails, IBaseBundle theMessage) {
|
||||
return FhirResourceDaoMessageHeaderDstu2.throwProcessMessageNotImplemented();
|
||||
}
|
||||
|
||||
|
||||
protected Meta toMeta(Collection<TagDefinition> tagDefinitions) {
|
||||
Meta retVal = new Meta();
|
||||
for (TagDefinition next : tagDefinitions) {
|
||||
switch (next.getTagType()) {
|
||||
case PROFILE:
|
||||
retVal.addProfile(next.getCode());
|
||||
break;
|
||||
case SECURITY_LABEL:
|
||||
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
case TAG:
|
||||
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
@Override
|
||||
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
|
||||
return myTransactionProcessor.transaction(theRequestDetails, theRequest);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public interface IJpaValidationSupportR5 extends IValidationSupport {
|
||||
// nothing yet
|
||||
}
|
|
@ -0,0 +1,200 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.Transactional.TxType;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
@Transactional(value = TxType.REQUIRED)
|
||||
public class JpaValidationSupportR5 implements IJpaValidationSupportR5, ApplicationContextAware {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaValidationSupportR5.class);
|
||||
|
||||
private IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
|
||||
private IFhirResourceDao<ValueSet> myValueSetDao;
|
||||
private IFhirResourceDao<Questionnaire> myQuestionnaireDao;
|
||||
private IFhirResourceDao<CodeSystem> myCodeSystemDao;
|
||||
|
||||
@Autowired
|
||||
private FhirContext myR5Ctx;
|
||||
private ApplicationContext myApplicationContext;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public JpaValidationSupportR5() {
|
||||
super();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
return fetchResource(theCtx, CodeSystem.class, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theCtx, String theSystem) {
|
||||
return fetchResource(theCtx, ValueSet.class, theSystem);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
IdType id = new IdType(theUri);
|
||||
boolean localReference = false;
|
||||
if (id.hasBaseUrl() == false && id.hasIdPart() == true) {
|
||||
localReference = true;
|
||||
}
|
||||
|
||||
String resourceName = myR5Ctx.getResourceDefinition(theClass).getName();
|
||||
IBundleProvider search;
|
||||
if ("ValueSet".equals(resourceName)) {
|
||||
if (localReference) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(theUri));
|
||||
search = myValueSetDao.search(params);
|
||||
if (search.size() == 0) {
|
||||
params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myValueSetDao.search(params);
|
||||
}
|
||||
} else {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myValueSetDao.search(params);
|
||||
}
|
||||
} else if ("StructureDefinition".equals(resourceName)) {
|
||||
// Don't allow the core FHIR definitions to be overwritten
|
||||
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||
String typeName = theUri.substring("http://hl7.org/fhir/StructureDefinition/".length());
|
||||
if (myR5Ctx.getElementDefinition(typeName) != null) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(StructureDefinition.SP_URL, new UriParam(theUri));
|
||||
search = myStructureDefinitionDao.search(params);
|
||||
} else if ("Questionnaire".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(IAnyResource.SP_RES_ID, new StringParam(id.getIdPart()));
|
||||
search = myQuestionnaireDao.search(params);
|
||||
} else if ("CodeSystem".equals(resourceName)) {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(CodeSystem.SP_URL, new UriParam(theUri));
|
||||
search = myCodeSystemDao.search(params);
|
||||
} else {
|
||||
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
|
||||
}
|
||||
|
||||
if (search.size() == 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (search.size() > 1) {
|
||||
ourLog.warn("Found multiple {} instances with URL search value of: {}", resourceName, theUri);
|
||||
}
|
||||
|
||||
return (T) search.getResources(0, 1).get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return fetchResource(theCtx, StructureDefinition.class, theUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext theApplicationContext) throws BeansException {
|
||||
myApplicationContext = theApplicationContext;
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
myStructureDefinitionDao = myApplicationContext.getBean("myStructureDefinitionDaoR5", IFhirResourceDao.class);
|
||||
myValueSetDao = myApplicationContext.getBean("myValueSetDaoR5", IFhirResourceDao.class);
|
||||
myQuestionnaireDao = myApplicationContext.getBean("myQuestionnaireDaoR5", IFhirResourceDao.class);
|
||||
myCodeSystemDao = myApplicationContext.getBean("myCodeSystemDaoR5", IFhirResourceDao.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookupCodeResult lookupCode(FhirContext theContext, String theSystem, String theCode) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,166 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.OperationOutcome;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class TransactionProcessorVersionAdapterR5 implements TransactionProcessor.ITransactionProcessorVersionAdapter<Bundle, Bundle.BundleEntryComponent> {
|
||||
@Override
|
||||
public void setResponseStatus(Bundle.BundleEntryComponent theBundleEntry, String theStatus) {
|
||||
theBundleEntry.getResponse().setStatus(theStatus);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponseLastModified(Bundle.BundleEntryComponent theBundleEntry, Date theLastModified) {
|
||||
theBundleEntry.getResponse().setLastModified(theLastModified);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResource(Bundle.BundleEntryComponent theBundleEntry, IBaseResource theResource) {
|
||||
theBundleEntry.setResource((Resource) theResource);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource getResource(Bundle.BundleEntryComponent theBundleEntry) {
|
||||
return theBundleEntry.getResource();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getBundleType(Bundle theRequest) {
|
||||
if (theRequest.getType() == null) {
|
||||
return null;
|
||||
}
|
||||
return theRequest.getTypeElement().getValue().toCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void populateEntryWithOperationOutcome(BaseServerResponseException theCaughtEx, Bundle.BundleEntryComponent theEntry) {
|
||||
OperationOutcome oo = new OperationOutcome();
|
||||
oo.addIssue()
|
||||
.setSeverity(OperationOutcome.IssueSeverity.ERROR)
|
||||
.setDiagnostics(theCaughtEx.getMessage())
|
||||
.setCode(OperationOutcome.IssueType.EXCEPTION);
|
||||
theEntry.getResponse().setOutcome(oo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle createBundle(String theBundleType) {
|
||||
Bundle resp = new Bundle();
|
||||
try {
|
||||
resp.setType(Bundle.BundleType.fromCode(theBundleType));
|
||||
} catch (FHIRException theE) {
|
||||
throw new InternalErrorException("Unknown bundle type: " + theBundleType);
|
||||
}
|
||||
return resp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Bundle.BundleEntryComponent> getEntries(Bundle theRequest) {
|
||||
return theRequest.getEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addEntry(Bundle theBundle, Bundle.BundleEntryComponent theEntry) {
|
||||
theBundle.addEntry(theEntry);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle.BundleEntryComponent addEntry(Bundle theBundle) {
|
||||
return theBundle.addEntry();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryRequestVerb(Bundle.BundleEntryComponent theEntry) {
|
||||
String retVal = null;
|
||||
Bundle.HTTPVerb value = theEntry.getRequest().getMethodElement().getValue();
|
||||
if (value != null) {
|
||||
retVal = value.toCode();
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getFullUrl(Bundle.BundleEntryComponent theEntry) {
|
||||
return theEntry.getFullUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryIfNoneExist(Bundle.BundleEntryComponent theEntry) {
|
||||
return theEntry.getRequest().getIfNoneExist();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryRequestUrl(Bundle.BundleEntryComponent theEntry) {
|
||||
return theEntry.getRequest().getUrl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponseLocation(Bundle.BundleEntryComponent theEntry, String theResponseLocation) {
|
||||
theEntry.getResponse().setLocation(theResponseLocation);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponseETag(Bundle.BundleEntryComponent theEntry, String theEtag) {
|
||||
theEntry.getResponse().setEtag(theEtag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryRequestIfMatch(Bundle.BundleEntryComponent theEntry) {
|
||||
return theEntry.getRequest().getIfMatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryRequestIfNoneExist(Bundle.BundleEntryComponent theEntry) {
|
||||
return theEntry.getRequest().getIfNoneExist();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getEntryRequestIfNoneMatch(Bundle.BundleEntryComponent theEntry) {
|
||||
return theEntry.getRequest().getIfNoneMatch();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResponseOutcome(Bundle.BundleEntryComponent theEntry, IBaseOperationOutcome theOperationOutcome) {
|
||||
theEntry.getResponse().setOutcome((Resource) theOperationOutcome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestVerb(Bundle.BundleEntryComponent theEntry, String theVerb) {
|
||||
theEntry.getRequest().setMethod(Bundle.HTTPVerb.fromCode(theVerb));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRequestUrl(Bundle.BundleEntryComponent theEntry, String theUrl) {
|
||||
theEntry.getRequest().setUrl(theUrl);
|
||||
}
|
||||
|
||||
}
|
|
@ -68,7 +68,7 @@ public class BaseJpaResourceProviderStructureDefinitionDstu3 extends JpaResource
|
|||
sd = (StructureDefinition) outcome.getResources(0, 1).get(0);
|
||||
}
|
||||
|
||||
return getDao().generateSnapshot(sd, null, null);
|
||||
return getDao().generateSnapshot(sd, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -62,13 +62,15 @@ public class BaseJpaResourceProviderStructureDefinitionR4 extends JpaResourcePro
|
|||
map.setLoadSynchronousUpTo(2);
|
||||
map.add(StructureDefinition.SP_URL, new UriParam(theUrl.getValue()));
|
||||
IBundleProvider outcome = getDao().search(map, theRequestDetails);
|
||||
if (outcome.size() == 0) {
|
||||
Integer numResults = outcome.size();
|
||||
assert numResults != null;
|
||||
if (numResults == 0) {
|
||||
throw new ResourceNotFoundException("No StructureDefiniton found with url = '" + theUrl.getValue() + "'");
|
||||
}
|
||||
sd = (StructureDefinition) outcome.getResources(0, 1).get(0);
|
||||
}
|
||||
|
||||
return getDao().generateSnapshot(sd, null, null);
|
||||
return getDao().generateSnapshot(sd, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.List;
|
||||
|
||||
public class BaseJpaResourceProviderCodeSystemR5 extends JpaResourceProviderR5<CodeSystem> {
|
||||
|
||||
/**
|
||||
* $lookup operation
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
@Operation(name = JpaConstants.OPERATION_LOOKUP, idempotent = true, returnParameters= {
|
||||
@OperationParam(name="name", type=StringType.class, min=1),
|
||||
@OperationParam(name="version", type=StringType.class, min=0),
|
||||
@OperationParam(name="display", type=StringType.class, min=1),
|
||||
@OperationParam(name="abstract", type=BooleanType.class, min=1),
|
||||
})
|
||||
public Parameters lookup(
|
||||
HttpServletRequest theServletRequest,
|
||||
@OperationParam(name="code", min=0, max=1) CodeType theCode,
|
||||
@OperationParam(name="system", min=0, max=1) UriType theSystem,
|
||||
@OperationParam(name="coding", min=0, max=1) Coding theCoding,
|
||||
@OperationParam(name = "property", min = 0, max = OperationParam.MAX_UNLIMITED) List<CodeType> theProperties,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> dao = (IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept>) getDao();
|
||||
IContextValidationSupport.LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding, theRequestDetails);
|
||||
result.throwNotFoundIfAppropriate();
|
||||
return (Parameters) result.toParameters(theRequestDetails.getFhirContext(), theProperties);
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* $subsumes operation
|
||||
*/
|
||||
@Operation(name = JpaConstants.OPERATION_SUBSUMES, idempotent = true, returnParameters= {
|
||||
@OperationParam(name="outcome", type=CodeType.class, min=1),
|
||||
})
|
||||
public Parameters subsumes(
|
||||
HttpServletRequest theServletRequest,
|
||||
@OperationParam(name="codeA", min=0, max=1) CodeType theCodeA,
|
||||
@OperationParam(name="codeB", min=0, max=1) CodeType theCodeB,
|
||||
@OperationParam(name="system", min=0, max=1) UriType theSystem,
|
||||
@OperationParam(name="codingA", min=0, max=1) Coding theCodingA,
|
||||
@OperationParam(name="codingB", min=0, max=1) Coding theCodingB,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> dao = (IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept>) getDao();
|
||||
IFhirResourceDaoCodeSystem.SubsumesResult result = dao.subsumes(theCodeA, theCodeB, theSystem, theCodingA, theCodingB, theRequestDetails);
|
||||
return (Parameters) result.toParameters(theRequestDetails.getFhirContext());
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoComposition;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
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.Sort;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class BaseJpaResourceProviderCompositionR5 extends JpaResourceProviderR5<Composition> {
|
||||
|
||||
/**
|
||||
* Composition/123/$document
|
||||
*/
|
||||
@Operation(name = JpaConstants.OPERATION_DOCUMENT, idempotent = true, bundleType=BundleTypeEnum.DOCUMENT)
|
||||
public IBaseBundle getDocumentForComposition(
|
||||
|
||||
javax.servlet.http.HttpServletRequest theServletRequest,
|
||||
|
||||
@IdParam
|
||||
IdType theId,
|
||||
|
||||
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||
@OperationParam(name = Constants.PARAM_COUNT)
|
||||
UnsignedIntType theCount,
|
||||
|
||||
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
|
||||
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
|
||||
DateRangeParam theLastUpdated,
|
||||
|
||||
@Sort
|
||||
SortSpec theSortSpec,
|
||||
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
IBundleProvider bundleProvider = ((IFhirResourceDaoComposition<Composition>) getDao()).getDocumentForComposition(theServletRequest, theId, theCount, theLastUpdated, theSortSpec, theRequestDetails);
|
||||
List<IBaseResource> resourceList = bundleProvider.getResources(0, bundleProvider.size());
|
||||
|
||||
boolean foundCompositionResource = false;
|
||||
Bundle bundle = new Bundle().setType(Bundle.BundleType.DOCUMENT);
|
||||
for (IBaseResource resource : resourceList) {
|
||||
bundle.addEntry(new Bundle.BundleEntryComponent().setResource((Resource) resource));
|
||||
}
|
||||
return bundle;
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoConceptMap;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.term.TranslationRequest;
|
||||
import ca.uhn.fhir.jpa.term.TranslationResult;
|
||||
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.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.convertors.VersionConvertor_40_50;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
public class BaseJpaResourceProviderConceptMapR5 extends JpaResourceProviderR5<ConceptMap> {
|
||||
@Operation(name = JpaConstants.OPERATION_TRANSLATE, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "result", type = BooleanType.class, min = 1, max = 1),
|
||||
@OperationParam(name = "message", type = StringType.class, min = 0, max = 1),
|
||||
})
|
||||
public Parameters translate(
|
||||
HttpServletRequest theServletRequest,
|
||||
@IdParam(optional = true) IdType theId,
|
||||
@OperationParam(name = "code", min = 0, max = 1) CodeType theSourceCode,
|
||||
@OperationParam(name = "system", min = 0, max = 1) UriType theSourceCodeSystem,
|
||||
@OperationParam(name = "version", min = 0, max = 1) StringType theSourceCodeSystemVersion,
|
||||
@OperationParam(name = "source", min = 0, max = 1) UriType theSourceValueSet,
|
||||
@OperationParam(name = "coding", min = 0, max = 1) Coding theSourceCoding,
|
||||
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theSourceCodeableConcept,
|
||||
@OperationParam(name = "target", min = 0, max = 1) UriType theTargetValueSet,
|
||||
@OperationParam(name = "targetsystem", min = 0, max = 1) UriType theTargetCodeSystem,
|
||||
@OperationParam(name = "reverse", min = 0, max = 1) BooleanType theReverse,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
boolean haveSourceCode = theSourceCode != null
|
||||
&& theSourceCode.hasCode();
|
||||
boolean haveSourceCodeSystem = theSourceCodeSystem != null
|
||||
&& theSourceCodeSystem.hasValue();
|
||||
boolean haveSourceCodeSystemVersion = theSourceCodeSystemVersion != null
|
||||
&& theSourceCodeSystemVersion.hasValue();
|
||||
boolean haveSourceValueSet = theSourceValueSet != null
|
||||
&& theSourceValueSet.hasValue();
|
||||
boolean haveSourceCoding = theSourceCoding != null
|
||||
&& theSourceCoding.hasCode();
|
||||
boolean haveSourceCodeableConcept= theSourceCodeableConcept != null
|
||||
&& theSourceCodeableConcept.hasCoding()
|
||||
&& theSourceCodeableConcept.getCodingFirstRep().hasCode();
|
||||
boolean haveTargetValueSet = theTargetValueSet != null
|
||||
&& theTargetValueSet.hasValue();
|
||||
boolean haveTargetCodeSystem = theTargetCodeSystem != null
|
||||
&& theTargetCodeSystem.hasValue();
|
||||
boolean haveReverse = theReverse != null;
|
||||
boolean haveId = theId != null && theId.hasIdPart();
|
||||
|
||||
// <editor-fold desc="Filters">
|
||||
if ((!haveSourceCode && !haveSourceCoding && !haveSourceCodeableConcept)
|
||||
|| moreThanOneTrue(haveSourceCode, haveSourceCoding, haveSourceCodeableConcept)) {
|
||||
throw new InvalidRequestException("One (and only one) of the in parameters (code, coding, codeableConcept) must be provided, to identify the code that is to be translated.");
|
||||
}
|
||||
|
||||
TranslationRequest translationRequest = new TranslationRequest();
|
||||
|
||||
if (haveSourceCode) {
|
||||
translationRequest.getCodeableConcept().addCoding().setCodeElement(VersionConvertor_40_50.convertCode(theSourceCode));
|
||||
|
||||
if (haveSourceCodeSystem) {
|
||||
translationRequest.getCodeableConcept().getCodingFirstRep().setSystemElement(VersionConvertor_40_50.convertUri(theSourceCodeSystem));
|
||||
}
|
||||
|
||||
if (haveSourceCodeSystemVersion) {
|
||||
translationRequest.getCodeableConcept().getCodingFirstRep().setVersionElement(VersionConvertor_40_50.convertString(theSourceCodeSystemVersion));
|
||||
}
|
||||
} else if (haveSourceCoding) {
|
||||
translationRequest.getCodeableConcept().addCoding(VersionConvertor_40_50.convertCoding(theSourceCoding));
|
||||
} else {
|
||||
translationRequest.setCodeableConcept(VersionConvertor_40_50.convertCodeableConcept(theSourceCodeableConcept));
|
||||
}
|
||||
|
||||
if (haveSourceValueSet) {
|
||||
translationRequest.setSource(VersionConvertor_40_50.convertUri(theSourceValueSet));
|
||||
}
|
||||
|
||||
if (haveTargetValueSet) {
|
||||
translationRequest.setTarget(VersionConvertor_40_50.convertUri(theTargetValueSet));
|
||||
}
|
||||
|
||||
if (haveTargetCodeSystem) {
|
||||
translationRequest.setTargetSystem(VersionConvertor_40_50.convertUri(theTargetCodeSystem));
|
||||
}
|
||||
|
||||
if (haveReverse) {
|
||||
translationRequest.setReverse(VersionConvertor_40_50.convertBoolean(theReverse));
|
||||
}
|
||||
|
||||
if (haveId) {
|
||||
translationRequest.setResourceId(theId.getIdPartAsLong());
|
||||
}
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
IFhirResourceDaoConceptMap<ConceptMap> dao = (IFhirResourceDaoConceptMap<ConceptMap>) getDao();
|
||||
TranslationResult result = dao.translate(translationRequest, theRequestDetails);
|
||||
org.hl7.fhir.r4.model.Parameters parameters = result.toParameters();
|
||||
return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters);
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean moreThanOneTrue(boolean... theBooleans) {
|
||||
boolean haveOne = false;
|
||||
for (boolean next : theBooleans) {
|
||||
if (next) {
|
||||
if (haveOne) {
|
||||
return true;
|
||||
} else {
|
||||
haveOne = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoEncounter;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
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.Sort;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import org.hl7.fhir.r5.model.Encounter;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.UnsignedIntType;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class BaseJpaResourceProviderEncounterR5 extends JpaResourceProviderR5<Encounter> {
|
||||
|
||||
/**
|
||||
* Encounter/123/$everything
|
||||
*/
|
||||
@Operation(name = JpaConstants.OPERATION_EVERYTHING, idempotent = true, bundleType=BundleTypeEnum.SEARCHSET)
|
||||
public IBundleProvider EncounterInstanceEverything(
|
||||
|
||||
javax.servlet.http.HttpServletRequest theServletRequest,
|
||||
|
||||
@IdParam
|
||||
IdType theId,
|
||||
|
||||
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||
@OperationParam(name = Constants.PARAM_COUNT)
|
||||
UnsignedIntType theCount,
|
||||
|
||||
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
|
||||
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
|
||||
DateRangeParam theLastUpdated,
|
||||
|
||||
@Sort
|
||||
SortSpec theSortSpec
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
return ((IFhirResourceDaoEncounter<Encounter>)getDao()).encounterInstanceEverything(theServletRequest, theId, theCount, theLastUpdated, theSortSpec);
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}}
|
||||
|
||||
/**
|
||||
* /Encounter/$everything
|
||||
*/
|
||||
@Operation(name = JpaConstants.OPERATION_EVERYTHING, idempotent = true, bundleType=BundleTypeEnum.SEARCHSET)
|
||||
public IBundleProvider EncounterTypeEverything(
|
||||
|
||||
javax.servlet.http.HttpServletRequest theServletRequest,
|
||||
|
||||
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||
@OperationParam(name = Constants.PARAM_COUNT)
|
||||
UnsignedIntType theCount,
|
||||
|
||||
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
|
||||
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
|
||||
DateRangeParam theLastUpdated,
|
||||
|
||||
@Sort
|
||||
SortSpec theSortSpec
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
return ((IFhirResourceDaoEncounter<Encounter>)getDao()).encounterTypeEverything(theServletRequest, theCount, theLastUpdated, theSortSpec);
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import org.hl7.fhir.r5.model.MessageHeader;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class BaseJpaResourceProviderMessageHeaderR5 extends JpaResourceProviderR5<MessageHeader> {
|
||||
// nothing right now
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
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.Sort;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.StringAndListParam;
|
||||
import ca.uhn.fhir.rest.param.StringOrListParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.r5.model.UnsignedIntType;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class BaseJpaResourceProviderPatientR5 extends JpaResourceProviderR5<Patient> {
|
||||
|
||||
/**
|
||||
* Patient/123/$everything
|
||||
*/
|
||||
@Operation(name = JpaConstants.OPERATION_EVERYTHING, idempotent = true, bundleType = BundleTypeEnum.SEARCHSET)
|
||||
public IBundleProvider patientInstanceEverything(
|
||||
|
||||
javax.servlet.http.HttpServletRequest theServletRequest,
|
||||
|
||||
@IdParam
|
||||
IdType theId,
|
||||
|
||||
@Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||
@OperationParam(name = Constants.PARAM_COUNT)
|
||||
UnsignedIntType theCount,
|
||||
|
||||
@Description(shortDefinition = "Only return resources which were last updated as specified by the given range")
|
||||
@OperationParam(name = Constants.PARAM_LASTUPDATED, min = 0, max = 1)
|
||||
DateRangeParam theLastUpdated,
|
||||
|
||||
@Description(shortDefinition = "Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
|
||||
@OperationParam(name = Constants.PARAM_CONTENT, min = 0, max = OperationParam.MAX_UNLIMITED)
|
||||
List<StringType> theContent,
|
||||
|
||||
@Description(shortDefinition = "Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
|
||||
@OperationParam(name = Constants.PARAM_TEXT, min = 0, max = OperationParam.MAX_UNLIMITED)
|
||||
List<StringType> theNarrative,
|
||||
|
||||
@Sort
|
||||
SortSpec theSortSpec,
|
||||
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
return ((IFhirResourceDaoPatient<Patient>) getDao()).patientInstanceEverything(theServletRequest, theId, theCount, theLastUpdated, theSortSpec, toStringAndList(theContent), toStringAndList(theNarrative), theRequestDetails);
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* /Patient/$everything
|
||||
*/
|
||||
@Operation(name = JpaConstants.OPERATION_EVERYTHING, idempotent = true, bundleType = BundleTypeEnum.SEARCHSET)
|
||||
public IBundleProvider patientTypeEverything(
|
||||
|
||||
javax.servlet.http.HttpServletRequest theServletRequest,
|
||||
|
||||
@Description(formalDefinition = "Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||
@OperationParam(name = Constants.PARAM_COUNT)
|
||||
UnsignedIntType theCount,
|
||||
|
||||
@Description(shortDefinition = "Only return resources which were last updated as specified by the given range")
|
||||
@OperationParam(name = Constants.PARAM_LASTUPDATED, min = 0, max = 1)
|
||||
DateRangeParam theLastUpdated,
|
||||
|
||||
@Description(shortDefinition = "Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
|
||||
@OperationParam(name = Constants.PARAM_CONTENT, min = 0, max = OperationParam.MAX_UNLIMITED)
|
||||
List<StringType> theContent,
|
||||
|
||||
@Description(shortDefinition = "Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
|
||||
@OperationParam(name = Constants.PARAM_TEXT, min = 0, max = OperationParam.MAX_UNLIMITED)
|
||||
List<StringType> theNarrative,
|
||||
|
||||
@Sort
|
||||
SortSpec theSortSpec,
|
||||
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
return ((IFhirResourceDaoPatient<Patient>) getDao()).patientTypeEverything(theServletRequest, theCount, theLastUpdated, theSortSpec, toStringAndList(theContent), toStringAndList(theNarrative), theRequestDetails);
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private StringAndListParam toStringAndList(List<StringType> theNarrative) {
|
||||
StringAndListParam retVal = new StringAndListParam();
|
||||
if (theNarrative != null) {
|
||||
for (StringType next : theNarrative) {
|
||||
if (isNotBlank(next.getValue())) {
|
||||
retVal.addAnd(new StringOrListParam().addOr(new StringParam(next.getValue())));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (retVal.getValuesAsQueryTokens().isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoStructureDefinition;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
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.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.StringType;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class BaseJpaResourceProviderStructureDefinitionR5 extends JpaResourceProviderR5<StructureDefinition> {
|
||||
|
||||
/**
|
||||
* <code>$snapshot</code> operation
|
||||
*/
|
||||
@Operation(name=JpaConstants.OPERATION_SNAPSHOT, idempotent = true)
|
||||
public StructureDefinition snapshot(
|
||||
@IdParam(optional = true) IdType theId,
|
||||
@OperationParam(name = "definition") StructureDefinition theStructureDefinition,
|
||||
@OperationParam(name = "url") StringType theUrl,
|
||||
RequestDetails theRequestDetails) {
|
||||
|
||||
ValidateUtil.exactlyOneNotNullOrThrowInvalidRequestException(
|
||||
new Object[]{ theId, theStructureDefinition, theUrl },
|
||||
"Must supply either an ID or a StructureDefinition or a URL (but not more than one of these things)"
|
||||
);
|
||||
|
||||
StructureDefinition sd;
|
||||
if (theId == null && theStructureDefinition != null && theUrl == null) {
|
||||
sd = theStructureDefinition;
|
||||
} else if (theId != null && theStructureDefinition == null) {
|
||||
sd = getDao().read(theId, theRequestDetails);
|
||||
} else {
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLoadSynchronousUpTo(2);
|
||||
map.add(StructureDefinition.SP_URL, new UriParam(theUrl.getValue()));
|
||||
IBundleProvider outcome = getDao().search(map, theRequestDetails);
|
||||
Integer numResults = outcome.size();
|
||||
assert numResults != null;
|
||||
if (numResults == 0) {
|
||||
throw new ResourceNotFoundException("No StructureDefiniton found with url = '" + theUrl.getValue() + "'");
|
||||
}
|
||||
sd = (StructureDefinition) outcome.getResources(0, 1).get(0);
|
||||
}
|
||||
|
||||
return getDao().generateSnapshot(sd, null, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IFhirResourceDaoStructureDefinition<StructureDefinition> getDao() {
|
||||
return (IFhirResourceDaoStructureDefinition<StructureDefinition>) super.getDao();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
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.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<ValueSet> {
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_EXPAND, idempotent = true)
|
||||
public ValueSet expand(
|
||||
HttpServletRequest theServletRequest,
|
||||
@IdParam(optional = true) IdType theId,
|
||||
@OperationParam(name = "valueSet", min = 0, max = 1) ValueSet theValueSet,
|
||||
@OperationParam(name = "url", min = 0, max = 1) UriType theUrl,
|
||||
@OperationParam(name = "filter", min = 0, max = 1) StringType theFilter,
|
||||
RequestDetails theRequestDetails) {
|
||||
|
||||
boolean haveId = theId != null && theId.hasIdPart();
|
||||
boolean haveIdentifier = theUrl != null && isNotBlank(theUrl.getValue());
|
||||
boolean haveValueSet = theValueSet != null && theValueSet.isEmpty() == false;
|
||||
|
||||
if (!haveId && !haveIdentifier && !haveValueSet) {
|
||||
throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires a url or a valueSet as a part of the request");
|
||||
}
|
||||
|
||||
if (moreThanOneTrue(haveId, haveIdentifier, haveValueSet)) {
|
||||
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
|
||||
}
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
||||
if (haveId) {
|
||||
return dao.expand(theId, toFilterString(theFilter), theRequestDetails);
|
||||
} else if (haveIdentifier) {
|
||||
return dao.expandByIdentifier(theUrl.getValue(), toFilterString(theFilter));
|
||||
} else {
|
||||
return dao.expand(theValueSet, toFilterString(theFilter));
|
||||
}
|
||||
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private String toFilterString(StringType theFilter) {
|
||||
return theFilter != null ? theFilter.getValue() : null;
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Operation(name = JpaConstants.OPERATION_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 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 = "coding", min = 0, max = 1) Coding theCoding,
|
||||
@OperationParam(name = "codeableConcept", min = 0, max = 1) CodeableConcept theCodeableConcept,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
||||
ValidateCodeResult result = dao.validateCode(theValueSetUrl, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept, theRequestDetails);
|
||||
Parameters retVal = new Parameters();
|
||||
retVal.addParameter().setName("result").setValue(new BooleanType(result.isResult()));
|
||||
if (isNotBlank(result.getMessage())) {
|
||||
retVal.addParameter().setName("message").setValue(new StringType(result.getMessage()));
|
||||
}
|
||||
if (isNotBlank(result.getDisplay())) {
|
||||
retVal.addParameter().setName("display").setValue(new StringType(result.getDisplay()));
|
||||
}
|
||||
return retVal;
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private static boolean moreThanOneTrue(boolean... theBooleans) {
|
||||
boolean haveOne = false;
|
||||
for (boolean next : theBooleans) {
|
||||
if (next) {
|
||||
if (haveOne) {
|
||||
return true;
|
||||
} else {
|
||||
haveOne = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.ExtensionConstants;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.CapabilityStatement.*;
|
||||
import org.hl7.fhir.r5.model.Enumerations.SearchParamType;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class JpaConformanceProviderR5 extends org.hl7.fhir.r5.hapi.rest.server.ServerCapabilityStatementProvider {
|
||||
|
||||
private volatile CapabilityStatement myCachedValue;
|
||||
private DaoConfig myDaoConfig;
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
private String myImplementationDescription;
|
||||
private boolean myIncludeResourceCounts;
|
||||
private RestfulServer myRestfulServer;
|
||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
@CoverageIgnore
|
||||
public JpaConformanceProviderR5(){
|
||||
super();
|
||||
super.setCache(false);
|
||||
setIncludeResourceCounts(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public JpaConformanceProviderR5(RestfulServer theRestfulServer, IFhirSystemDao<Bundle, Meta> theSystemDao, DaoConfig theDaoConfig) {
|
||||
super(theRestfulServer);
|
||||
myRestfulServer = theRestfulServer;
|
||||
mySystemDao = theSystemDao;
|
||||
myDaoConfig = theDaoConfig;
|
||||
super.setCache(false);
|
||||
setIncludeResourceCounts(true);
|
||||
setSearchParamRegistry(theSystemDao.getSearchParamRegistry());
|
||||
}
|
||||
|
||||
public void setSearchParamRegistry(ISearchParamRegistry theSearchParamRegistry) {
|
||||
mySearchParamRegistry = theSearchParamRegistry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
|
||||
CapabilityStatement retVal = myCachedValue;
|
||||
|
||||
Map<String, Long> counts = null;
|
||||
if (myIncludeResourceCounts) {
|
||||
counts = mySystemDao.getResourceCountsFromCache();
|
||||
}
|
||||
counts = defaultIfNull(counts, Collections.emptyMap());
|
||||
|
||||
retVal = super.getServerConformance(theRequest, theRequestDetails);
|
||||
for (CapabilityStatementRestComponent nextRest : retVal.getRest()) {
|
||||
|
||||
for (CapabilityStatementRestResourceComponent nextResource : nextRest.getResource()) {
|
||||
|
||||
nextResource.setVersioning(ResourceVersionPolicy.VERSIONEDUPDATE);
|
||||
|
||||
ConditionalDeleteStatus conditionalDelete = nextResource.getConditionalDelete();
|
||||
if (conditionalDelete == ConditionalDeleteStatus.MULTIPLE && myDaoConfig.isAllowMultipleDelete() == false) {
|
||||
nextResource.setConditionalDelete(ConditionalDeleteStatus.SINGLE);
|
||||
}
|
||||
|
||||
// Add resource counts
|
||||
Long count = counts.get(nextResource.getTypeElement().getValueAsString());
|
||||
if (count != null) {
|
||||
nextResource.addExtension(new Extension(ExtensionConstants.CONF_RESOURCE_COUNT, new DecimalType(count)));
|
||||
}
|
||||
|
||||
nextResource.getSearchParam().clear();
|
||||
String resourceName = nextResource.getType();
|
||||
RuntimeResourceDefinition resourceDef = myRestfulServer.getFhirContext().getResourceDefinition(resourceName);
|
||||
Collection<RuntimeSearchParam> searchParams = mySearchParamRegistry.getSearchParamsByResourceType(resourceDef);
|
||||
for (RuntimeSearchParam runtimeSp : searchParams) {
|
||||
CapabilityStatementRestResourceSearchParamComponent confSp = nextResource.addSearchParam();
|
||||
|
||||
confSp.setName(runtimeSp.getName());
|
||||
confSp.setDocumentation(runtimeSp.getDescription());
|
||||
confSp.setDefinition(runtimeSp.getUri());
|
||||
switch (runtimeSp.getParamType()) {
|
||||
case COMPOSITE:
|
||||
confSp.setType(SearchParamType.COMPOSITE);
|
||||
break;
|
||||
case DATE:
|
||||
confSp.setType(SearchParamType.DATE);
|
||||
break;
|
||||
case NUMBER:
|
||||
confSp.setType(SearchParamType.NUMBER);
|
||||
break;
|
||||
case QUANTITY:
|
||||
confSp.setType(SearchParamType.QUANTITY);
|
||||
break;
|
||||
case REFERENCE:
|
||||
confSp.setType(SearchParamType.REFERENCE);
|
||||
break;
|
||||
case STRING:
|
||||
confSp.setType(SearchParamType.STRING);
|
||||
break;
|
||||
case TOKEN:
|
||||
confSp.setType(SearchParamType.TOKEN);
|
||||
break;
|
||||
case URI:
|
||||
confSp.setType(SearchParamType.URI);
|
||||
break;
|
||||
case HAS:
|
||||
// Shouldn't happen
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if (myDaoConfig.getSupportedSubscriptionTypes().contains(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.WEBSOCKET)) {
|
||||
if (isNotBlank(myDaoConfig.getWebsocketContextPath())) {
|
||||
Extension websocketExtension = new Extension();
|
||||
websocketExtension.setUrl(Constants.CAPABILITYSTATEMENT_WEBSOCKET_URL);
|
||||
websocketExtension.setValue(new UriType(myDaoConfig.getWebsocketContextPath()));
|
||||
retVal.getRestFirstRep().addExtension(websocketExtension);
|
||||
}
|
||||
}
|
||||
|
||||
massage(retVal);
|
||||
|
||||
retVal.getImplementation().setDescription(myImplementationDescription);
|
||||
myCachedValue = retVal;
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public boolean isIncludeResourceCounts() {
|
||||
return myIncludeResourceCounts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may override
|
||||
*/
|
||||
protected void massage(CapabilityStatement theStatement) {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public void setDaoConfig(DaoConfig myDaoConfig) {
|
||||
this.myDaoConfig = myDaoConfig;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
public void setImplementationDescription(String theImplDesc) {
|
||||
myImplementationDescription = theImplDesc;
|
||||
}
|
||||
|
||||
public void setIncludeResourceCounts(boolean theIncludeResourceCounts) {
|
||||
myIncludeResourceCounts = theIncludeResourceCounts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRestfulServer(RestfulServer theRestfulServer) {
|
||||
this.myRestfulServer = theRestfulServer;
|
||||
super.setRestfulServer(theRestfulServer);
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
public void setSystemDao(IFhirSystemDao<Bundle, Meta> mySystemDao) {
|
||||
this.mySystemDao = mySystemDao;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaResourceProvider;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import static ca.uhn.fhir.jpa.model.util.JpaConstants.*;
|
||||
|
||||
public class JpaResourceProviderR5<T extends IAnyResource> extends BaseJpaResourceProvider<T> {
|
||||
|
||||
public JpaResourceProviderR5() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public JpaResourceProviderR5(IFhirResourceDao<T> theDao) {
|
||||
super(theDao);
|
||||
}
|
||||
|
||||
@Create
|
||||
public MethodOutcome create(HttpServletRequest theRequest, @ResourceParam T theResource, @ConditionalUrlParam String theConditional, RequestDetails theRequestDetails) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
if (theConditional != null) {
|
||||
return getDao().create(theResource, theConditional, theRequestDetails);
|
||||
} else {
|
||||
return getDao().create(theResource, theRequestDetails);
|
||||
}
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Delete()
|
||||
public MethodOutcome delete(HttpServletRequest theRequest, @IdParam IdType theResource, @ConditionalUrlParam(supportsMultiple = true) String theConditional, RequestDetails theRequestDetails) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
if (theConditional != null) {
|
||||
return getDao().deleteByUrl(theConditional, theRequestDetails);
|
||||
} else {
|
||||
return getDao().delete(theResource, theRequestDetails);
|
||||
}
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@IdParam IIdType theIdParam,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions,
|
||||
RequestDetails theRequest) {
|
||||
|
||||
org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(theIdParam, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null, theRequest);
|
||||
return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters);
|
||||
|
||||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions,
|
||||
RequestDetails theRequest) {
|
||||
org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(null, theLimit, theExpungeDeletedResources, theExpungeOldVersions, null, theRequest);
|
||||
return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters);
|
||||
}
|
||||
|
||||
@Operation(name = OPERATION_META, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = Meta.class)
|
||||
})
|
||||
public Parameters meta(RequestDetails theRequestDetails) {
|
||||
Parameters parameters = new Parameters();
|
||||
Meta metaGetOperation = getDao().metaGetOperation(Meta.class, theRequestDetails);
|
||||
parameters.addParameter().setName("return").setValue(metaGetOperation);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Operation(name = OPERATION_META, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = Meta.class)
|
||||
})
|
||||
public Parameters meta(@IdParam IdType theId, RequestDetails theRequestDetails) {
|
||||
Parameters parameters = new Parameters();
|
||||
Meta metaGetOperation = getDao().metaGetOperation(Meta.class, theId, theRequestDetails);
|
||||
parameters.addParameter().setName("return").setValue(metaGetOperation);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Operation(name = OPERATION_META_ADD, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = Meta.class)
|
||||
})
|
||||
public Parameters metaAdd(@IdParam IdType theId, @OperationParam(name = "meta") Meta theMeta, RequestDetails theRequestDetails) {
|
||||
if (theMeta == null) {
|
||||
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
|
||||
}
|
||||
Parameters parameters = new Parameters();
|
||||
Meta metaAddOperation = getDao().metaAddOperation(theId, theMeta, theRequestDetails);
|
||||
parameters.addParameter().setName("return").setValue(metaAddOperation);
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Operation(name = OPERATION_META_DELETE, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = Meta.class)
|
||||
})
|
||||
public Parameters metaDelete(@IdParam IdType theId, @OperationParam(name = "meta") Meta theMeta, RequestDetails theRequestDetails) {
|
||||
if (theMeta == null) {
|
||||
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
|
||||
}
|
||||
Parameters parameters = new Parameters();
|
||||
parameters.addParameter().setName("return").setValue(getDao().metaDeleteOperation(theId, theMeta, theRequestDetails));
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Update
|
||||
public MethodOutcome update(HttpServletRequest theRequest, @ResourceParam T theResource, @IdParam IdType theId, @ConditionalUrlParam String theConditional, RequestDetails theRequestDetails) {
|
||||
startRequest(theRequest);
|
||||
try {
|
||||
if (theConditional != null) {
|
||||
return getDao().update(theResource, theConditional, theRequestDetails);
|
||||
} else {
|
||||
return getDao().update(theResource, theRequestDetails);
|
||||
}
|
||||
} finally {
|
||||
endRequest(theRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@Validate
|
||||
public MethodOutcome validate(@ResourceParam T theResource, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
|
||||
@Validate.Profile String theProfile, RequestDetails theRequestDetails) {
|
||||
return validate(theResource, null, theRawResource, theEncoding, theMode, theProfile, theRequestDetails);
|
||||
}
|
||||
|
||||
@Validate
|
||||
public MethodOutcome validate(@ResourceParam T theResource, @IdParam IdType theId, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
|
||||
@Validate.Profile String theProfile, RequestDetails theRequestDetails) {
|
||||
return getDao().validate(theResource, theId, theRawResource, theEncoding, theMode, theProfile, theRequestDetails);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,270 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.provider.BaseJpaSystemProviderDstu2Plus;
|
||||
import ca.uhn.fhir.model.api.annotation.Description;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class JpaSystemProviderR5 extends BaseJpaSystemProviderDstu2Plus<Bundle, Meta> {
|
||||
|
||||
@Autowired()
|
||||
@Qualifier("mySystemDaoR5")
|
||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
|
||||
@Autowired(required = false)
|
||||
private IFulltextSearchSvc mySearchDao;
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@IdParam IIdType theIdParam,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_EVERYTHING) BooleanType theExpungeEverything,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(theLimit, theExpungeDeletedResources, theExpungeOldVersions, theExpungeEverything, theRequestDetails);
|
||||
return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters);
|
||||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_EXPUNGE, idempotent = false, returnParameters = {
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_OUT_PARAM_EXPUNGE_COUNT, type = IntegerType.class)
|
||||
})
|
||||
public Parameters expunge(
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_LIMIT) IntegerType theLimit,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_DELETED_RESOURCES) BooleanType theExpungeDeletedResources,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_PREVIOUS_VERSIONS) BooleanType theExpungeOldVersions,
|
||||
@OperationParam(name = JpaConstants.OPERATION_EXPUNGE_PARAM_EXPUNGE_EVERYTHING) BooleanType theExpungeEverything,
|
||||
RequestDetails theRequestDetails
|
||||
) {
|
||||
org.hl7.fhir.r4.model.Parameters parameters = super.doExpunge(theLimit, theExpungeDeletedResources, theExpungeOldVersions, theExpungeEverything, theRequestDetails);
|
||||
return org.hl7.fhir.convertors.conv40_50.Parameters.convertParameters(parameters);
|
||||
}
|
||||
|
||||
// This is generated by hand:
|
||||
// ls hapi-fhir-structures-dstu2/target/generated-sources/tinder/ca/uhn/fhir/model/dstu2/resource/ | sort | sed "s/.java//" | sed "s/^/@OperationParam(name=\"/" | sed "s/$/\", type=IntegerType.class, min=0, max=1),/"
|
||||
@Operation(name = JpaConstants.OPERATION_GET_RESOURCE_COUNTS, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "AllergyIntolerance", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Appointment", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "AppointmentResponse", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "AuditEvent", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Basic", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Binary", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "BodySite", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Bundle", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "CarePlan", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "CarePlan2", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Claim", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ClaimResponse", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ClinicalImpression", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Communication", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "CommunicationRequest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Composition", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ConceptMap", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Condition", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Conformance", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Contract", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Contraindication", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Coverage", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DataElement", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Device", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DeviceComponent", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DeviceMetric", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DeviceUseRequest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DeviceUseStatement", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DiagnosticOrder", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DiagnosticReport", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DocumentManifest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "DocumentReference", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "EligibilityRequest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "EligibilityResponse", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Encounter", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "EnrollmentRequest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "EnrollmentResponse", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "EpisodeOfCare", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ExplanationOfBenefit", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "FamilyMemberHistory", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Flag", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Goal", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Group", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "HealthcareService", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ImagingObjectSelection", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ImagingStudy", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Immunization", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ImmunizationRecommendation", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ListResource", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Location", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Media", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Medication", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "MedicationAdministration", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "MedicationDispense", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "MedicationPrescription", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "MedicationStatement", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "MessageHeader", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "NamingSystem", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "NutritionOrder", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Observation", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "OperationDefinition", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "OperationOutcome", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Order", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "OrderResponse", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Organization", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Parameters", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Patient", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "PaymentNotice", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "PaymentReconciliation", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Person", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Practitioner", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Procedure", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ProcedureRequest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ProcessRequest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ProcessResponse", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Provenance", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Questionnaire", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "QuestionnaireAnswers", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ReferralRequest", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "RelatedPerson", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "RiskAssessment", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Schedule", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "SearchParameter", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Slot", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Specimen", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "StructureDefinition", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Subscription", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Substance", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "Supply", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "ValueSet", type = IntegerType.class, min = 0, max = 1),
|
||||
@OperationParam(name = "VisionPrescription", type = IntegerType.class, min = 0, max = 1)
|
||||
})
|
||||
@Description(shortDefinition = "Provides the number of resources currently stored on the server, broken down by resource type")
|
||||
public Parameters getResourceCounts() {
|
||||
Parameters retVal = new Parameters();
|
||||
|
||||
Map<String, Long> counts = mySystemDao.getResourceCountsFromCache();
|
||||
counts = defaultIfNull(counts, Collections.emptyMap());
|
||||
counts = new TreeMap<>(counts);
|
||||
for (Entry<String, Long> nextEntry : counts.entrySet()) {
|
||||
retVal.addParameter().setName((nextEntry.getKey())).setValue(new IntegerType(nextEntry.getValue().intValue()));
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_META, idempotent = true, returnParameters = {
|
||||
@OperationParam(name = "return", type = Meta.class)
|
||||
})
|
||||
public Parameters meta(RequestDetails theRequestDetails) {
|
||||
Parameters parameters = new Parameters();
|
||||
parameters.addParameter().setName("return").setValue(getDao().metaGetOperation(theRequestDetails));
|
||||
return parameters;
|
||||
}
|
||||
|
||||
@Operation(name = JpaConstants.OPERATION_SUGGEST_KEYWORDS, idempotent = true)
|
||||
public Parameters suggestKeywords(
|
||||
@OperationParam(name = "context", min = 1, max = 1) String theContext,
|
||||
@OperationParam(name = "searchParam", min = 1, max = 1) String theSearchParam,
|
||||
@OperationParam(name = "text", min = 1, max = 1) String theText,
|
||||
RequestDetails theRequest) {
|
||||
ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3.validateFulltextSearchEnabled(mySearchDao);
|
||||
|
||||
if (isBlank(theContext)) {
|
||||
throw new InvalidRequestException("Parameter 'context' must be provided");
|
||||
}
|
||||
if (isBlank(theSearchParam)) {
|
||||
throw new InvalidRequestException("Parameter 'searchParam' must be provided");
|
||||
}
|
||||
if (isBlank(theText)) {
|
||||
throw new InvalidRequestException("Parameter 'text' must be provided");
|
||||
}
|
||||
|
||||
List<Suggestion> keywords = mySearchDao.suggestKeywords(theContext, theSearchParam, theText, theRequest);
|
||||
|
||||
Parameters retVal = new Parameters();
|
||||
for (Suggestion next : keywords) {
|
||||
//@formatter:off
|
||||
retVal.addParameter()
|
||||
.addPart(new ParametersParameterComponent().setName("keyword").setValue(new StringType(next.getTerm())))
|
||||
.addPart(new ParametersParameterComponent().setName("score").setValue(new DecimalType(next.getScore())));
|
||||
//@formatter:on
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* /$process-message
|
||||
*/
|
||||
@Operation(name = JpaConstants.OPERATION_PROCESS_MESSAGE, idempotent = false)
|
||||
public IBaseBundle processMessage(
|
||||
HttpServletRequest theServletRequest,
|
||||
RequestDetails theRequestDetails,
|
||||
|
||||
@OperationParam(name = "content", min = 1, max = 1)
|
||||
@Description(formalDefinition = "The message to process (or, if using asynchronous messaging, it may be a response message to accept)")
|
||||
Bundle theMessageToProcess
|
||||
) {
|
||||
|
||||
startRequest(theServletRequest);
|
||||
try {
|
||||
return getDao().processMessage(theRequestDetails, theMessageToProcess);
|
||||
} finally {
|
||||
endRequest(theServletRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transaction
|
||||
public Bundle transaction(RequestDetails theRequestDetails, @TransactionParam Bundle theResources) {
|
||||
startRequest(((ServletRequestDetails) theRequestDetails).getServletRequest());
|
||||
try {
|
||||
return getDao().transaction(theRequestDetails, theResources);
|
||||
} finally {
|
||||
endRequest(((ServletRequestDetails) theRequestDetails).getServletRequest());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -242,7 +242,7 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvcImpl implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theProfileName) {
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,334 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public class HapiTerminologySvcR5 extends BaseHapiTerminologySvcImpl implements IValidationSupport, IHapiTerminologySvcR5 {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myValueSetDaoR5")
|
||||
private IFhirResourceDao<ValueSet> myValueSetResourceDao;
|
||||
@Autowired
|
||||
@Qualifier("myConceptMapDaoR5")
|
||||
private IFhirResourceDao<ConceptMap> myConceptMapResourceDao;
|
||||
@Autowired
|
||||
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemResourceDao;
|
||||
@Autowired
|
||||
private IValidationSupport myValidationSupport;
|
||||
@Autowired
|
||||
private IHapiTerminologySvc myTerminologySvc;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public HapiTerminologySvcR5() {
|
||||
super();
|
||||
}
|
||||
|
||||
private void addAllChildren(String theSystemString, ConceptDefinitionComponent theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
if (isNotBlank(theCode.getCode())) {
|
||||
theListToPopulate.add(new VersionIndependentConcept(theSystemString, theCode.getCode()));
|
||||
}
|
||||
for (ConceptDefinitionComponent nextChild : theCode.getConcept()) {
|
||||
addAllChildren(theSystemString, nextChild, theListToPopulate);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean addTreeIfItContainsCode(String theSystemString, ConceptDefinitionComponent theNext, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
boolean foundCodeInChild = false;
|
||||
for (ConceptDefinitionComponent nextChild : theNext.getConcept()) {
|
||||
foundCodeInChild |= addTreeIfItContainsCode(theSystemString, nextChild, theCode, theListToPopulate);
|
||||
}
|
||||
|
||||
if (theCode.equals(theNext.getCode()) || foundCodeInChild) {
|
||||
theListToPopulate.add(new VersionIndependentConcept(theSystemString, theNext.getCode()));
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IIdType createOrUpdateCodeSystem(org.hl7.fhir.r4.model.CodeSystem theCodeSystemResource) {
|
||||
CodeSystem resourceToStore;
|
||||
try {
|
||||
resourceToStore = org.hl7.fhir.convertors.conv40_50.CodeSystem.convertCodeSystem(theCodeSystemResource);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
validateCodeSystemForStorage(theCodeSystemResource);
|
||||
if (isBlank(resourceToStore.getIdElement().getIdPart())) {
|
||||
String matchUrl = "CodeSystem?url=" + UrlUtil.escapeUrlParam(theCodeSystemResource.getUrl());
|
||||
return myCodeSystemResourceDao.update(resourceToStore, matchUrl).getId();
|
||||
} else {
|
||||
return myCodeSystemResourceDao.update(resourceToStore).getId();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createOrUpdateConceptMap(org.hl7.fhir.r4.model.ConceptMap theConceptMap) {
|
||||
ConceptMap resourceToStore;
|
||||
try {
|
||||
resourceToStore = org.hl7.fhir.convertors.conv40_50.ConceptMap.convertConceptMap(theConceptMap);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
if (isBlank(resourceToStore.getIdElement().getIdPart())) {
|
||||
String matchUrl = "ConceptMap?url=" + UrlUtil.escapeUrlParam(theConceptMap.getUrl());
|
||||
myConceptMapResourceDao.update(resourceToStore, matchUrl);
|
||||
} else {
|
||||
myConceptMapResourceDao.update(resourceToStore);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void createOrUpdateValueSet(org.hl7.fhir.r4.model.ValueSet theValueSet) {
|
||||
ValueSet valueSetDstu3;
|
||||
try {
|
||||
valueSetDstu3 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(theValueSet);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
if (isBlank(valueSetDstu3.getIdElement().getIdPart())) {
|
||||
String matchUrl = "ValueSet?url=" + UrlUtil.escapeUrlParam(theValueSet.getUrl());
|
||||
myValueSetResourceDao.update(valueSetDstu3, matchUrl);
|
||||
} else {
|
||||
myValueSetResourceDao.update(valueSetDstu3);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
ValueSet valueSetToExpand = new ValueSet();
|
||||
valueSetToExpand.getCompose().addInclude(theInclude);
|
||||
|
||||
try {
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;
|
||||
valueSetToExpandR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSetToExpand);
|
||||
org.hl7.fhir.r4.model.ValueSet expandedValueSet = super.expandValueSet(valueSetToExpandR4);
|
||||
return new ValueSetExpander.ValueSetExpansionOutcome(org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(expandedValueSet));
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource expandValueSet(IBaseResource theInput) {
|
||||
ValueSet valueSetToExpand = (ValueSet) theInput;
|
||||
|
||||
try {
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;
|
||||
valueSetToExpandR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSetToExpand);
|
||||
org.hl7.fhir.r4.model.ValueSet expandedR4 = super.expandValueSet(valueSetToExpandR4);
|
||||
return org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(expandedR4);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void expandValueSet(IBaseResource theValueSetToExpand, IValueSetCodeAccumulator theValueSetCodeAccumulator) {
|
||||
ValueSet valueSetToExpand = (ValueSet) theValueSetToExpand;
|
||||
|
||||
try {
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;
|
||||
valueSetToExpandR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSetToExpand);
|
||||
super.expandValueSet(valueSetToExpandR4, theValueSetCodeAccumulator);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||
ValueSet vs = myValidationSupport.fetchResource(myContext, ValueSet.class, theValueSet);
|
||||
if (vs == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
org.hl7.fhir.r4.model.ValueSet valueSetToExpandR4;
|
||||
try {
|
||||
valueSetToExpandR4 = org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(vs);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
|
||||
return expandValueSetAndReturnVersionIndependentConcepts(valueSetToExpandR4);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource fetchResource(FhirContext theContext, Class theClass, String theUri) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void findCodesAbove(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
|
||||
for (ConceptDefinitionComponent next : conceptList) {
|
||||
addTreeIfItContainsCode(theSystemString, next, theCode, theListToPopulate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> findCodesAboveUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<>();
|
||||
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
if (system != null) {
|
||||
findCodesAbove(system, theSystem, theCode, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void findCodesBelow(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
|
||||
findCodesBelow(theSystemString, theCode, theListToPopulate, conceptList);
|
||||
}
|
||||
|
||||
private void findCodesBelow(String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate, List<ConceptDefinitionComponent> conceptList) {
|
||||
for (ConceptDefinitionComponent next : conceptList) {
|
||||
if (theCode.equals(next.getCode())) {
|
||||
addAllChildren(theSystemString, next, theListToPopulate);
|
||||
} else {
|
||||
findCodesBelow(theSystemString, theCode, theListToPopulate, next.getConcept());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> findCodesBelowUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<>();
|
||||
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
if (system != null) {
|
||||
findCodesBelow(system, theSystem, theCode, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected org.hl7.fhir.r4.model.CodeSystem getCodeSystemFromContext(String theSystem) {
|
||||
CodeSystem codeSystem = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
try {
|
||||
return org.hl7.fhir.convertors.conv40_50.CodeSystem.convertCodeSystem(codeSystem);
|
||||
} catch (FHIRException e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return myTerminologySvc.supportsSystem(theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@CoverageIgnore
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
return txTemplate.execute(t->{
|
||||
Optional<TermConcept> codeOpt = myTerminologySvc.findCode(theCodeSystem, theCode);
|
||||
if (codeOpt.isPresent()) {
|
||||
ConceptDefinitionComponent def = new ConceptDefinitionComponent();
|
||||
TermConcept code = codeOpt.get();
|
||||
def.setCode(code.getCode());
|
||||
def.setDisplay(code.getDisplay());
|
||||
CodeValidationResult retVal = new CodeValidationResult(def);
|
||||
retVal.setProperties(code.toValidationProperties());
|
||||
retVal.setCodeSystemName(code.getCodeSystemVersion().getCodeSystem().getName());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.ERROR, "Unknown code {" + theCodeSystem + "}" + theCode);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public LookupCodeResult lookupCode(FhirContext theContext, String theSystem, String theCode) {
|
||||
return super.lookupCode(theContext, theSystem, theCode);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
|
||||
public interface IHapiTerminologySvcR5 extends IHapiTerminologySvc, IValidationSupport {
|
||||
// nothing
|
||||
}
|
|
@ -69,7 +69,7 @@ public class JpaValidationSupportChainR4 extends ValidationSupportChain {
|
|||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
StructureDefinition retVal = super.fetchStructureDefinition(theCtx, theUrl);
|
||||
if (retVal != null && !retVal.hasSnapshot()) {
|
||||
retVal = generateSnapshot(retVal, theUrl, null);
|
||||
retVal = generateSnapshot(retVal, theUrl, null, null);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,91 @@
|
|||
package ca.uhn.fhir.jpa.validation;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR5;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r5.hapi.validation.SnapshotGeneratingValidationSupport;
|
||||
import org.hl7.fhir.r5.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
public class JpaValidationSupportChainR5 extends ValidationSupportChain {
|
||||
|
||||
private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport();
|
||||
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportR5")
|
||||
public ca.uhn.fhir.jpa.dao.r5.IJpaValidationSupportR5 myJpaValidationSupportR5;
|
||||
|
||||
@Autowired
|
||||
private IHapiTerminologySvcR5 myTerminologyService;
|
||||
|
||||
public JpaValidationSupportChainR5() {
|
||||
super();
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
myDefaultProfileValidationSupport.flush();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
if (theClass.equals(StructureDefinition.class)) {
|
||||
return (T) fetchStructureDefinition(theContext, theUri);
|
||||
}
|
||||
return super.fetchResource(theContext, theClass, theUri);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
StructureDefinition retVal = super.fetchStructureDefinition(theCtx, theUrl);
|
||||
if (retVal != null && !retVal.hasSnapshot()) {
|
||||
retVal = generateSnapshot(retVal, theUrl, null, null);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
addValidationSupport(myDefaultProfileValidationSupport);
|
||||
addValidationSupport(myJpaValidationSupportR5);
|
||||
addValidationSupport(myTerminologyService);
|
||||
addValidationSupport(new SnapshotGeneratingValidationSupport(myFhirContext, this));
|
||||
}
|
||||
|
||||
@PreDestroy
|
||||
public void preDestroy() {
|
||||
flush();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,176 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc;
|
||||
import ca.uhn.fhir.jpa.binstore.MemoryBinaryStorageSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.CircularQueueCaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.util.CurrentThreadCaptureQueriesListener;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import net.ttddyy.dsproxy.listener.SingleQueryCountHolder;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
import java.sql.Connection;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
@Configuration
|
||||
@Import(TestJPAConfig.class)
|
||||
@EnableTransactionManagement()
|
||||
public class TestR5Config extends BaseJavaConfigR5 {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestR5Config.class);
|
||||
public static Integer ourMaxThreads;
|
||||
|
||||
static {
|
||||
/*
|
||||
* We use a randomized number of maximum threads in order to try
|
||||
* and catch any potential deadlocks caused by database connection
|
||||
* starvation
|
||||
*/
|
||||
if (ourMaxThreads == null) {
|
||||
ourMaxThreads = (int) (Math.random() * 6.0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private Environment myEnvironment;
|
||||
|
||||
private Exception myLastStackTrace;
|
||||
|
||||
@Bean
|
||||
public CircularQueueCaptureQueriesListener captureQueriesListener() {
|
||||
return new CircularQueueCaptureQueriesListener();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource() {
|
||||
|
||||
|
||||
@Override
|
||||
public Connection getConnection() {
|
||||
ConnectionWrapper retVal;
|
||||
try {
|
||||
retVal = new ConnectionWrapper(super.getConnection());
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Exceeded maximum wait for connection", e);
|
||||
logGetConnectionStackTrace();
|
||||
fail("Exceeded maximum wait for connection: " + e.toString());
|
||||
retVal = null;
|
||||
}
|
||||
|
||||
try {
|
||||
throw new Exception();
|
||||
} catch (Exception e) {
|
||||
myLastStackTrace = e;
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void logGetConnectionStackTrace() {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Last connection request stack trace:");
|
||||
for (StackTraceElement next : myLastStackTrace.getStackTrace()) {
|
||||
b.append("\n ");
|
||||
b.append(next.getClassName());
|
||||
b.append(".");
|
||||
b.append(next.getMethodName());
|
||||
b.append("(");
|
||||
b.append(next.getFileName());
|
||||
b.append(":");
|
||||
b.append(next.getLineNumber());
|
||||
b.append(")");
|
||||
}
|
||||
ourLog.info(b.toString());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
retVal.setDriver(new org.h2.Driver());
|
||||
retVal.setUrl("jdbc:h2:mem:testdb_r5");
|
||||
retVal.setMaxWaitMillis(10000);
|
||||
retVal.setUsername("");
|
||||
retVal.setPassword("");
|
||||
retVal.setMaxTotal(ourMaxThreads);
|
||||
|
||||
DataSource dataSource = ProxyDataSourceBuilder
|
||||
.create(retVal)
|
||||
// .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
|
||||
// .logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
|
||||
// .countQuery(new ThreadQueryCountHolder())
|
||||
.beforeQuery(new BlockLargeNumbersOfParamsListener())
|
||||
.afterQuery(captureQueriesListener())
|
||||
.afterQuery(new CurrentThreadCaptureQueriesListener())
|
||||
.countQuery(singleQueryCountHolder())
|
||||
.build();
|
||||
|
||||
return dataSource;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public SingleQueryCountHolder singleQueryCountHolder() {
|
||||
return new SingleQueryCountHolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
|
||||
retVal.setPersistenceUnitName("PU_HapiFhirJpaR5");
|
||||
retVal.setDataSource(dataSource());
|
||||
retVal.setJpaProperties(jpaProperties());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
extraProperties.put("hibernate.format_sql", "false");
|
||||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.dialect", H2Dialect.class.getName());
|
||||
extraProperties.put("hibernate.search.model_mapping", ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "local-heap");
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
extraProperties.put("hibernate.search.autoregister_listeners", "true");
|
||||
|
||||
return extraProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidatorR5());
|
||||
|
||||
return requestValidator;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public IBinaryStorageSvc binaryStorage() {
|
||||
return new MemoryBinaryStorageSvcImpl();
|
||||
}
|
||||
|
||||
public static int getMaxThreads() {
|
||||
return ourMaxThreads;
|
||||
}
|
||||
|
||||
}
|
|
@ -24,7 +24,7 @@ public class FhirResourceDaoDstu3StructureDefinitionTest extends BaseJpaDstu3Tes
|
|||
StructureDefinition sd = loadResourceFromClasspath(StructureDefinition.class, "/dstu3/profile-differential-patient-dstu3.json");
|
||||
assertEquals(0, sd.getSnapshot().getElement().size());
|
||||
|
||||
StructureDefinition output = myStructureDefinitionDao.generateSnapshot(sd, "http://foo", "THE BEST PROFILE");
|
||||
StructureDefinition output = myStructureDefinitionDao.generateSnapshot(sd, "http://foo", null, "THE BEST PROFILE");
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(54, output.getSnapshot().getElement().size());
|
||||
|
|
|
@ -16,7 +16,7 @@ import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
|||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Ignore;
|
||||
|
@ -84,14 +84,14 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
|||
@After
|
||||
public void after() {
|
||||
FhirInstanceValidator val = AopTestUtils.getTargetObject(myValidatorModule);
|
||||
val.setBestPracticeWarningLevel(IResourceValidator.BestPracticeWarningLevel.Warning);
|
||||
val.setBestPracticeWarningLevel(org.hl7.fhir.r5.utils.IResourceValidator.BestPracticeWarningLevel.Warning);
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testValidateWithCanonicalReference() {
|
||||
FhirInstanceValidator val = AopTestUtils.getTargetObject(myValidatorModule);
|
||||
IResourceValidator.BestPracticeWarningLevel a = IResourceValidator.BestPracticeWarningLevel.Ignore;
|
||||
org.hl7.fhir.r5.utils.IResourceValidator.BestPracticeWarningLevel a = IResourceValidator.BestPracticeWarningLevel.Ignore;
|
||||
val.setBestPracticeWarningLevel(a);
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
|
|
|
@ -48,7 +48,7 @@ import org.hl7.fhir.r4.model.ConceptMap.ConceptMapGroupComponent;
|
|||
import org.hl7.fhir.r4.model.ConceptMap.SourceElementComponent;
|
||||
import org.hl7.fhir.r4.model.ConceptMap.TargetElementComponent;
|
||||
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
|
|
|
@ -1,25 +1,12 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
|
@ -40,7 +27,7 @@ public class FhirResourceDaoR4StructureDefinitionTest extends BaseJpaR4Test {
|
|||
StructureDefinition sd = loadResourceFromClasspath(StructureDefinition.class, "/r4/profile-differential-patient-r4.json");
|
||||
assertEquals(0, sd.getSnapshot().getElement().size());
|
||||
|
||||
StructureDefinition output = myStructureDefinitionDao.generateSnapshot(sd, "http://foo", "THE BEST PROFILE");
|
||||
StructureDefinition output = myStructureDefinitionDao.generateSnapshot(sd, "http://foo", null, "THE BEST PROFILE");
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(51, output.getSnapshot().getElement().size());
|
||||
|
|
|
@ -18,7 +18,7 @@ import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
|||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Ignore;
|
||||
|
@ -184,7 +184,7 @@ public class FhirResourceDaoR4ValidateTest extends BaseJpaR4Test {
|
|||
@Test
|
||||
public void testValidateWithCanonicalReference() {
|
||||
FhirInstanceValidator val = AopTestUtils.getTargetObject(myValidatorModule);
|
||||
val.setBestPracticeWarningLevel(IResourceValidator.BestPracticeWarningLevel.Ignore);
|
||||
val.setBestPracticeWarningLevel(org.hl7.fhir.r5.utils.IResourceValidator.BestPracticeWarningLevel.Ignore);
|
||||
|
||||
ValueSet vs = new ValueSet();
|
||||
vs.setId("MYVS");
|
||||
|
|
|
@ -0,0 +1,554 @@
|
|||
package ca.uhn.fhir.jpa.dao.r5;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||
import ca.uhn.fhir.jpa.binstore.BinaryAccessProvider;
|
||||
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
||||
import ca.uhn.fhir.jpa.config.TestR5Config;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
|
||||
import ca.uhn.fhir.jpa.interceptor.PerformanceTracingLoggingInterceptor;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||
import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.BaseSearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR5;
|
||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR5;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.BasePagingProvider;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hibernate.search.jpa.FullTextEntityManager;
|
||||
import org.hibernate.search.jpa.Search;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.hapi.validation.FhirInstanceValidator;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.ConceptMap.ConceptMapGroupComponent;
|
||||
import org.hl7.fhir.r5.model.ConceptMap.SourceElementComponent;
|
||||
import org.hl7.fhir.r5.model.ConceptMap.TargetElementComponent;
|
||||
import org.hl7.fhir.r5.model.Enumerations.ConceptMapEquivalence;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.persistence.EntityManager;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = {TestR5Config.class})
|
||||
public abstract class BaseJpaR5Test extends BaseJpaTest {
|
||||
private static JpaValidationSupportChainR5 ourJpaValidationSupportChainR5;
|
||||
private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myResourceCountsCache")
|
||||
protected ResourceCountCache myResourceCountsCache;
|
||||
@Autowired
|
||||
protected IResourceLinkDao myResourceLinkDao;
|
||||
@Autowired
|
||||
protected ISearchParamPresentDao mySearchParamPresentDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedSearchParamStringDao myResourceIndexedSearchParamStringDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedSearchParamTokenDao myResourceIndexedSearchParamTokenDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedSearchParamQuantityDao myResourceIndexedSearchParamQuantityDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedSearchParamDateDao myResourceIndexedSearchParamDateDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||
@Autowired
|
||||
@Qualifier("myAllergyIntoleranceDaoR5")
|
||||
protected IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
||||
@Autowired
|
||||
protected BinaryAccessProvider myBinaryAccessProvider;
|
||||
@Autowired
|
||||
protected BinaryStorageInterceptor myBinaryStorageInterceptor;
|
||||
@Autowired
|
||||
protected ApplicationContext myAppCtx;
|
||||
@Autowired
|
||||
@Qualifier("myAppointmentDaoR5")
|
||||
protected IFhirResourceDao<Appointment> myAppointmentDao;
|
||||
@Autowired
|
||||
@Qualifier("myAuditEventDaoR5")
|
||||
protected IFhirResourceDao<AuditEvent> myAuditEventDao;
|
||||
@Autowired
|
||||
@Qualifier("myBundleDaoR5")
|
||||
protected IFhirResourceDao<Bundle> myBundleDao;
|
||||
@Autowired
|
||||
@Qualifier("myCommunicationDaoR5")
|
||||
protected IFhirResourceDao<Communication> myCommunicationDao;
|
||||
@Autowired
|
||||
@Qualifier("myCommunicationRequestDaoR5")
|
||||
protected IFhirResourceDao<CommunicationRequest> myCommunicationRequestDao;
|
||||
@Autowired
|
||||
@Qualifier("myCarePlanDaoR5")
|
||||
protected IFhirResourceDao<CarePlan> myCarePlanDao;
|
||||
@Autowired
|
||||
@Qualifier("myCodeSystemDaoR5")
|
||||
protected IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
|
||||
@Autowired
|
||||
protected ITermCodeSystemDao myTermCodeSystemDao;
|
||||
@Autowired
|
||||
protected ITermConceptParentChildLinkDao myTermConceptParentChildLinkDao;
|
||||
@Autowired
|
||||
protected ITermCodeSystemVersionDao myTermCodeSystemVersionDao;
|
||||
@Autowired
|
||||
@Qualifier("myCompartmentDefinitionDaoR5")
|
||||
protected IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myConceptMapDaoR5")
|
||||
protected IFhirResourceDaoConceptMap<ConceptMap> myConceptMapDao;
|
||||
@Autowired
|
||||
protected ITermConceptDao myTermConceptDao;
|
||||
@Autowired
|
||||
protected ITermConceptDesignationDao myTermConceptDesignationDao;
|
||||
@Autowired
|
||||
@Qualifier("myConditionDaoR5")
|
||||
protected IFhirResourceDao<Condition> myConditionDao;
|
||||
@Autowired
|
||||
protected DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
protected ModelConfig myModelConfig;
|
||||
@Autowired
|
||||
@Qualifier("myDeviceDaoR5")
|
||||
protected IFhirResourceDao<Device> myDeviceDao;
|
||||
@Autowired
|
||||
@Qualifier("myDiagnosticReportDaoR5")
|
||||
protected IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
|
||||
@Autowired
|
||||
@Qualifier("myEncounterDaoR5")
|
||||
protected IFhirResourceDao<Encounter> myEncounterDao;
|
||||
// @PersistenceContext()
|
||||
@Autowired
|
||||
protected EntityManager myEntityManager;
|
||||
@Autowired
|
||||
protected FhirContext myFhirCtx;
|
||||
@Autowired
|
||||
@Qualifier("myGroupDaoR5")
|
||||
protected IFhirResourceDao<Group> myGroupDao;
|
||||
@Autowired
|
||||
@Qualifier("myMolecularSequenceDaoR5")
|
||||
protected IFhirResourceDao<MolecularSequence> myMolecularSequenceDao;
|
||||
@Autowired
|
||||
@Qualifier("myImmunizationDaoR5")
|
||||
protected IFhirResourceDao<Immunization> myImmunizationDao;
|
||||
@Autowired
|
||||
@Qualifier("myImmunizationRecommendationDaoR5")
|
||||
protected IFhirResourceDao<ImmunizationRecommendation> myImmunizationRecommendationDao;
|
||||
@Autowired
|
||||
@Qualifier("myRiskAssessmentDaoR5")
|
||||
protected IFhirResourceDao<RiskAssessment> myRiskAssessmentDao;
|
||||
@Autowired
|
||||
protected IInterceptorService myInterceptorRegistry;
|
||||
@Autowired
|
||||
@Qualifier("myLocationDaoR5")
|
||||
protected IFhirResourceDao<Location> myLocationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMediaDaoR5")
|
||||
protected IFhirResourceDao<Media> myMediaDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationAdministrationDaoR5")
|
||||
protected IFhirResourceDao<MedicationAdministration> myMedicationAdministrationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationDaoR5")
|
||||
protected IFhirResourceDao<Medication> myMedicationDao;
|
||||
@Autowired
|
||||
@Qualifier("myMedicationRequestDaoR5")
|
||||
protected IFhirResourceDao<MedicationRequest> myMedicationRequestDao;
|
||||
@Autowired
|
||||
@Qualifier("myProcedureDaoR5")
|
||||
protected IFhirResourceDao<Procedure> myProcedureDao;
|
||||
@Autowired
|
||||
@Qualifier("myNamingSystemDaoR5")
|
||||
protected IFhirResourceDao<NamingSystem> myNamingSystemDao;
|
||||
@Autowired
|
||||
@Qualifier("myChargeItemDaoR5")
|
||||
protected IFhirResourceDao<ChargeItem> myChargeItemDao;
|
||||
@Autowired
|
||||
@Qualifier("myObservationDaoR5")
|
||||
protected IFhirResourceDao<Observation> myObservationDao;
|
||||
@Autowired
|
||||
@Qualifier("myOperationDefinitionDaoR5")
|
||||
protected IFhirResourceDao<OperationDefinition> myOperationDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myOrganizationDaoR5")
|
||||
protected IFhirResourceDao<Organization> myOrganizationDao;
|
||||
@Autowired
|
||||
protected DatabaseBackedPagingProvider myPagingProvider;
|
||||
@Autowired
|
||||
@Qualifier("myBinaryDaoR5")
|
||||
protected IFhirResourceDao<Binary> myBinaryDao;
|
||||
@Autowired
|
||||
@Qualifier("myPatientDaoR5")
|
||||
protected IFhirResourceDaoPatient<Patient> myPatientDao;
|
||||
@Autowired
|
||||
protected IResourceTableDao myResourceTableDao;
|
||||
@Autowired
|
||||
protected IResourceHistoryTableDao myResourceHistoryTableDao;
|
||||
@Autowired
|
||||
protected IForcedIdDao myForcedIdDao;
|
||||
@Autowired
|
||||
@Qualifier("myCoverageDaoR5")
|
||||
protected IFhirResourceDao<Coverage> myCoverageDao;
|
||||
@Autowired
|
||||
@Qualifier("myPractitionerDaoR5")
|
||||
protected IFhirResourceDao<Practitioner> myPractitionerDao;
|
||||
@Autowired
|
||||
@Qualifier("myServiceRequestDaoR5")
|
||||
protected IFhirResourceDao<ServiceRequest> myServiceRequestDao;
|
||||
@Autowired
|
||||
@Qualifier("myQuestionnaireDaoR5")
|
||||
protected IFhirResourceDao<Questionnaire> myQuestionnaireDao;
|
||||
@Autowired
|
||||
@Qualifier("myQuestionnaireResponseDaoR5")
|
||||
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
||||
@Autowired
|
||||
@Qualifier("myResourceProvidersR5")
|
||||
protected ResourceProviderFactory myResourceProviders;
|
||||
@Autowired
|
||||
protected IResourceTagDao myResourceTagDao;
|
||||
@Autowired
|
||||
protected ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
@Autowired(required = false)
|
||||
protected IFulltextSearchSvc mySearchDao;
|
||||
@Autowired
|
||||
protected ISearchDao mySearchEntityDao;
|
||||
@Autowired
|
||||
protected ISearchResultDao mySearchResultDao;
|
||||
@Autowired
|
||||
protected ISearchIncludeDao mySearchIncludeDao;
|
||||
@Autowired
|
||||
protected IResourceReindexJobDao myResourceReindexJobDao;
|
||||
@Autowired
|
||||
@Qualifier("mySearchParameterDaoR5")
|
||||
protected IFhirResourceDao<SearchParameter> mySearchParameterDao;
|
||||
@Autowired
|
||||
protected BaseSearchParamRegistry mySearchParamRegistry;
|
||||
@Autowired
|
||||
protected IStaleSearchDeletingSvc myStaleSearchDeletingSvc;
|
||||
@Autowired
|
||||
@Qualifier("myStructureDefinitionDaoR5")
|
||||
protected IFhirResourceDaoStructureDefinition<StructureDefinition> myStructureDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myConsentDaoR5")
|
||||
protected IFhirResourceDao<Consent> myConsentDao;
|
||||
@Autowired
|
||||
@Qualifier("mySubscriptionDaoR5")
|
||||
protected IFhirResourceDaoSubscription<Subscription> mySubscriptionDao;
|
||||
@Autowired
|
||||
@Qualifier("mySubstanceDaoR5")
|
||||
protected IFhirResourceDao<Substance> mySubstanceDao;
|
||||
@Autowired
|
||||
@Qualifier("mySystemDaoR5")
|
||||
protected IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||
@Autowired
|
||||
protected IResourceReindexingSvc myResourceReindexingSvc;
|
||||
@Autowired
|
||||
@Qualifier("mySystemProviderR5")
|
||||
protected JpaSystemProviderR5 mySystemProvider;
|
||||
@Autowired
|
||||
protected ITagDefinitionDao myTagDefinitionDao;
|
||||
@Autowired
|
||||
@Qualifier("myTaskDaoR5")
|
||||
protected IFhirResourceDao<Task> myTaskDao;
|
||||
@Autowired
|
||||
protected IHapiTerminologySvcR5 myTermSvc;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myTransactionMgr;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myTxManager;
|
||||
@Autowired
|
||||
@Qualifier("myJpaValidationSupportChainR5")
|
||||
protected IValidationSupport myValidationSupport;
|
||||
@Autowired
|
||||
@Qualifier("myValueSetDaoR5")
|
||||
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
|
||||
@Autowired
|
||||
protected ITermValueSetDao myTermValueSetDao;
|
||||
@Autowired
|
||||
protected ITermValueSetConceptDao myTermValueSetConceptDao;
|
||||
@Autowired
|
||||
protected ITermValueSetConceptDesignationDao myTermValueSetConceptDesignationDao;
|
||||
@Autowired
|
||||
protected ITermConceptMapDao myTermConceptMapDao;
|
||||
@Autowired
|
||||
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
|
||||
@Autowired
|
||||
protected ICacheWarmingSvc myCacheWarmingSvc;
|
||||
@Autowired
|
||||
protected SubscriptionRegistry mySubscriptionRegistry;
|
||||
protected IServerInterceptor myInterceptor;
|
||||
@Autowired
|
||||
private JpaValidationSupportChainR5 myJpaValidationSupportChainR5;
|
||||
private PerformanceTracingLoggingInterceptor myPerformanceTracingLoggingInterceptor;
|
||||
private List<Object> mySystemInterceptors;
|
||||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
|
||||
@After()
|
||||
public void afterCleanupDao() {
|
||||
myDaoConfig.setExpireSearchResults(new DaoConfig().isExpireSearchResults());
|
||||
myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete());
|
||||
myDaoConfig.setExpireSearchResultsAfterMillis(new DaoConfig().getExpireSearchResultsAfterMillis());
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setSuppressUpdatesWithNoChange(new DaoConfig().isSuppressUpdatesWithNoChange());
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
|
||||
myPagingProvider.setDefaultPageSize(BasePagingProvider.DEFAULT_DEFAULT_PAGE_SIZE);
|
||||
myPagingProvider.setMaximumPageSize(BasePagingProvider.DEFAULT_MAX_PAGE_SIZE);
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterResetInterceptors() {
|
||||
myInterceptorRegistry.unregisterAllInterceptors();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterClearTerminologyCaches() {
|
||||
BaseHapiTerminologySvcImpl baseHapiTerminologySvc = AopTestUtils.getTargetObject(myTermSvc);
|
||||
baseHapiTerminologySvc.clearTranslationCache();
|
||||
baseHapiTerminologySvc.clearTranslationWithReverseCache();
|
||||
baseHapiTerminologySvc.clearDeferred();
|
||||
BaseHapiTerminologySvcImpl.clearOurLastResultsFromTranslationCache();
|
||||
BaseHapiTerminologySvcImpl.clearOurLastResultsFromTranslationWithReverseCache();
|
||||
}
|
||||
|
||||
@After()
|
||||
public void afterGrabCaches() {
|
||||
ourValueSetDao = myValueSetDao;
|
||||
ourJpaValidationSupportChainR5 = myJpaValidationSupportChainR5;
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeCreateInterceptor() {
|
||||
mySystemInterceptors = myInterceptorRegistry.getAllRegisteredInterceptors();
|
||||
|
||||
myInterceptor = mock(IServerInterceptor.class);
|
||||
|
||||
myPerformanceTracingLoggingInterceptor = new PerformanceTracingLoggingInterceptor();
|
||||
myInterceptorRegistry.registerInterceptor(myPerformanceTracingLoggingInterceptor);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeFlushFT() {
|
||||
runInTransaction(() -> {
|
||||
FullTextEntityManager ftem = Search.getFullTextEntityManager(myEntityManager);
|
||||
ftem.purgeAll(ResourceTable.class);
|
||||
ftem.purgeAll(ResourceIndexedSearchParamString.class);
|
||||
ftem.flushToIndexes();
|
||||
});
|
||||
|
||||
myDaoConfig.setSchedulingDisabled(true);
|
||||
myDaoConfig.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
}
|
||||
|
||||
@Before
|
||||
@Transactional()
|
||||
public void beforePurgeDatabase() {
|
||||
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeResetConfig() {
|
||||
myDaoConfig.setHardSearchLimit(1000);
|
||||
myDaoConfig.setHardTagListLimit(1000);
|
||||
myDaoConfig.setIncludeLimit(2000);
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FhirContext getContext() {
|
||||
return myFhirCtx;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected PlatformTransactionManager getTxManager() {
|
||||
return myTxManager;
|
||||
}
|
||||
|
||||
protected <T extends IBaseResource> T loadResourceFromClasspath(Class<T> type, String resourceName) throws IOException {
|
||||
InputStream stream = FhirResourceDaoDstu2SearchNoFtTest.class.getResourceAsStream(resourceName);
|
||||
if (stream == null) {
|
||||
fail("Unable to load resource: " + resourceName);
|
||||
}
|
||||
String string = IOUtils.toString(stream, "UTF-8");
|
||||
IParser newJsonParser = EncodingEnum.detectEncodingNoDefault(string).newParser(myFhirCtx);
|
||||
return newJsonParser.parseResource(type, string);
|
||||
}
|
||||
|
||||
protected void validate(IBaseResource theResource) {
|
||||
FhirValidator validatorModule = myFhirCtx.newValidator();
|
||||
FhirInstanceValidator instanceValidator = new FhirInstanceValidator(myValidationSupport);
|
||||
instanceValidator.setBestPracticeWarningLevel(IResourceValidator.BestPracticeWarningLevel.Ignore);
|
||||
validatorModule.registerValidatorModule(instanceValidator);
|
||||
ValidationResult result = validatorModule.validateWithResult(theResource);
|
||||
if (!result.isSuccessful()) {
|
||||
fail(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected void upload(String theClasspath) throws IOException {
|
||||
String resource = loadResource(theClasspath);
|
||||
IParser parser = EncodingEnum.detectEncoding(resource).newParser(myFhirCtx);
|
||||
IBaseResource resourceParsed = parser.parseResource(resource);
|
||||
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceParsed.getIdElement().getResourceType());
|
||||
dao.update(resourceParsed);
|
||||
}
|
||||
|
||||
protected String loadResource(String theClasspath) throws IOException {
|
||||
return IOUtils.toString(BaseJpaR5Test.class.getResourceAsStream(theClasspath), Charsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContextBaseJpaR5Test() {
|
||||
ourValueSetDao.purgeCaches();
|
||||
ourJpaValidationSupportChainR5.flush();
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a single {@link ConceptMap} entity that includes:
|
||||
* <br>
|
||||
* <ul>
|
||||
* <li>
|
||||
* One group with two elements, each identifying one target apiece.
|
||||
* </li>
|
||||
* <li>
|
||||
* One group with one element, identifying two targets.
|
||||
* </li>
|
||||
* <li>
|
||||
* One group with one element, identifying a target that also appears
|
||||
* in the first element of the first group.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </br>
|
||||
* The first two groups identify the same source code system and different target code systems.
|
||||
* </br>
|
||||
* The first two groups also include an element with the same source code.
|
||||
*
|
||||
* @return A {@link ConceptMap} entity for testing.
|
||||
*/
|
||||
public static ConceptMap createConceptMap() {
|
||||
ConceptMap conceptMap = new ConceptMap();
|
||||
conceptMap.setUrl(CM_URL);
|
||||
|
||||
conceptMap.setSource(new UriType(VS_URL));
|
||||
conceptMap.setTarget(new UriType(VS_URL_2));
|
||||
|
||||
ConceptMapGroupComponent group = conceptMap.addGroup();
|
||||
group.setSource(CS_URL);
|
||||
group.setSourceVersion("Version 1");
|
||||
group.setTarget(CS_URL_2);
|
||||
group.setTargetVersion("Version 2");
|
||||
|
||||
SourceElementComponent element = group.addElement();
|
||||
element.setCode("12345");
|
||||
element.setDisplay("Source Code 12345");
|
||||
|
||||
TargetElementComponent target = element.addTarget();
|
||||
target.setCode("34567");
|
||||
target.setDisplay("Target Code 34567");
|
||||
target.setEquivalence(ConceptMapEquivalence.EQUAL);
|
||||
|
||||
element = group.addElement();
|
||||
element.setCode("23456");
|
||||
element.setDisplay("Source Code 23456");
|
||||
|
||||
target = element.addTarget();
|
||||
target.setCode("45678");
|
||||
target.setDisplay("Target Code 45678");
|
||||
target.setEquivalence(ConceptMapEquivalence.WIDER);
|
||||
|
||||
// Add a duplicate
|
||||
target = element.addTarget();
|
||||
target.setCode("45678");
|
||||
target.setDisplay("Target Code 45678");
|
||||
target.setEquivalence(ConceptMapEquivalence.WIDER);
|
||||
|
||||
group = conceptMap.addGroup();
|
||||
group.setSource(CS_URL);
|
||||
group.setSourceVersion("Version 3");
|
||||
group.setTarget(CS_URL_3);
|
||||
group.setTargetVersion("Version 4");
|
||||
|
||||
element = group.addElement();
|
||||
element.setCode("12345");
|
||||
element.setDisplay("Source Code 12345");
|
||||
|
||||
target = element.addTarget();
|
||||
target.setCode("56789");
|
||||
target.setDisplay("Target Code 56789");
|
||||
target.setEquivalence(ConceptMapEquivalence.EQUAL);
|
||||
|
||||
target = element.addTarget();
|
||||
target.setCode("67890");
|
||||
target.setDisplay("Target Code 67890");
|
||||
target.setEquivalence(ConceptMapEquivalence.WIDER);
|
||||
|
||||
group = conceptMap.addGroup();
|
||||
group.setSource(CS_URL_4);
|
||||
group.setSourceVersion("Version 5");
|
||||
group.setTarget(CS_URL_2);
|
||||
group.setTargetVersion("Version 2");
|
||||
|
||||
element = group.addElement();
|
||||
element.setCode("78901");
|
||||
element.setDisplay("Source Code 78901");
|
||||
|
||||
target = element.addTarget();
|
||||
target.setCode("34567");
|
||||
target.setDisplay("Target Code 34567");
|
||||
target.setEquivalence(ConceptMapEquivalence.NARROWER);
|
||||
|
||||
return conceptMap;
|
||||
}
|
||||
|
||||
public static String toSearchUuidFromLinkNext(Bundle theBundle) {
|
||||
String linkNext = theBundle.getLink("next").getUrl();
|
||||
linkNext = linkNext.substring(linkNext.indexOf('?'));
|
||||
Map<String, String[]> params = UrlUtil.parseQueryString(linkNext);
|
||||
String[] uuidParams = params.get(Constants.PARAM_PAGINGACTION);
|
||||
String uuid = uuidParams[0];
|
||||
return uuid;
|
||||
}
|
||||
|
||||
}
|
|
@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
|
|||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
|
||||
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryDstu3;
|
||||
|
@ -61,9 +62,8 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
protected static SearchParamRegistryDstu3 ourSearchParamRegistry;
|
||||
protected static DatabaseBackedPagingProvider ourPagingProvider;
|
||||
protected static ISearchDao mySearchEntityDao;
|
||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
protected static ISearchCoordinatorSvc ourSearchCoordinatorSvc;
|
||||
private static Server ourServer;
|
||||
private TerminologyUploaderProviderDstu3 myTerminologyUploaderProvider;
|
||||
protected static SubscriptionTriggeringProvider ourSubscriptionTriggeringProvider;
|
||||
|
||||
public BaseResourceProviderDstu3Test() {
|
||||
|
@ -91,8 +91,8 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
ourRestServer.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderDstu3.class);
|
||||
ourRestServer.registerProviders(mySystemProvider, myTerminologyUploaderProvider);
|
||||
TerminologyUploaderProvider terminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
|
||||
ourRestServer.registerProviders(mySystemProvider, terminologyUploaderProvider);
|
||||
|
||||
SubscriptionTriggeringProvider subscriptionTriggeringProvider = myAppCtx.getBean(SubscriptionTriggeringProvider.class);
|
||||
ourRestServer.registerProvider(subscriptionTriggeringProvider);
|
||||
|
@ -102,6 +102,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
ourRestServer.setServerConformanceProvider(confProvider);
|
||||
|
||||
ourPagingProvider = myAppCtx.getBean(DatabaseBackedPagingProvider.class);
|
||||
ourSearchCoordinatorSvc = myAppCtx.getBean(ISearchCoordinatorSvc.class);
|
||||
|
||||
Server server = new Server(0);
|
||||
|
||||
|
@ -151,7 +152,7 @@ public abstract class BaseResourceProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(subsServletHolder.getServlet().getServletConfig().getServletContext());
|
||||
myValidationSupport = wac.getBean(JpaValidationSupportChainDstu3.class);
|
||||
mySearchCoordinatorSvc = wac.getBean(ISearchCoordinatorSvc.class);
|
||||
ourSearchCoordinatorSvc = wac.getBean(ISearchCoordinatorSvc.class);
|
||||
mySearchEntityDao = wac.getBean(ISearchDao.class);
|
||||
ourSearchParamRegistry = wac.getBean(SearchParamRegistryDstu3.class);
|
||||
ourSubscriptionTriggeringProvider = wac.getBean(SubscriptionTriggeringProvider.class);
|
||||
|
|
|
@ -162,12 +162,9 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void beforeDisableResultReuse() {
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||
mySearchCoordinatorSvcRaw = AopTestUtils.getTargetObject(mySearchCoordinatorSvc);
|
||||
mySearchCoordinatorSvcRaw = AopTestUtils.getTargetObject(ourSearchCoordinatorSvc);
|
||||
}
|
||||
|
||||
private void checkParamMissing(String paramName) throws IOException {
|
||||
|
@ -4043,7 +4040,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
assertEquals(412, response.getStatusLine().getStatusCode());
|
||||
assertThat(resp, not(containsString("Resource has no id")));
|
||||
assertThat(resp,
|
||||
stringContainsInOrder(">ERROR<", "[Patient.contact]", "<pre>SHALL at least contain a contact's details or a reference to an organization", "<issue><severity value=\"error\"/>"));
|
||||
stringContainsInOrder(">ERROR<", "[Patient.contact[0]]", "<pre>SHALL at least contain a contact's details or a reference to an organization", "<issue><severity value=\"error\"/>"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
response.close();
|
||||
|
|
|
@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
|
|||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryR4;
|
||||
|
@ -20,6 +21,7 @@ import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
|||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
|
@ -52,8 +54,6 @@ import java.util.concurrent.TimeUnit;
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
|
||||
public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
||||
|
||||
protected static JpaValidationSupportChainR4 myValidationSupport;
|
||||
|
@ -70,7 +70,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
protected static Server ourServer;
|
||||
protected IGenericClient ourClient;
|
||||
ResourceCountCache ourResourceCountsCache;
|
||||
private TerminologyUploaderProviderR4 myTerminologyUploaderProvider;
|
||||
private TerminologyUploaderProvider myTerminologyUploaderProvider;
|
||||
private Object ourGraphQLProvider;
|
||||
private boolean ourRestHookSubscriptionInterceptorRequested;
|
||||
|
||||
|
@ -104,7 +104,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
ourRestServer.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProviderR4.class);
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
|
||||
ourGraphQLProvider = myAppCtx.getBean("myGraphQLProvider");
|
||||
myDaoRegistry = myAppCtx.getBean(DaoRegistry.class);
|
||||
|
||||
|
|
|
@ -5179,7 +5179,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
assertEquals(412, response.getStatusLine().getStatusCode());
|
||||
assertThat(resp, not(containsString("Resource has no id")));
|
||||
assertThat(resp,
|
||||
stringContainsInOrder(">ERROR<", "[Patient.contact]", "<pre>SHALL at least contain a contact's details or a reference to an organization", "<issue><severity value=\"error\"/>"));
|
||||
stringContainsInOrder(">ERROR<", "[Patient.contact[0]]", "<pre>SHALL at least contain a contact's details or a reference to an organization", "<issue><severity value=\"error\"/>"));
|
||||
} finally {
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
response.close();
|
||||
|
|
|
@ -0,0 +1,292 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.WebsocketDispatcherConfig;
|
||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
||||
import ca.uhn.fhir.jpa.dao.r5.BaseJpaR5Test;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryR5;
|
||||
import ca.uhn.fhir.jpa.subscription.SubscriptionMatcherInterceptor;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionLoader;
|
||||
import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR5;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletContextHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r5.model.Parameters;
|
||||
import org.hl7.fhir.r5.model.Parameters.ParametersParameterComponent;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.context.ContextLoader;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.context.support.GenericWebApplicationContext;
|
||||
import org.springframework.web.context.support.WebApplicationContextUtils;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public abstract class BaseResourceProviderR5Test extends BaseJpaR5Test {
|
||||
|
||||
protected static JpaValidationSupportChainR5 myValidationSupport;
|
||||
protected static CloseableHttpClient ourHttpClient;
|
||||
protected static int ourPort;
|
||||
protected static RestfulServer ourRestServer;
|
||||
protected static String ourServerBase;
|
||||
protected static SearchParamRegistryR5 ourSearchParamRegistry;
|
||||
private static DatabaseBackedPagingProvider ourPagingProvider;
|
||||
protected static ISearchDao mySearchEntityDao;
|
||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
private static GenericWebApplicationContext ourWebApplicationContext;
|
||||
private static SubscriptionMatcherInterceptor ourSubscriptionMatcherInterceptor;
|
||||
protected static Server ourServer;
|
||||
protected IGenericClient ourClient;
|
||||
ResourceCountCache ourResourceCountsCache;
|
||||
private Object ourGraphQLProvider;
|
||||
private boolean ourRestHookSubscriptionInterceptorRequested;
|
||||
|
||||
@Autowired
|
||||
protected SubscriptionLoader mySubscriptionLoader;
|
||||
@Autowired
|
||||
protected DaoRegistry myDaoRegistry;
|
||||
private TerminologyUploaderProvider myTerminologyUploaderProvider;
|
||||
|
||||
public BaseResourceProviderR5Test() {
|
||||
super();
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.ONCE);
|
||||
ourRestServer.getInterceptorService().unregisterAllInterceptors();
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "rawtypes"})
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
myFhirCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
myFhirCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
|
||||
if (ourServer == null) {
|
||||
ourRestServer = new RestfulServer(myFhirCtx);
|
||||
ourRestServer.registerProviders(myResourceProviders.createProviders());
|
||||
ourRestServer.registerProvider(myBinaryAccessProvider);
|
||||
ourRestServer.getInterceptorService().registerInterceptor(myBinaryStorageInterceptor);
|
||||
ourRestServer.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
ourRestServer.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||
|
||||
myTerminologyUploaderProvider = myAppCtx.getBean(TerminologyUploaderProvider.class);
|
||||
myDaoRegistry = myAppCtx.getBean(DaoRegistry.class);
|
||||
ourRestServer.registerProviders(mySystemProvider, myTerminologyUploaderProvider);
|
||||
|
||||
// ourGraphQLProvider = myAppCtx.getBean("myGraphQLProvider");
|
||||
// ourRestServer.registerProvider(ourGraphQLProvider);
|
||||
|
||||
JpaConformanceProviderR5 confProvider = new JpaConformanceProviderR5(ourRestServer, mySystemDao, myDaoConfig);
|
||||
confProvider.setImplementationDescription("THIS IS THE DESC");
|
||||
ourRestServer.setServerConformanceProvider(confProvider);
|
||||
|
||||
ourPagingProvider = myAppCtx.getBean(DatabaseBackedPagingProvider.class);
|
||||
ourResourceCountsCache = (ResourceCountCache) myAppCtx.getBean("myResourceCountsCache");
|
||||
|
||||
Server server = new Server(0);
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
||||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(ourRestServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
|
||||
ourWebApplicationContext = new GenericWebApplicationContext();
|
||||
ourWebApplicationContext.setParent(myAppCtx);
|
||||
ourWebApplicationContext.refresh();
|
||||
proxyHandler.getServletContext().setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ourWebApplicationContext);
|
||||
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet();
|
||||
// dispatcherServlet.setApplicationContext(webApplicationContext);
|
||||
dispatcherServlet.setContextClass(AnnotationConfigWebApplicationContext.class);
|
||||
ServletHolder subsServletHolder = new ServletHolder();
|
||||
subsServletHolder.setServlet(dispatcherServlet);
|
||||
subsServletHolder.setInitParameter(
|
||||
ContextLoader.CONFIG_LOCATION_PARAM,
|
||||
WebsocketDispatcherConfig.class.getName());
|
||||
proxyHandler.addServlet(subsServletHolder, "/*");
|
||||
|
||||
// Register a CORS filter
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
CorsInterceptor corsInterceptor = new CorsInterceptor(config);
|
||||
config.addAllowedHeader("x-fhir-starter");
|
||||
config.addAllowedHeader("Origin");
|
||||
config.addAllowedHeader("Accept");
|
||||
config.addAllowedHeader("X-Requested-With");
|
||||
config.addAllowedHeader("Content-Type");
|
||||
config.addAllowedHeader("Access-Control-Request-Method");
|
||||
config.addAllowedHeader("Access-Control-Request-Headers");
|
||||
config.addAllowedOrigin("*");
|
||||
config.addExposedHeader("Location");
|
||||
config.addExposedHeader("Content-Location");
|
||||
config.setAllowedMethods(Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS"));
|
||||
ourRestServer.registerInterceptor(corsInterceptor);
|
||||
|
||||
server.setHandler(proxyHandler);
|
||||
JettyUtil.startServer(server);
|
||||
ourPort = JettyUtil.getPortForStartedServer(server);
|
||||
ourServerBase = "http://localhost:" + ourPort + "/fhir/context";
|
||||
|
||||
WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(subsServletHolder.getServlet().getServletConfig().getServletContext());
|
||||
myValidationSupport = wac.getBean(JpaValidationSupportChainR5.class);
|
||||
mySearchCoordinatorSvc = wac.getBean(ISearchCoordinatorSvc.class);
|
||||
mySearchEntityDao = wac.getBean(ISearchDao.class);
|
||||
ourSearchParamRegistry = wac.getBean(SearchParamRegistryR5.class);
|
||||
ourSubscriptionMatcherInterceptor = wac.getBean(SubscriptionMatcherInterceptor.class);
|
||||
ourSubscriptionMatcherInterceptor.start();
|
||||
|
||||
myFhirCtx.getRestfulClientFactory().setSocketTimeout(5000000);
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
builder.setMaxConnPerRoute(99);
|
||||
ourHttpClient = builder.build();
|
||||
|
||||
ourServer = server;
|
||||
}
|
||||
|
||||
ourRestServer.setPagingProvider(ourPagingProvider);
|
||||
|
||||
ourClient = myFhirCtx.newRestfulGenericClient(ourServerBase);
|
||||
if (shouldLogClient()) {
|
||||
ourClient.registerInterceptor(new LoggingInterceptor());
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean shouldLogClient() {
|
||||
return true;
|
||||
}
|
||||
|
||||
protected List<String> toNameList(Bundle resp) {
|
||||
List<String> names = new ArrayList<>();
|
||||
for (BundleEntryComponent next : resp.getEntry()) {
|
||||
Patient nextPt = (Patient) next.getResource();
|
||||
String nextStr = nextPt.getName().size() > 0 ? nextPt.getName().get(0).getGivenAsSingleString() + " " + nextPt.getName().get(0).getFamily() : "";
|
||||
if (isNotBlank(nextStr)) {
|
||||
names.add(nextStr);
|
||||
}
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
protected void waitForActivatedSubscriptionCount(int theSize) throws Exception {
|
||||
for (int i = 0; ; i++) {
|
||||
if (i == 10) {
|
||||
fail("Failed to init subscriptions");
|
||||
}
|
||||
try {
|
||||
mySubscriptionLoader.doSyncSubscriptionsForUnitTest();
|
||||
break;
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
Thread.sleep(250);
|
||||
}
|
||||
}
|
||||
|
||||
TestUtil.waitForSize(theSize, () -> mySubscriptionRegistry.size());
|
||||
Thread.sleep(500);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContextBaseResourceProviderR5Test() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
ourHttpClient.close();
|
||||
ourServer = null;
|
||||
ourHttpClient = null;
|
||||
myValidationSupport.flush();
|
||||
myValidationSupport = null;
|
||||
ourWebApplicationContext.close();
|
||||
ourWebApplicationContext = null;
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
public static int getNumberOfParametersByName(Parameters theParameters, String theName) {
|
||||
int retVal = 0;
|
||||
|
||||
for (ParametersParameterComponent param : theParameters.getParameter()) {
|
||||
if (param.getName().equals(theName)) {
|
||||
retVal++;
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
public static ParametersParameterComponent getParameterByName(Parameters theParameters, String theName) {
|
||||
for (ParametersParameterComponent param : theParameters.getParameter()) {
|
||||
if (param.getName().equals(theName)) {
|
||||
return param;
|
||||
}
|
||||
}
|
||||
|
||||
return new ParametersParameterComponent();
|
||||
}
|
||||
|
||||
public static List<ParametersParameterComponent> getParametersByName(Parameters theParameters, String theName) {
|
||||
List<ParametersParameterComponent> params = new ArrayList<>();
|
||||
for (ParametersParameterComponent param : theParameters.getParameter()) {
|
||||
if (param.getName().equals(theName)) {
|
||||
params.add(param);
|
||||
}
|
||||
}
|
||||
|
||||
return params;
|
||||
}
|
||||
|
||||
public static ParametersParameterComponent getPartByName(ParametersParameterComponent theParameter, String theName) {
|
||||
for (ParametersParameterComponent part : theParameter.getPart()) {
|
||||
if (part.getName().equals(theName)) {
|
||||
return part;
|
||||
}
|
||||
}
|
||||
|
||||
return new ParametersParameterComponent();
|
||||
}
|
||||
|
||||
public static boolean hasParameterByName(Parameters theParameters, String theName) {
|
||||
for (ParametersParameterComponent param : theParameters.getParameter()) {
|
||||
if (param.getName().equals(theName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package ca.uhn.fhir.jpa.provider.r5;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class ResourceProviderR5Test extends BaseResourceProviderR5Test {
|
||||
|
||||
private CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
|
||||
|
||||
@Override
|
||||
@After
|
||||
public void after() throws Exception {
|
||||
super.after();
|
||||
|
||||
myDaoConfig.setAllowMultipleDelete(new DaoConfig().isAllowMultipleDelete());
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setCountSearchResultsUpTo(new DaoConfig().getCountSearchResultsUpTo());
|
||||
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
|
||||
ourClient.unregisterInterceptor(myCapturingInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
myFhirCtx.setParserErrorHandler(new StrictErrorHandler());
|
||||
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
ourClient.registerInterceptor(myCapturingInterceptor);
|
||||
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithContainsLowerCase() {
|
||||
myDaoConfig.setAllowContainsSearches(true);
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("Elizabeth");
|
||||
String pt1id = myPatientDao.create(pt1).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.addName().setFamily("fghijk");
|
||||
String pt2id = myPatientDao.create(pt2).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Patient pt3 = new Patient();
|
||||
pt3.addName().setFamily("zzzzz");
|
||||
myPatientDao.create(pt3).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
|
||||
Bundle output = ourClient
|
||||
.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.NAME.contains().value("ZAB"))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
List<String> ids = output.getEntry().stream().map(t -> t.getResource().getIdElement().toUnqualifiedVersionless().getValue()).collect(Collectors.toList());
|
||||
assertThat(ids, containsInAnyOrder(pt1id));
|
||||
|
||||
output = ourClient
|
||||
.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.NAME.contains().value("zab"))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
ids = output.getEntry().stream().map(t -> t.getResource().getIdElement().toUnqualifiedVersionless().getValue()).collect(Collectors.toList());
|
||||
assertThat(ids, containsInAnyOrder(pt1id));
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
}
|
|
@ -9,7 +9,6 @@ import org.hl7.fhir.dstu3.model.Patient;
|
|||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
import org.springframework.cglib.proxy.Proxy;
|
||||
import org.springframework.test.util.AopTestUtils;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
|
@ -41,7 +40,7 @@ public class PagingMultinodeProviderDstu3Test extends BaseResourceProviderDstu3T
|
|||
|
||||
myDaoConfig.setAllowMultipleDelete(true);
|
||||
|
||||
mySearchCoordinatorSvcRaw = AopTestUtils.getTargetObject(mySearchCoordinatorSvc);
|
||||
mySearchCoordinatorSvcRaw = AopTestUtils.getTargetObject(ourSearchCoordinatorSvc);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -107,7 +107,7 @@ public class RestHookWithEventDefinitionR4Test extends BaseResourceProviderR4Tes
|
|||
.setType(TriggerDefinition.TriggerType.DATAADDED)
|
||||
.setCondition(new Expression()
|
||||
.setDescription("Encounter Location = emergency (active/completed encounters, current or previous)")
|
||||
.setLanguage(Expression.ExpressionLanguage.TEXT_FHIRPATH)
|
||||
.setLanguage(Expression.ExpressionLanguage.TEXT_FHIRPATH.toCode())
|
||||
.setExpression("(this | %previous).location.where(location = 'Location/emergency' and status in {'active', 'completed'}).exists()")
|
||||
)
|
||||
);
|
||||
|
|
|
@ -62,6 +62,11 @@
|
|||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r5</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
|
@ -82,6 +87,11 @@
|
|||
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-r5</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
|
|
|
@ -0,0 +1,886 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.extractor;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Search Parameters
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.model.util.StringNormalizer;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Sets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.PathEngineException;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Enumeration;
|
||||
import org.hl7.fhir.r5.model.CapabilityStatement.CapabilityStatementRestSecurityComponent;
|
||||
import org.hl7.fhir.r5.model.Location.LocationPositionComponent;
|
||||
import org.hl7.fhir.r5.model.Patient.PatientCommunicationComponent;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.measure.unit.NonSI;
|
||||
import javax.measure.unit.Unit;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class SearchParamExtractorR5 extends BaseSearchParamExtractor implements ISearchParamExtractor {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamExtractorR5.class);
|
||||
private static final Set<Class<?>> ourIgnoredForSearchDatatypes;
|
||||
|
||||
static {
|
||||
//noinspection unchecked
|
||||
ourIgnoredForSearchDatatypes = Collections.unmodifiableSet(Sets.newHashSet(
|
||||
Age.class,
|
||||
Annotation.class,
|
||||
Attachment.class,
|
||||
Count.class,
|
||||
Distance.class,
|
||||
Ratio.class,
|
||||
SampledData.class,
|
||||
Signature.class,
|
||||
LocationPositionComponent.class
|
||||
));
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SearchParamExtractorR5() {
|
||||
super();
|
||||
}
|
||||
|
||||
// This constructor is used by tests
|
||||
@VisibleForTesting
|
||||
public SearchParamExtractorR5(ModelConfig theModelConfig, FhirContext theCtx, IValidationSupport theValidationSupport, ISearchParamRegistry theSearchParamRegistry) {
|
||||
super(theCtx, theSearchParamRegistry);
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
private void addQuantity(ResourceTable theEntity, HashSet<ResourceIndexedSearchParamQuantity> retVal, String resourceName, Quantity nextValue) {
|
||||
if (!nextValue.getValueElement().isEmpty()) {
|
||||
BigDecimal nextValueValue = nextValue.getValueElement().getValue();
|
||||
String nextValueString = nextValue.getSystemElement().getValueAsString();
|
||||
String nextValueCode = nextValue.getCode();
|
||||
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValueValue, nextValueString, nextValueCode);
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
}
|
||||
}
|
||||
|
||||
private void addMoney(ResourceTable theEntity, HashSet<ResourceIndexedSearchParamQuantity> retVal, String resourceName, Money nextValue) {
|
||||
if (!nextValue.getValueElement().isEmpty()) {
|
||||
BigDecimal nextValueValue = nextValue.getValueElement().getValue();
|
||||
String nextValueString = "urn:iso:std:iso:4217";
|
||||
String nextValueCode = nextValue.getCurrency();
|
||||
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValueValue, nextValueString, nextValueCode);
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
}
|
||||
}
|
||||
|
||||
private void addSearchTerm(ResourceTable theEntity, Set<ResourceIndexedSearchParamString> retVal, String resourceName, String searchTerm) {
|
||||
if (isBlank(searchTerm)) {
|
||||
return;
|
||||
}
|
||||
if (searchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
||||
searchTerm = searchTerm.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
|
||||
}
|
||||
|
||||
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(getModelConfig(), resourceName, StringNormalizer.normalizeString(searchTerm), searchTerm);
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
}
|
||||
|
||||
private void addStringParam(ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> retVal, RuntimeSearchParam nextSpDef, String value) {
|
||||
if (value.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
|
||||
value = value.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
|
||||
}
|
||||
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(getModelConfig(), nextSpDef.getName(), StringNormalizer.normalizeString(value), value);
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PathAndRef> extractResourceLinks(IBaseResource theResource, RuntimeSearchParam theNextSpDef) {
|
||||
ArrayList<PathAndRef> retVal = new ArrayList<>();
|
||||
|
||||
String[] nextPathsSplit = SPLIT_R4.split(theNextSpDef.getPath());
|
||||
for (String path : nextPathsSplit) {
|
||||
path = path.trim();
|
||||
if (isNotBlank(path)) {
|
||||
|
||||
for (Object next : extractValues(path, theResource)) {
|
||||
retVal.add(new PathAndRef(path, next));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IBaseResource theResource) {
|
||||
// TODO: implement
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
|
||||
*/
|
||||
@Override
|
||||
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<>();
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.DATE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String nextPath = nextSpDef.getPath();
|
||||
if (isBlank(nextPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean multiType = false;
|
||||
if (nextPath.endsWith("[x]")) {
|
||||
multiType = true;
|
||||
}
|
||||
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
if (nextObject == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceIndexedSearchParamDate nextEntity;
|
||||
if (nextObject instanceof BaseDateTimeType) {
|
||||
BaseDateTimeType nextValue = (BaseDateTimeType) nextObject;
|
||||
if (nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), nextValue.getValue(), nextValue.getValue(), nextValue.getValueAsString());
|
||||
} else if (nextObject instanceof Period) {
|
||||
Period nextValue = (Period) nextObject;
|
||||
if (nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), nextValue.getStart(), nextValue.getEnd(), nextValue.getStartElement().getValueAsString());
|
||||
} else if (nextObject instanceof Timing) {
|
||||
Timing nextValue = (Timing) nextObject;
|
||||
if (nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
TreeSet<Date> dates = new TreeSet<>();
|
||||
String firstValue = null;
|
||||
for (DateTimeType nextEvent : nextValue.getEvent()) {
|
||||
if (nextEvent.getValue() != null) {
|
||||
dates.add(nextEvent.getValue());
|
||||
if (firstValue == null) {
|
||||
firstValue = nextEvent.getValueAsString();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (nextValue.getRepeat().hasBounds()) {
|
||||
if (nextValue.getRepeat().getBoundsPeriod().getStart() != null) {
|
||||
dates.add(nextValue.getRepeat().getBoundsPeriod().getStart());
|
||||
}
|
||||
if (nextValue.getRepeat().getBoundsPeriod().getEnd() != null) {
|
||||
dates.add(nextValue.getRepeat().getBoundsPeriod().getEnd());
|
||||
}
|
||||
}
|
||||
if (dates.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), dates.first(), dates.last(), firstValue);
|
||||
} else if (nextObject instanceof StringType) {
|
||||
// CarePlan.activitydate can be a string
|
||||
continue;
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (nextEntity != null) {
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
|
||||
*/
|
||||
@Override
|
||||
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<>();
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.NUMBER) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String nextPath = nextSpDef.getPath();
|
||||
if (isBlank(nextPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String resourceName = nextSpDef.getName();
|
||||
boolean multiType = false;
|
||||
if (nextPath.endsWith("[x]")) {
|
||||
multiType = true;
|
||||
}
|
||||
|
||||
if (nextObject instanceof Duration) {
|
||||
Duration nextValue = (Duration) nextObject;
|
||||
if (nextValue.getValueElement().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (SearchParamConstants.UCUM_NS.equals(nextValue.getSystem())) {
|
||||
if (isNotBlank(nextValue.getCode())) {
|
||||
|
||||
Unit<? extends javax.measure.quantity.Quantity> unit = Unit.valueOf(nextValue.getCode());
|
||||
javax.measure.converter.UnitConverter dayConverter = unit.getConverterTo(NonSI.DAY);
|
||||
double dayValue = dayConverter.convert(nextValue.getValue().doubleValue());
|
||||
Duration newValue = new Duration();
|
||||
newValue.setSystem(SearchParamConstants.UCUM_NS);
|
||||
newValue.setCode(NonSI.DAY.toString());
|
||||
newValue.setValue(dayValue);
|
||||
nextValue = newValue;
|
||||
|
||||
/*
|
||||
* @SuppressWarnings("unchecked") PhysicsUnit<? extends org.unitsofmeasurement.quantity.Quantity<?>> unit = (PhysicsUnit<? extends org.unitsofmeasurement.quantity.Quantity<?>>)
|
||||
* UCUMFormat.getCaseInsensitiveInstance().parse(nextValue.getCode().getValue(), null); if (unit.isCompatible(UCUM.DAY)) {
|
||||
*
|
||||
* @SuppressWarnings("unchecked") PhysicsUnit<org.unitsofmeasurement.quantity.Time> timeUnit = (PhysicsUnit<Time>) unit; UnitConverter conv = timeUnit.getConverterTo(UCUM.DAY);
|
||||
* double dayValue = conv.convert(nextValue.getValue().getValue().doubleValue()); Duration newValue = new Duration(); newValue.setSystem(UCUM_NS);
|
||||
* newValue.setCode(UCUM.DAY.getSymbol()); newValue.setValue(dayValue); nextValue=newValue; }
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue());
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
} else if (nextObject instanceof Quantity) {
|
||||
Quantity nextValue = (Quantity) nextObject;
|
||||
if (nextValue.getValueElement().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue());
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
} else if (nextObject instanceof IntegerType) {
|
||||
IntegerType nextValue = (IntegerType) nextObject;
|
||||
if (nextValue.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, new BigDecimal(nextValue.getValue()));
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
} else if (nextObject instanceof DecimalType) {
|
||||
DecimalType nextValue = (DecimalType) nextObject;
|
||||
if (nextValue.getValue() == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue());
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
|
||||
*/
|
||||
@Override
|
||||
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<>();
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.QUANTITY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String nextPath = nextSpDef.getPath();
|
||||
if (isBlank(nextPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String resourceName = nextSpDef.getName();
|
||||
boolean multiType = false;
|
||||
if (nextPath.endsWith("[x]")) {
|
||||
multiType = true;
|
||||
}
|
||||
|
||||
if (nextObject instanceof Quantity) {
|
||||
Quantity nextValue = (Quantity) nextObject;
|
||||
addQuantity(theEntity, retVal, resourceName, nextValue);
|
||||
} else if (nextObject instanceof Money) {
|
||||
Money nextValue = (Money) nextObject;
|
||||
addMoney(theEntity, retVal, resourceName, nextValue);
|
||||
} else if (nextObject instanceof Range) {
|
||||
Range nextValue = (Range) nextObject;
|
||||
addQuantity(theEntity, retVal, resourceName, nextValue.getLow());
|
||||
addQuantity(theEntity, retVal, resourceName, nextValue.getHigh());
|
||||
} else if (ourIgnoredForSearchDatatypes.contains(nextObject.getClass())) {
|
||||
continue;
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
|
||||
*/
|
||||
@Override
|
||||
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<>();
|
||||
|
||||
String resourceName = getContext().getResourceDefinition(theResource).getName();
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.STRING) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String nextPath = nextSpDef.getPath();
|
||||
String nextSpName = nextSpDef.getName();
|
||||
|
||||
if (isBlank(nextPath)) {
|
||||
|
||||
// // TODO: implement phonetic, and any others that have no path
|
||||
//
|
||||
// // TODO: do we still need this check?
|
||||
// if ("Questionnaire".equals(nextSpName) && nextSpDef.getName().equals("title")) {
|
||||
// Questionnaire q = (Questionnaire) theResource;
|
||||
// String title = "";// q.getGroup().getTitle();
|
||||
// addSearchTerm(theEntity, retVal, nextSpName, title);
|
||||
// }
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean multiType = false;
|
||||
if (nextPath.endsWith("[x]")) {
|
||||
multiType = true;
|
||||
}
|
||||
|
||||
if (nextObject instanceof IPrimitiveType<?>) {
|
||||
IPrimitiveType<?> nextValue = (IPrimitiveType<?>) nextObject;
|
||||
String searchTerm = nextValue.getValueAsString();
|
||||
addSearchTerm(theEntity, retVal, nextSpName, searchTerm);
|
||||
} else {
|
||||
if (nextObject instanceof HumanName) {
|
||||
ArrayList<StringType> allNames = new ArrayList<>();
|
||||
HumanName nextHumanName = (HumanName) nextObject;
|
||||
if (isNotBlank(nextHumanName.getFamily())) {
|
||||
allNames.add(nextHumanName.getFamilyElement());
|
||||
}
|
||||
allNames.addAll(nextHumanName.getGiven());
|
||||
for (StringType nextName : allNames) {
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof Address) {
|
||||
ArrayList<StringType> allNames = new ArrayList<>();
|
||||
Address nextAddress = (Address) nextObject;
|
||||
allNames.addAll(nextAddress.getLine());
|
||||
allNames.add(nextAddress.getCityElement());
|
||||
allNames.add(nextAddress.getStateElement());
|
||||
allNames.add(nextAddress.getCountryElement());
|
||||
allNames.add(nextAddress.getPostalCodeElement());
|
||||
for (StringType nextName : allNames) {
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextName.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof ContactPoint) {
|
||||
ContactPoint nextContact = (ContactPoint) nextObject;
|
||||
if (nextContact.getValueElement().isEmpty() == false) {
|
||||
addSearchTerm(theEntity, retVal, nextSpName, nextContact.getValue());
|
||||
}
|
||||
} else if (nextObject instanceof Quantity) {
|
||||
BigDecimal value = ((Quantity) nextObject).getValue();
|
||||
if (value != null) {
|
||||
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
|
||||
}
|
||||
} else if (nextObject instanceof Range) {
|
||||
Quantity low = ((Range) nextObject).getLow();
|
||||
if (low != null) {
|
||||
BigDecimal value = low.getValue();
|
||||
if (value != null) {
|
||||
addSearchTerm(theEntity, retVal, nextSpName, value.toPlainString());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + nextSpName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable, ca.uhn.fhir.model.api.IBaseResource)
|
||||
*/
|
||||
@Override
|
||||
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<BaseResourceIndexedSearchParam> retVal = new HashSet<>();
|
||||
|
||||
String useSystem = null;
|
||||
if (theResource instanceof CodeSystem) {
|
||||
CodeSystem cs = (CodeSystem) theResource;
|
||||
useSystem = cs.getUrl();
|
||||
}
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String resourceType = theEntity.getResourceType();
|
||||
String nextPath = nextSpDef.getPath();
|
||||
if (isBlank(nextPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
boolean multiType = false;
|
||||
if (nextPath.endsWith("[x]")) {
|
||||
multiType = true;
|
||||
}
|
||||
|
||||
List<String> systems = new ArrayList<>();
|
||||
List<String> codes = new ArrayList<>();
|
||||
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
|
||||
if (nextObject == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Patient:language
|
||||
if (nextObject instanceof PatientCommunicationComponent) {
|
||||
PatientCommunicationComponent nextValue = (PatientCommunicationComponent) nextObject;
|
||||
nextObject = nextValue.getLanguage();
|
||||
}
|
||||
|
||||
if (nextObject instanceof Identifier) {
|
||||
Identifier nextValue = (Identifier) nextObject;
|
||||
if (nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
String system = StringUtils.defaultIfBlank(nextValue.getSystemElement().getValueAsString(), null);
|
||||
String value = nextValue.getValueElement().getValue();
|
||||
if (isNotBlank(value)) {
|
||||
systems.add(system);
|
||||
codes.add(value);
|
||||
}
|
||||
|
||||
if (isNotBlank(nextValue.getType().getText())) {
|
||||
addStringParam(theEntity, retVal, nextSpDef, nextValue.getType().getText());
|
||||
}
|
||||
|
||||
} else if (nextObject instanceof ContactPoint) {
|
||||
ContactPoint nextValue = (ContactPoint) nextObject;
|
||||
if (nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
systems.add(nextValue.getSystemElement().getValueAsString());
|
||||
codes.add(nextValue.getValueElement().getValue());
|
||||
} else if (nextObject instanceof Enumeration<?>) {
|
||||
Enumeration<?> obj = (Enumeration<?>) nextObject;
|
||||
String system = extractSystem(obj);
|
||||
String code = obj.getValueAsString();
|
||||
if (isNotBlank(code)) {
|
||||
systems.add(system);
|
||||
codes.add(code);
|
||||
}
|
||||
} else if (nextObject instanceof IPrimitiveType<?>) {
|
||||
IPrimitiveType<?> nextValue = (IPrimitiveType<?>) nextObject;
|
||||
if (nextValue.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
if ("CodeSystem.concept.code".equals(nextPath)) {
|
||||
systems.add(useSystem);
|
||||
} else {
|
||||
systems.add(null);
|
||||
}
|
||||
codes.add(nextValue.getValueAsString());
|
||||
} else if (nextObject instanceof Coding) {
|
||||
Coding nextValue = (Coding) nextObject;
|
||||
extractTokensFromCoding(systems, codes, theEntity, retVal, nextSpDef, nextValue);
|
||||
} else if (nextObject instanceof CodeableConcept) {
|
||||
CodeableConcept nextCC = (CodeableConcept) nextObject;
|
||||
if (!nextCC.getTextElement().isEmpty()) {
|
||||
addStringParam(theEntity, retVal, nextSpDef, nextCC.getTextElement().getValue());
|
||||
}
|
||||
|
||||
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
|
||||
} else if (nextObject instanceof CapabilityStatementRestSecurityComponent) {
|
||||
// Conformance.security search param points to something kind of useless right now - This should probably
|
||||
// be fixed.
|
||||
CapabilityStatementRestSecurityComponent sec = (CapabilityStatementRestSecurityComponent) nextObject;
|
||||
for (CodeableConcept nextCC : sec.getService()) {
|
||||
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
|
||||
}
|
||||
} else if (nextObject instanceof LocationPositionComponent) {
|
||||
ourLog.warn("Position search not currently supported, not indexing location");
|
||||
continue;
|
||||
} else if (nextObject instanceof StructureDefinition.StructureDefinitionContextComponent) {
|
||||
ourLog.warn("StructureDefinition context indexing not currently supported"); // TODO: implement this
|
||||
continue;
|
||||
} else if (resourceType.equals("Consent") && nextPath.equals("Consent.source")) {
|
||||
// Consent#source-identifier has a path that isn't typed - This is a one-off to deal with that
|
||||
continue;
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + nextSpDef.getName() + " with path " + nextPath + " is of unexpected datatype: " + nextObject.getClass());
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
assert systems.size() == codes.size() : "Systems contains " + systems + ", codes contains: " + codes;
|
||||
|
||||
Set<Pair<String, String>> haveValues = new HashSet<>();
|
||||
for (int i = 0; i < systems.size(); i++) {
|
||||
String system = systems.get(i);
|
||||
String code = codes.get(i);
|
||||
if (isBlank(system) && isBlank(code)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||
system = system.substring(0, ResourceIndexedSearchParamToken.MAX_LENGTH);
|
||||
}
|
||||
if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
|
||||
code = code.substring(0, ResourceIndexedSearchParamToken.MAX_LENGTH);
|
||||
}
|
||||
|
||||
Pair<String, String> nextPair = Pair.of(system, code);
|
||||
if (haveValues.contains(nextPair)) {
|
||||
continue;
|
||||
}
|
||||
haveValues.add(nextPair);
|
||||
|
||||
ResourceIndexedSearchParamToken nextEntity;
|
||||
nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), system, code);
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IBaseResource theResource) {
|
||||
HashSet<ResourceIndexedSearchParamUri> retVal = new HashSet<>();
|
||||
|
||||
Collection<RuntimeSearchParam> searchParams = getSearchParams(theResource);
|
||||
for (RuntimeSearchParam nextSpDef : searchParams) {
|
||||
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.URI) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String nextPath = nextSpDef.getPath();
|
||||
if (isBlank(nextPath)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (Object nextObject : extractValues(nextPath, theResource)) {
|
||||
if (nextObject == null || ((IBase) nextObject).isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
String resourceName = nextSpDef.getName();
|
||||
boolean multiType = false;
|
||||
if (nextPath.endsWith("[x]")) {
|
||||
multiType = true;
|
||||
}
|
||||
|
||||
if (nextObject instanceof UriType) {
|
||||
UriType nextValue = (UriType) nextObject;
|
||||
if (isBlank(nextValue.getValue())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ourLog.trace("Adding param: {}, {}", resourceName, nextValue.getValue());
|
||||
|
||||
ResourceIndexedSearchParamUri nextEntity = new ResourceIndexedSearchParamUri(resourceName, nextValue.getValue());
|
||||
|
||||
nextEntity.setResource(theEntity);
|
||||
retVal.add(nextEntity);
|
||||
} else {
|
||||
if (!multiType) {
|
||||
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConcept theCodeableConcept, ResourceTable theEntity,
|
||||
Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
|
||||
for (Coding nextCoding : theCodeableConcept.getCoding()) {
|
||||
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
|
||||
}
|
||||
}
|
||||
|
||||
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate,
|
||||
RuntimeSearchParam theParameterDef, Coding nextCoding) {
|
||||
if (nextCoding != null && !nextCoding.isEmpty()) {
|
||||
|
||||
String nextSystem = nextCoding.getSystemElement().getValueAsString();
|
||||
String nextCode = nextCoding.getCodeElement().getValue();
|
||||
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
|
||||
theSystems.add(nextSystem);
|
||||
theCodes.add(nextCode);
|
||||
}
|
||||
|
||||
if (!nextCoding.getDisplayElement().isEmpty()) {
|
||||
addStringParam(theEntity, theListToPopulate, theParameterDef, nextCoding.getDisplayElement().getValue());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override parent because we're using FHIRPath here
|
||||
*/
|
||||
@Override
|
||||
protected List<Object> extractValues(String thePaths, IBaseResource theResource) {
|
||||
IWorkerContext worker = new org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext(getContext(), myValidationSupport);
|
||||
FHIRPathEngine fp = new FHIRPathEngine(worker);
|
||||
fp.setHostServices(new SearchParamExtractorR5HostServices());
|
||||
|
||||
List<Object> values = new ArrayList<>();
|
||||
String[] nextPathsSplit = SPLIT_R4.split(thePaths);
|
||||
for (String nextPath : nextPathsSplit) {
|
||||
List<Base> allValues;
|
||||
try {
|
||||
allValues = fp.evaluate((Base) theResource, nextPath);
|
||||
} catch (FHIRException e) {
|
||||
String msg = getContext().getLocalizer().getMessage(BaseSearchParamExtractor.class, "failedToExtractPaths", nextPath, e.toString());
|
||||
throw new InternalErrorException(msg, e);
|
||||
}
|
||||
if (allValues.isEmpty() == false) {
|
||||
values.addAll(allValues);
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < values.size(); i++) {
|
||||
Object nextObject = values.get(i);
|
||||
if (nextObject instanceof Extension) {
|
||||
Extension nextExtension = (Extension) nextObject;
|
||||
nextObject = nextExtension.getValue();
|
||||
values.set(i, nextObject);
|
||||
}
|
||||
}
|
||||
|
||||
return values;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
void setValidationSupportForTesting(IValidationSupport theValidationSupport) {
|
||||
myValidationSupport = theValidationSupport;
|
||||
}
|
||||
|
||||
private class SearchParamExtractorR5HostServices implements FHIRPathEngine.IEvaluationContext {
|
||||
|
||||
private Map<String, Base> myResourceTypeToStub = Collections.synchronizedMap(new HashMap<>());
|
||||
|
||||
@Override
|
||||
public Base resolveConstant(Object appContext, String name, boolean beforeContext) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDetails resolveConstantType(Object appContext, String name) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean log(String argument, List<Base> focus) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FunctionDetails resolveFunction(String functionName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TypeDetails checkFunction(Object appContext, String functionName, List<TypeDetails> parameters) throws PathEngineException {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Base> executeFunction(Object appContext, String functionName, List<List<Base>> parameters) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Base resolveReference(Object theAppContext, String theUrl) throws FHIRException {
|
||||
|
||||
/*
|
||||
* When we're doing resolution within the SearchParamExtractor, if we want
|
||||
* to do a resolve() it's just to check the type, so there is no point
|
||||
* going through the heavyweight test. We can just return a stub and
|
||||
* that's good enough since we're just doing something like
|
||||
* Encounter.patient.where(resolve() is Patient)
|
||||
*/
|
||||
IdType url = new IdType(theUrl);
|
||||
Base retVal = null;
|
||||
if (isNotBlank(url.getResourceType())) {
|
||||
|
||||
retVal = myResourceTypeToStub.get(url.getResourceType());
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
ResourceType resourceType = ResourceType.fromCode(url.getResourceType());
|
||||
if (resourceType != null) {
|
||||
retVal = new Resource() {
|
||||
@Override
|
||||
public Resource copy() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceType getResourceType() {
|
||||
return resourceType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String fhirType() {
|
||||
return url.getResourceType();
|
||||
}
|
||||
|
||||
};
|
||||
myResourceTypeToStub.put(url.getResourceType(), retVal);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean conformsToProfile(Object appContext, Base item, String url) throws FHIRException {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet resolveValueSet(Object theO, String theS) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static <T extends Enum<?>> String extractSystem(Enumeration<T> theBoundCode) {
|
||||
if (theBoundCode.getValue() != null) {
|
||||
return theBoundCode.getEnumFactory().toSystem(theBoundCode.getValue());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,130 @@
|
|||
package ca.uhn.fhir.jpa.searchparam.registry;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Search Parameters
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam.RuntimeSearchParamStatusEnum;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.rest.api.RestSearchParameterTypeEnum;
|
||||
import ca.uhn.fhir.util.DatatypeUtil;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.Extension;
|
||||
import org.hl7.fhir.r5.model.Reference;
|
||||
import org.hl7.fhir.r5.model.SearchParameter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class SearchParamRegistryR5 extends BaseSearchParamRegistry<SearchParameter> {
|
||||
|
||||
@Override
|
||||
protected RuntimeSearchParam toRuntimeSp(SearchParameter theNextSp) {
|
||||
String name = theNextSp.getCode();
|
||||
String description = theNextSp.getDescription();
|
||||
String path = theNextSp.getExpression();
|
||||
RestSearchParameterTypeEnum paramType = null;
|
||||
RuntimeSearchParamStatusEnum status = null;
|
||||
switch (theNextSp.getType()) {
|
||||
case COMPOSITE:
|
||||
paramType = RestSearchParameterTypeEnum.COMPOSITE;
|
||||
break;
|
||||
case DATE:
|
||||
paramType = RestSearchParameterTypeEnum.DATE;
|
||||
break;
|
||||
case NUMBER:
|
||||
paramType = RestSearchParameterTypeEnum.NUMBER;
|
||||
break;
|
||||
case QUANTITY:
|
||||
paramType = RestSearchParameterTypeEnum.QUANTITY;
|
||||
break;
|
||||
case REFERENCE:
|
||||
paramType = RestSearchParameterTypeEnum.REFERENCE;
|
||||
break;
|
||||
case STRING:
|
||||
paramType = RestSearchParameterTypeEnum.STRING;
|
||||
break;
|
||||
case TOKEN:
|
||||
paramType = RestSearchParameterTypeEnum.TOKEN;
|
||||
break;
|
||||
case URI:
|
||||
paramType = RestSearchParameterTypeEnum.URI;
|
||||
break;
|
||||
case SPECIAL:
|
||||
paramType = RestSearchParameterTypeEnum.SPECIAL;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
if (theNextSp.getStatus() != null) {
|
||||
switch (theNextSp.getStatus()) {
|
||||
case ACTIVE:
|
||||
status = RuntimeSearchParamStatusEnum.ACTIVE;
|
||||
break;
|
||||
case DRAFT:
|
||||
status = RuntimeSearchParamStatusEnum.DRAFT;
|
||||
break;
|
||||
case RETIRED:
|
||||
status = RuntimeSearchParamStatusEnum.RETIRED;
|
||||
break;
|
||||
case UNKNOWN:
|
||||
status = RuntimeSearchParamStatusEnum.UNKNOWN;
|
||||
break;
|
||||
case NULL:
|
||||
break;
|
||||
}
|
||||
}
|
||||
Set<String> providesMembershipInCompartments = Collections.emptySet();
|
||||
Set<String> targets = DatatypeUtil.toStringSet(theNextSp.getTarget());
|
||||
|
||||
if (isBlank(name) || isBlank(path) || paramType == null) {
|
||||
if (paramType != RestSearchParameterTypeEnum.COMPOSITE) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
IIdType id = theNextSp.getIdElement();
|
||||
String uri = "";
|
||||
boolean unique = false;
|
||||
|
||||
List<Extension> uniqueExts = theNextSp.getExtensionsByUrl(SearchParamConstants.EXT_SP_UNIQUE);
|
||||
if (uniqueExts.size() > 0) {
|
||||
IPrimitiveType<?> uniqueExtsValuePrimitive = uniqueExts.get(0).getValueAsPrimitive();
|
||||
if (uniqueExtsValuePrimitive != null) {
|
||||
if ("true".equalsIgnoreCase(uniqueExtsValuePrimitive.getValueAsString())) {
|
||||
unique = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<JpaRuntimeSearchParam.Component> components = new ArrayList<>();
|
||||
for (SearchParameter.SearchParameterComponentComponent next : theNextSp.getComponent()) {
|
||||
components.add(new JpaRuntimeSearchParam.Component(next.getExpression(), new Reference(next.getDefinition())));
|
||||
}
|
||||
|
||||
return new JpaRuntimeSearchParam(id, uri, name, description, path, paramType, providesMembershipInCompartments, targets, status, unique, components, theNextSp.getBase());
|
||||
}
|
||||
}
|
|
@ -9,22 +9,29 @@ import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
|||
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.r5.JpaConformanceProviderR5;
|
||||
import ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||
import ca.uhn.fhir.jpa.subscription.SubscriptionInterceptorLoader;
|
||||
import ca.uhn.fhir.jpa.util.ResourceProviderFactory;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.*;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.ElementsSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.BanUnsupportedHttpMethodsInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
import ca.uhn.fhirtest.config.*;
|
||||
import ca.uhn.fhirtest.config.TestDstu2Config;
|
||||
import ca.uhn.fhirtest.config.TestDstu3Config;
|
||||
import ca.uhn.fhirtest.config.TestR4Config;
|
||||
import ca.uhn.fhirtest.config.TestR5Config;
|
||||
import ca.uhn.hapi.converters.server.VersionedApiConverterInterceptor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.r4.hapi.rest.server.GraphQLProvider;
|
||||
|
@ -40,6 +47,7 @@ import java.util.List;
|
|||
|
||||
public class TestRestfulServer extends RestfulServer {
|
||||
|
||||
public static final String FHIR_BASEURL_R5 = "fhir.baseurl.r5";
|
||||
public static final String FHIR_BASEURL_R4 = "fhir.baseurl.r4";
|
||||
public static final String FHIR_BASEURL_DSTU2 = "fhir.baseurl.dstu2";
|
||||
public static final String FHIR_BASEURL_DSTU3 = "fhir.baseurl.dstu3";
|
||||
|
@ -118,7 +126,7 @@ public class TestRestfulServer extends RestfulServer {
|
|||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
providers.add(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||
providers.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
break;
|
||||
}
|
||||
case "R4": {
|
||||
|
@ -136,10 +144,29 @@ public class TestRestfulServer extends RestfulServer {
|
|||
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
providers.add(myAppCtx.getBean(TerminologyUploaderProviderR4.class));
|
||||
providers.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
providers.add(myAppCtx.getBean(GraphQLProvider.class));
|
||||
break;
|
||||
}
|
||||
case "R5": {
|
||||
myAppCtx = new AnnotationConfigWebApplicationContext();
|
||||
myAppCtx.setServletConfig(getServletConfig());
|
||||
myAppCtx.setParent(parentAppCtx);
|
||||
myAppCtx.register(TestR5Config.class, WebsocketDispatcherConfig.class);
|
||||
baseUrlProperty = FHIR_BASEURL_R5;
|
||||
myAppCtx.refresh();
|
||||
setFhirContext(FhirContext.forR5());
|
||||
beans = myAppCtx.getBean("myResourceProvidersR5", ResourceProviderFactory.class);
|
||||
providers.add(myAppCtx.getBean("mySystemProviderR5", JpaSystemProviderR5.class));
|
||||
systemDao = myAppCtx.getBean("mySystemDaoR5", IFhirSystemDao.class);
|
||||
etagSupport = ETagSupportEnum.ENABLED;
|
||||
JpaConformanceProviderR5 confProvider = new JpaConformanceProviderR5(this, systemDao, myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription(implDesc);
|
||||
setServerConformanceProvider(confProvider);
|
||||
providers.add(myAppCtx.getBean(TerminologyUploaderProvider.class));
|
||||
// providers.add(myAppCtx.getBean(GraphQLProvider.class));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new ServletException("Unknown FHIR version specified in init-param[FhirVersion]: " + fhirVersionParam);
|
||||
}
|
||||
|
|
|
@ -42,6 +42,11 @@ public class FhirTesterConfig {
|
|||
public TesterConfig testerConfig() {
|
||||
TesterConfig retVal = new TesterConfig();
|
||||
retVal
|
||||
.addServer()
|
||||
.withId("home_r4")
|
||||
.withFhirVersion(FhirVersionEnum.R4)
|
||||
.withBaseUrl("http://hapi.fhir.org/baseR4")
|
||||
.withName("UHN/HAPI Server (R4 FHIR)")
|
||||
.addServer()
|
||||
.withId("home_21")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU3)
|
||||
|
@ -53,10 +58,10 @@ public class FhirTesterConfig {
|
|||
.withBaseUrl("http://hapi.fhir.org/baseDstu2")
|
||||
.withName("UHN/HAPI Server (DSTU2 FHIR)")
|
||||
.addServer()
|
||||
.withId("home_r4")
|
||||
.withFhirVersion(FhirVersionEnum.R4)
|
||||
.withBaseUrl("http://hapi.fhir.org/baseR4")
|
||||
.withName("UHN/HAPI Server (R4 FHIR)")
|
||||
.withId("home_r5")
|
||||
.withFhirVersion(FhirVersionEnum.R5)
|
||||
.withBaseUrl("http://hapi.fhir.org/baseR5")
|
||||
.withName("UHN/HAPI Server (R5 FHIR)")
|
||||
// .addServer()
|
||||
// .withId("tdl_d2")
|
||||
// .withFhirVersion(FhirVersionEnum.DSTU2)
|
||||
|
|
|
@ -0,0 +1,170 @@
|
|||
package ca.uhn.fhirtest.config;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigR5;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
|
||||
import ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import ca.uhn.fhirtest.interceptor.PublicSecurityInterceptor;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import org.hibernate.dialect.PostgreSQL94Dialect;
|
||||
import org.hl7.fhir.dstu2.model.Subscription;
|
||||
import org.springframework.beans.factory.annotation.Autowire;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@Import(CommonConfig.class)
|
||||
@EnableTransactionManagement()
|
||||
public class TestR5Config extends BaseJavaConfigR5 {
|
||||
public static final String FHIR_DB_USERNAME = "${fhir.db.username}";
|
||||
public static final String FHIR_DB_PASSWORD = "${fhir.db.password}";
|
||||
public static final String FHIR_LUCENE_LOCATION_R5 = "${fhir.lucene.location.r5}";
|
||||
public static final Integer COUNT_SEARCH_RESULTS_UP_TO = 50000;
|
||||
|
||||
@Value(TestR5Config.FHIR_DB_USERNAME)
|
||||
private String myDbUsername;
|
||||
|
||||
@Value(TestR5Config.FHIR_DB_PASSWORD)
|
||||
private String myDbPassword;
|
||||
|
||||
@Value(FHIR_LUCENE_LOCATION_R5)
|
||||
private String myFhirLuceneLocation;
|
||||
|
||||
@Bean
|
||||
public DaoConfig daoConfig() {
|
||||
DaoConfig retVal = new DaoConfig();
|
||||
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL);
|
||||
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
retVal.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.WEBSOCKET);
|
||||
retVal.setWebsocketContextPath("/websocketR5");
|
||||
retVal.setAllowContainsSearches(true);
|
||||
retVal.setAllowMultipleDelete(true);
|
||||
retVal.setAllowInlineMatchUrlReferences(true);
|
||||
retVal.setAllowExternalReferences(true);
|
||||
retVal.getTreatBaseUrlsAsLocal().add("http://hapi.fhir.org/baseR5");
|
||||
retVal.getTreatBaseUrlsAsLocal().add("https://hapi.fhir.org/baseR5");
|
||||
retVal.getTreatBaseUrlsAsLocal().add("http://fhirtest.uhn.ca/baseR5");
|
||||
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseR5");
|
||||
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
|
||||
retVal.setCountSearchResultsUpTo(TestR5Config.COUNT_SEARCH_RESULTS_UP_TO);
|
||||
retVal.setFetchSizeDefaultMaximum(10000);
|
||||
retVal.setExpungeEnabled(true);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ModelConfig modelConfig() {
|
||||
return daoConfig().getModelConfig();
|
||||
}
|
||||
|
||||
|
||||
@Bean(name = "myPersistenceDataSourceR5", destroyMethod = "close")
|
||||
public DataSource dataSource() {
|
||||
BasicDataSource retVal = new BasicDataSource();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
retVal.setUrl("jdbc:derby:memory:fhirtest_r5;create=true");
|
||||
} else {
|
||||
retVal.setDriver(new org.postgresql.Driver());
|
||||
retVal.setUrl("jdbc:postgresql://localhost/fhirtest_r5");
|
||||
}
|
||||
retVal.setUsername(myDbUsername);
|
||||
retVal.setPassword(myDbPassword);
|
||||
retVal.setDefaultQueryTimeout(20);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean(autowire = Autowire.BY_TYPE)
|
||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||
DatabaseBackedPagingProvider retVal = super.databaseBackedPagingProvider();
|
||||
retVal.setDefaultPageSize(20);
|
||||
retVal.setMaximumPageSize(500);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
|
||||
retVal.setPersistenceUnitName("PU_HapiFhirJpaR5");
|
||||
retVal.setDataSource(dataSource());
|
||||
retVal.setJpaProperties(jpaProperties());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private Properties jpaProperties() {
|
||||
Properties extraProperties = new Properties();
|
||||
if (CommonConfig.isLocalTestMode()) {
|
||||
extraProperties.put("hibernate.dialect", DerbyTenSevenHapiFhirDialect.class.getName());
|
||||
} else {
|
||||
extraProperties.put("hibernate.dialect", PostgreSQL94Dialect.class.getName());
|
||||
}
|
||||
extraProperties.put("hibernate.format_sql", "false");
|
||||
extraProperties.put("hibernate.show_sql", "false");
|
||||
extraProperties.put("hibernate.hbm2ddl.auto", "update");
|
||||
extraProperties.put("hibernate.jdbc.batch_size", "20");
|
||||
extraProperties.put("hibernate.cache.use_query_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
extraProperties.put("hibernate.cache.use_structured_entries", "false");
|
||||
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
|
||||
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
|
||||
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
return extraProperties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bean which validates incoming requests
|
||||
*/
|
||||
@Bean
|
||||
@Lazy
|
||||
public RequestValidatingInterceptor requestValidatingInterceptor() {
|
||||
RequestValidatingInterceptor requestValidator = new RequestValidatingInterceptor();
|
||||
requestValidator.setFailOnSeverity(null);
|
||||
requestValidator.setAddResponseHeaderOnSeverity(null);
|
||||
requestValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
|
||||
requestValidator.addValidatorModule(instanceValidatorR5());
|
||||
requestValidator.setIgnoreValidatorExceptions(true);
|
||||
|
||||
return requestValidator;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PublicSecurityInterceptor securityInterceptor() {
|
||||
return new PublicSecurityInterceptor();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
|
||||
JpaTransactionManager retVal = new JpaTransactionManager();
|
||||
retVal.setEntityManagerFactory(entityManagerFactory);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* This lets the "@Value" fields reference properties from the properties file
|
||||
*/
|
||||
@Bean
|
||||
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
|
||||
return new PropertySourcesPlaceholderConfigurer();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -40,6 +40,20 @@
|
|||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServletR5</servlet-name>
|
||||
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
|
||||
<init-param>
|
||||
<param-name>ImplementationDescription</param-name>
|
||||
<param-value>UHN Test Server (R5 Resources)</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>FhirVersion</param-name>
|
||||
<param-value>R5</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServletR4</servlet-name>
|
||||
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
|
||||
|
@ -111,16 +125,18 @@
|
|||
</servlet>
|
||||
-->
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServletR5</servlet-name>
|
||||
<url-pattern>/baseR5/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServletR4</servlet-name>
|
||||
<url-pattern>/baseR4/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServletDstu2</servlet-name>
|
||||
<url-pattern>/baseDstu2/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServletDstu3</servlet-name>
|
||||
<url-pattern>/baseDstu2.1/*</url-pattern>
|
||||
|
|
|
@ -175,7 +175,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theProfileName) {
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import com.github.benmanes.caffeine.cache.Caffeine;
|
|||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.fhir.ucum.UcumService;
|
||||
import org.hl7.fhir.exceptions.DefinitionException;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r4.context.IWorkerContext;
|
||||
|
@ -26,6 +27,7 @@ import org.hl7.fhir.r4.terminologies.ValueSetExpander;
|
|||
import org.hl7.fhir.r4.terminologies.ValueSetExpanderFactory;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpanderSimple;
|
||||
import org.hl7.fhir.r4.utils.IResourceValidator;
|
||||
import org.hl7.fhir.utilities.TerminologyServiceOptions;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
|
@ -61,6 +63,11 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
return myValidationSupport.fetchAllStructureDefinitions(myCtx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> getStructures() {
|
||||
return allStructures();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(String theSystem) {
|
||||
if (myValidationSupport == null) {
|
||||
|
@ -149,9 +156,9 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(CodeableConcept theCode, ValueSet theVs) {
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, CodeableConcept theCode, ValueSet theVs) {
|
||||
for (Coding next : theCode.getCoding()) {
|
||||
ValidationResult retVal = validateCode(next, theVs);
|
||||
ValidationResult retVal = validateCode(theOptions, next, theVs);
|
||||
if (retVal != null && retVal.isOk()) {
|
||||
return retVal;
|
||||
}
|
||||
|
@ -161,15 +168,15 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(Coding theCode, ValueSet theVs) {
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, Coding theCode, ValueSet theVs) {
|
||||
String system = theCode.getSystem();
|
||||
String code = theCode.getCode();
|
||||
String display = theCode.getDisplay();
|
||||
return validateCode(system, code, display, theVs);
|
||||
return validateCode(theOptions, system, code, display, theVs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(String theSystem, String theCode, String theDisplay) {
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String theSystem, String theCode, String theDisplay) {
|
||||
CodeValidationResult result = myValidationSupport.validateCode(myCtx, theSystem, theCode, theDisplay);
|
||||
if (result == null) {
|
||||
return null;
|
||||
|
@ -178,12 +185,12 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(String theSystem, String theCode, String theDisplay, ConceptSetComponent theVsi) {
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String theSystem, String theCode, String theDisplay, ConceptSetComponent theVsi) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(String theSystem, String theCode, String theDisplay, ValueSet theVs) {
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String theSystem, String theCode, String theDisplay, ValueSet theVs) {
|
||||
|
||||
if (theVs != null && isNotBlank(theCode)) {
|
||||
for (ConceptSetComponent next : theVs.getCompose().getInclude()) {
|
||||
|
@ -264,8 +271,8 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(String code, ValueSet vs) {
|
||||
return validateCode(null, code, null, vs);
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String code, ValueSet vs) {
|
||||
return validateCode(theOptions, null, code, null, vs);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -274,6 +281,11 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateSnapshot(StructureDefinition p) throws DefinitionException, FHIRException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters getExpansionParameters() {
|
||||
return myExpansionProfile;
|
||||
|
|
|
@ -78,12 +78,9 @@ public interface IValidationSupport
|
|||
/**
|
||||
* Generate a snapshot from the given differential profile.
|
||||
*
|
||||
* @param theInput
|
||||
* @param theUrl
|
||||
* @param theProfileName
|
||||
* @return Returns null if this module does not know how to handle this request
|
||||
*/
|
||||
StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theProfileName);
|
||||
StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName);
|
||||
|
||||
/**
|
||||
* Validates that the given code exists and if possible returns a display
|
||||
|
|
|
@ -1309,29 +1309,6 @@ public class ClientR4Test {
|
|||
retVal.addEntry().setResource(p);
|
||||
|
||||
return theCtx.newXmlParser().encodeResourceToString(retVal);
|
||||
|
||||
// String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
|
||||
// "<title/>\n" +
|
||||
// "<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" +
|
||||
// "<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" +
|
||||
// "<author>\n" +
|
||||
// "<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" +
|
||||
// "</author>\n" +
|
||||
// "<entry>\n" +
|
||||
// "<content type=\"text/xml\">"
|
||||
// + "<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||
// + "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>"
|
||||
// + "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>"
|
||||
// + "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>"
|
||||
// + "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>"
|
||||
// + "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>"
|
||||
// + "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>"
|
||||
// + "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />"
|
||||
// + "</Patient>"
|
||||
// + "</content>\n"
|
||||
// + " </entry>\n"
|
||||
// + "</feed>";
|
||||
// return msg;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,329 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-structures-r5</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<name>HAPI FHIR Structures - FHIR R5</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.utilities</artifactId>
|
||||
<version>${fhir_core_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>org.hl7.fhir.r5</artifactId>
|
||||
<version>${fhir_core_version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.fhir</groupId>
|
||||
<artifactId>ucum</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Optional dependencies from RI codebase
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>org.codehaus.woodstox</groupId>
|
||||
<artifactId>woodstox-core-asl</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>es.nitaur.markdown</groupId>
|
||||
<artifactId>txtmark</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.antlr</groupId>
|
||||
<artifactId>ST4</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>xpp3</groupId>
|
||||
<artifactId>xpp3</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Used by the validator -->
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!--
|
||||
Test dependencies on other optional parts of HAPI
|
||||
-->
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-validation-resources-r5</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-client</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-server</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.servlet</groupId>
|
||||
<artifactId>javax.servlet-api</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
<dependency>
|
||||
<groupId>org.xmlunit</groupId>
|
||||
<artifactId>xmlunit-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlets</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-servlet</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-server</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-util</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-http</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<optional>true</optional>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.thymeleaf</groupId>
|
||||
<artifactId>thymeleaf</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-test-utilities</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- Dependencies for Schematron -->
|
||||
<dependency>
|
||||
<groupId>com.helger</groupId>
|
||||
<artifactId>ph-schematron</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.helger</groupId>
|
||||
<artifactId>ph-commons</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.activation</groupId>
|
||||
<artifactId>javax.activation-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>javax.xml.bind</groupId>
|
||||
<artifactId>jaxb-api</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.sun.xml.bind</groupId>-->
|
||||
<!--<artifactId>jaxb-core</artifactId>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
<!--<dependency>-->
|
||||
<!--<groupId>com.sun.xml.bind</groupId>-->
|
||||
<!--<artifactId>jaxb-impl</artifactId>-->
|
||||
<!--<scope>test</scope>-->
|
||||
<!--</dependency>-->
|
||||
<dependency>
|
||||
<groupId>org.glassfish.jaxb</groupId>
|
||||
<artifactId>jaxb-runtime</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- UNIT TEST DEPENDENCIES -->
|
||||
<dependency>
|
||||
<groupId>net.sf.json-lib</groupId>
|
||||
<artifactId>json-lib</artifactId>
|
||||
<classifier>jdk15</classifier>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<groupId>commons-lang</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>net.sf.json-lib</groupId>
|
||||
<artifactId>json-lib</artifactId>
|
||||
<classifier>jdk15-sources</classifier>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>directory-naming</groupId>
|
||||
<artifactId>naming-java</artifactId>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>commons-logging</artifactId>
|
||||
<groupId>commons-logging</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava-testlib</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<reporting>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<show>public</show>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</reporting>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jacoco</groupId>
|
||||
<artifactId>jacoco-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<classFolders>
|
||||
<classFolder>${basedir}/target/classes</classFolder>
|
||||
<classFolder>${basedir}/../hapi-fhir-base/target/classes</classFolder>
|
||||
<classFolder>${basedir}/../hapi-fhir-client/target/classes</classFolder>
|
||||
<classFolder>${basedir}/../hapi-fhir-server/target/classes</classFolder>
|
||||
</classFolders>
|
||||
<sourceFolders>
|
||||
<sourceFolder>${basedir}/src/main/java</sourceFolder>
|
||||
<sourceFolder>${basedir}/../hapi-fhir-base/src/main/java</sourceFolder>
|
||||
<sourceFolder>${basedir}/../hapi-fhir-client/src/main/java</sourceFolder>
|
||||
<sourceFolder>${basedir}/../hapi-fhir-server/src/main/java</sourceFolder>
|
||||
</sourceFolders>
|
||||
<dumpOnExit>true</dumpOnExit>
|
||||
</configuration>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-prepare-agent</id>
|
||||
<goals>
|
||||
<goal>prepare-agent</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-surefire-plugin</artifactId>
|
||||
<configuration>
|
||||
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>license-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<!-- Don't add UHN licenses to RI structures -->
|
||||
<skipUpdateLicense>true</skipUpdateLicense>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<configuration>
|
||||
<fork>true</fork>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Fragment-Host>
|
||||
ca.uhn.hapi.fhir.hapi-fhir-base
|
||||
</Fragment-Host>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
|
@ -0,0 +1,321 @@
|
|||
package org.hl7.fhir.r5.hapi.ctx;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
|
||||
private static final String URL_PREFIX_VALUE_SET = "http://hl7.org/fhir/ValueSet/";
|
||||
private static final String URL_PREFIX_STRUCTURE_DEFINITION = "http://hl7.org/fhir/StructureDefinition/";
|
||||
private static final String URL_PREFIX_STRUCTURE_DEFINITION_BASE = "http://hl7.org/fhir/";
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultProfileValidationSupport.class);
|
||||
|
||||
private Map<String, CodeSystem> myCodeSystems;
|
||||
private Map<String, StructureDefinition> myStructureDefinitions;
|
||||
private Map<String, ValueSet> myValueSets;
|
||||
|
||||
private void addConcepts(ConceptSetComponent theInclude, ValueSetExpansionComponent theRetVal, Set<String> theWantCodes, List<ConceptDefinitionComponent> theConcepts) {
|
||||
for (ConceptDefinitionComponent next : theConcepts) {
|
||||
if (theWantCodes.isEmpty() || theWantCodes.contains(next.getCode())) {
|
||||
theRetVal
|
||||
.addContains()
|
||||
.setSystem(theInclude.getSystem())
|
||||
.setCode(next.getCode())
|
||||
.setDisplay(next.getDisplay());
|
||||
}
|
||||
addConcepts(theInclude, theRetVal, theWantCodes, next.getConcept());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
ValueSetExpander.ValueSetExpansionOutcome retVal = new ValueSetExpander.ValueSetExpansionOutcome(new ValueSet());
|
||||
|
||||
Set<String> wantCodes = new HashSet<>();
|
||||
for (ConceptReferenceComponent next : theInclude.getConcept()) {
|
||||
wantCodes.add(next.getCode());
|
||||
}
|
||||
|
||||
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
|
||||
if (system != null) {
|
||||
List<ConceptDefinitionComponent> concepts = system.getConcept();
|
||||
addConcepts(theInclude, retVal.getValueset().getExpansion(), wantCodes, concepts);
|
||||
}
|
||||
|
||||
for (UriType next : theInclude.getValueSet()) {
|
||||
ValueSet vs = myValueSets.get(defaultString(next.getValueAsString()));
|
||||
if (vs != null) {
|
||||
for (ConceptSetComponent nextInclude : vs.getCompose().getInclude()) {
|
||||
ValueSetExpander.ValueSetExpansionOutcome contents = expandValueSet(theContext, nextInclude);
|
||||
retVal.getValueset().getExpansion().getContains().addAll(contents.getValueset().getExpansion().getContains());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||
retVal.addAll(myCodeSystems.values());
|
||||
retVal.addAll(myStructureDefinitions.values());
|
||||
retVal.addAll(myValueSets.values());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<>(provideStructureDefinitionMap(theContext).values());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return (CodeSystem) fetchCodeSystemOrValueSet(theContext, theSystem, true);
|
||||
}
|
||||
|
||||
private DomainResource fetchCodeSystemOrValueSet(FhirContext theContext, String theSystem, boolean codeSystem) {
|
||||
synchronized (this) {
|
||||
Map<String, CodeSystem> codeSystems = myCodeSystems;
|
||||
Map<String, ValueSet> valueSets = myValueSets;
|
||||
if (codeSystems == null || valueSets == null) {
|
||||
codeSystems = new HashMap<>();
|
||||
valueSets = new HashMap<>();
|
||||
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r5/model/valueset/valuesets.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r5/model/valueset/v2-tables.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r5/model/valueset/v3-codesystems.xml");
|
||||
|
||||
myCodeSystems = codeSystems;
|
||||
myValueSets = valueSets;
|
||||
}
|
||||
|
||||
// System can take the form "http://url|version"
|
||||
String system = theSystem;
|
||||
if (system.contains("|")) {
|
||||
String version = system.substring(system.indexOf('|') + 1);
|
||||
if (version.matches("^[0-9.]+$")) {
|
||||
system = system.substring(0, system.indexOf('|'));
|
||||
}
|
||||
}
|
||||
|
||||
if (codeSystem) {
|
||||
return codeSystems.get(system);
|
||||
} else {
|
||||
return valueSets.get(system);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
Validate.notBlank(theUri, "theUri must not be null or blank");
|
||||
|
||||
if (theClass.equals(StructureDefinition.class)) {
|
||||
return (T) fetchStructureDefinition(theContext, theUri);
|
||||
}
|
||||
|
||||
if (theClass.equals(ValueSet.class) || theUri.startsWith(URL_PREFIX_VALUE_SET)) {
|
||||
return (T) fetchValueSet(theContext, theUri);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theContext, String theUrl) {
|
||||
String url = theUrl;
|
||||
if (url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) {
|
||||
// no change
|
||||
} else if (url.indexOf('/') == -1) {
|
||||
url = URL_PREFIX_STRUCTURE_DEFINITION + url;
|
||||
} else if (StringUtils.countMatches(url, '/') == 1) {
|
||||
url = URL_PREFIX_STRUCTURE_DEFINITION_BASE + url;
|
||||
}
|
||||
return provideStructureDefinitionMap(theContext).get(url);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet fetchValueSet(FhirContext theContext, String uri) {
|
||||
return (ValueSet) fetchCodeSystemOrValueSet(theContext, uri, false);
|
||||
}
|
||||
|
||||
public void flush() {
|
||||
myCodeSystems = null;
|
||||
myStructureDefinitions = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theSystem);
|
||||
return cs != null && cs.getContent() != CodeSystemContentMode.NOTPRESENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void loadCodeSystems(FhirContext theContext, Map<String, CodeSystem> theCodeSystems, Map<String, ValueSet> theValueSets, String theClasspath) {
|
||||
ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath);
|
||||
InputStream inputStream = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
|
||||
InputStreamReader reader = null;
|
||||
if (inputStream != null) {
|
||||
try {
|
||||
reader = new InputStreamReader(inputStream, Constants.CHARSET_UTF8);
|
||||
|
||||
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
|
||||
for (BundleEntryComponent next : bundle.getEntry()) {
|
||||
if (next.getResource() instanceof CodeSystem) {
|
||||
CodeSystem nextValueSet = (CodeSystem) next.getResource();
|
||||
nextValueSet.getText().setDivAsString("");
|
||||
String system = nextValueSet.getUrl();
|
||||
if (isNotBlank(system)) {
|
||||
theCodeSystems.put(system, nextValueSet);
|
||||
}
|
||||
} else if (next.getResource() instanceof ValueSet) {
|
||||
ValueSet nextValueSet = (ValueSet) next.getResource();
|
||||
nextValueSet.getText().setDivAsString("");
|
||||
String system = nextValueSet.getUrl();
|
||||
if (isNotBlank(system)) {
|
||||
theValueSets.put(system, nextValueSet);
|
||||
}
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
try {
|
||||
if (reader != null) {
|
||||
reader.close();
|
||||
}
|
||||
inputStream.close();
|
||||
} catch (IOException e) {
|
||||
ourLog.warn("Failure closing stream", e);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ourLog.warn("Unable to load resource: {}", theClasspath);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadStructureDefinitions(FhirContext theContext, Map<String, StructureDefinition> theCodeSystems, String theClasspath) {
|
||||
ourLog.info("Loading structure definitions from classpath: {}", theClasspath);
|
||||
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
|
||||
if (valuesetText != null) {
|
||||
InputStreamReader reader = new InputStreamReader(valuesetText, Constants.CHARSET_UTF8);
|
||||
|
||||
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
|
||||
for (BundleEntryComponent next : bundle.getEntry()) {
|
||||
if (next.getResource() instanceof StructureDefinition) {
|
||||
StructureDefinition nextSd = (StructureDefinition) next.getResource();
|
||||
nextSd.getText().setDivAsString("");
|
||||
String system = nextSd.getUrl();
|
||||
if (isNotBlank(system)) {
|
||||
theCodeSystems.put(system, nextSd);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ourLog.warn("Unable to load resource: {}", theClasspath);
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, StructureDefinition> provideStructureDefinitionMap(FhirContext theContext) {
|
||||
Map<String, StructureDefinition> structureDefinitions = myStructureDefinitions;
|
||||
if (structureDefinitions == null) {
|
||||
structureDefinitions = new HashMap<>();
|
||||
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/r5/model/profile/profiles-resources.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/r5/model/profile/profiles-types.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/r5/model/profile/profiles-others.xml");
|
||||
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/r5/model/extension/extension-definitions.xml");
|
||||
|
||||
myStructureDefinitions = structureDefinitions;
|
||||
}
|
||||
return structureDefinitions;
|
||||
}
|
||||
|
||||
private CodeValidationResult testIfConceptIsInList(CodeSystem theCodeSystem, String theCode, List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive) {
|
||||
String code = theCode;
|
||||
if (theCaseSensitive == false) {
|
||||
code = code.toUpperCase();
|
||||
}
|
||||
|
||||
return testIfConceptIsInListInner(theCodeSystem, conceptList, theCaseSensitive, code);
|
||||
}
|
||||
|
||||
private CodeValidationResult testIfConceptIsInListInner(CodeSystem theCodeSystem, List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive, String code) {
|
||||
CodeValidationResult retVal = null;
|
||||
for (ConceptDefinitionComponent next : conceptList) {
|
||||
String nextCandidate = next.getCode();
|
||||
if (theCaseSensitive == false) {
|
||||
nextCandidate = nextCandidate.toUpperCase();
|
||||
}
|
||||
if (nextCandidate.equals(code)) {
|
||||
retVal = new CodeValidationResult(next);
|
||||
break;
|
||||
}
|
||||
|
||||
// recurse
|
||||
retVal = testIfConceptIsInList(theCodeSystem, code, next.getConcept(), theCaseSensitive);
|
||||
if (retVal != null) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (retVal != null) {
|
||||
retVal.setCodeSystemName(theCodeSystem.getName());
|
||||
retVal.setCodeSystemVersion(theCodeSystem.getVersion());
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
|
||||
if (cs != null) {
|
||||
boolean caseSensitive = true;
|
||||
if (cs.hasCaseSensitive()) {
|
||||
caseSensitive = cs.getCaseSensitive();
|
||||
}
|
||||
|
||||
CodeValidationResult retVal = testIfConceptIsInList(cs, theCode, cs.getConcept(), caseSensitive);
|
||||
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IContextValidationSupport.LookupCodeResult lookupCode(FhirContext theContext, String theSystem, String theCode) {
|
||||
return validateCode(theContext, theSystem, theCode, null).asLookupCodeResult(theSystem, theCode);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
package org.hl7.fhir.r5.hapi.ctx;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||
import ca.uhn.fhir.model.api.IFhirVersion;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.util.ReflectionUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.r5.hapi.fhirpath.FhirPathR5;
|
||||
import org.hl7.fhir.r5.hapi.rest.server.R5BundleFactory;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
public class FhirR5 implements IFhirVersion {
|
||||
|
||||
private String myId;
|
||||
|
||||
@Override
|
||||
public IFluentPath createFluentPathExecutor(FhirContext theFhirContext) {
|
||||
return new FhirPathR5(theFhirContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IContextValidationSupport<?, ?, ?, ?, ?, ?> createValidationSupport() {
|
||||
return ReflectionUtil.newInstanceOfFhirProfileValidationSupport("org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase) {
|
||||
StructureDefinition retVal = new StructureDefinition();
|
||||
|
||||
RuntimeResourceDefinition def = theRuntimeResourceDefinition;
|
||||
|
||||
myId = def.getId();
|
||||
if (StringUtils.isBlank(myId)) {
|
||||
myId = theRuntimeResourceDefinition.getName().toLowerCase();
|
||||
}
|
||||
|
||||
retVal.setId(new IdDt(myId));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Override
|
||||
public Class<List> getContainedType() {
|
||||
return List.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getFhirVersionPropertiesFile() {
|
||||
String path = "org/hl7/fhir/r5/model/fhirversion.properties";
|
||||
InputStream str = FhirR5.class.getResourceAsStream("/" + path);
|
||||
if (str == null) {
|
||||
str = FhirR5.class.getResourceAsStream(path);
|
||||
}
|
||||
if (str == null) {
|
||||
throw new ConfigurationException("Can not find model property file on classpath: " + path);
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IPrimitiveType<Date> getLastUpdated(IBaseResource theResource) {
|
||||
return ((Resource) theResource).getMeta().getLastUpdatedElement();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPathToSchemaDefinitions() {
|
||||
return "/org/hl7/fhir/r5/model/schema";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseReference> getResourceReferenceType() {
|
||||
return Reference.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getServerVersion() {
|
||||
return ReflectionUtil.newInstanceOfFhirServerType("org.hl7.fhir.r5.hapi.ctx.FhirServerR5");
|
||||
}
|
||||
|
||||
@Override
|
||||
public FhirVersionEnum getVersion() {
|
||||
return FhirVersionEnum.R5;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext) {
|
||||
return new R5BundleFactory(theContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseCoding newCodingDt() {
|
||||
return new Coding();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IIdType newIdType() {
|
||||
return new IdType();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
package org.hl7.fhir.r5.hapi.ctx;
|
||||
|
||||
import ca.uhn.fhir.rest.api.server.IFhirVersionServer;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import org.hl7.fhir.r5.hapi.rest.server.ServerCapabilityStatementProvider;
|
||||
import org.hl7.fhir.r5.hapi.rest.server.ServerProfileProvider;
|
||||
|
||||
public class FhirServerR5 implements IFhirVersionServer {
|
||||
@Override
|
||||
public ServerCapabilityStatementProvider createServerConformanceProvider(RestfulServer theServer) {
|
||||
return new ServerCapabilityStatementProvider(theServer);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer) {
|
||||
return new ServerProfileProvider(theRestfulServer);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,441 @@
|
|||
package org.hl7.fhir.r5.hapi.ctx;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import com.github.benmanes.caffeine.cache.Cache;
|
||||
import com.github.benmanes.caffeine.cache.Caffeine;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.fhir.ucum.UcumService;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.exceptions.TerminologyServiceException;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.formats.IParser;
|
||||
import org.hl7.fhir.r5.formats.ParserType;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport.CodeValidationResult;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.ElementDefinition.ElementDefinitionBindingComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ValueSetExpansionContainsComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpanderFactory;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpanderSimple;
|
||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||
import org.hl7.fhir.utilities.TerminologyServiceOptions;
|
||||
import org.hl7.fhir.utilities.TranslationServices;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander, ValueSetExpanderFactory {
|
||||
private final FhirContext myCtx;
|
||||
private final Cache<String, Resource> myFetchedResourceCache;
|
||||
private IValidationSupport myValidationSupport;
|
||||
private Parameters myExpansionProfile;
|
||||
private String myOverrideVersionNs;
|
||||
|
||||
public HapiWorkerContext(FhirContext theCtx, IValidationSupport theValidationSupport) {
|
||||
Validate.notNull(theCtx, "theCtx must not be null");
|
||||
Validate.notNull(theValidationSupport, "theValidationSupport must not be null");
|
||||
myCtx = theCtx;
|
||||
myValidationSupport = theValidationSupport;
|
||||
|
||||
long timeoutMillis = 10 * DateUtils.MILLIS_PER_SECOND;
|
||||
if (System.getProperties().containsKey(Constants.TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS)) {
|
||||
timeoutMillis = Long.parseLong(System.getProperty(Constants.TEST_SYSTEM_PROP_VALIDATION_RESOURCE_CACHES_MS));
|
||||
}
|
||||
|
||||
myFetchedResourceCache = Caffeine.newBuilder().expireAfterWrite(timeoutMillis, TimeUnit.MILLISECONDS).build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> allStructures() {
|
||||
return myValidationSupport.fetchAllStructureDefinitions(myCtx);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> getStructures() {
|
||||
return allStructures();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(String theSystem) {
|
||||
if (myValidationSupport == null) {
|
||||
return null;
|
||||
} else {
|
||||
return myValidationSupport.fetchCodeSystem(myCtx, theSystem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<ConceptMap> findMapsForSource(String theUrl) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getAbbreviation(String theName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpander getExpander() {
|
||||
ValueSetExpanderSimple retVal = new ValueSetExpanderSimple(this);
|
||||
retVal.setMaxExpansionSize(Integer.MAX_VALUE);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r5.utils.INarrativeGenerator getNarrativeGenerator(String thePrefix, String theBasePath) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser getParser(ParserType theType) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser getParser(String theType) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getResourceNames() {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (ResourceType next : ResourceType.values()) {
|
||||
result.add(next.name());
|
||||
}
|
||||
Collections.sort(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser newJsonParser() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IResourceValidator newValidator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IParser newXmlParser() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String oid2Uri(String theCode) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSystem(String theSystem) {
|
||||
if (myValidationSupport == null) {
|
||||
return false;
|
||||
} else {
|
||||
return myValidationSupport.isCodeSystemSupported(myCtx, theSystem);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> typeTails() {
|
||||
return new HashSet<>(Arrays.asList("Integer", "UnsignedInt", "PositiveInt", "Decimal", "DateTime", "Date", "Time", "Instant", "String", "Uri", "Oid", "Uuid", "Id", "Boolean", "Code",
|
||||
"Markdown", "Base64Binary", "Coding", "CodeableConcept", "Attachment", "Identifier", "Quantity", "SampledData", "Range", "Period", "Ratio", "HumanName", "Address", "ContactPoint",
|
||||
"Timing", "Reference", "Annotation", "Signature", "Meta"));
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, CodeableConcept theCode, ValueSet theVs) {
|
||||
for (Coding next : theCode.getCoding()) {
|
||||
ValidationResult retVal = validateCode(theOptions, next, theVs);
|
||||
if (retVal != null && retVal.isOk()) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new ValidationResult(IssueSeverity.ERROR, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, Coding theCode, ValueSet theVs) {
|
||||
String system = theCode.getSystem();
|
||||
String code = theCode.getCode();
|
||||
String display = theCode.getDisplay();
|
||||
return validateCode(theOptions, system, code, display, theVs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String theSystem, String theCode, String theDisplay) {
|
||||
CodeValidationResult result = myValidationSupport.validateCode(myCtx, theSystem, theCode, theDisplay);
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
return new ValidationResult(result.getSeverity(), result.getMessage(), result.asConceptDefinition());
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String theSystem, String theCode, String theDisplay, ConceptSetComponent theVsi) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String theSystem, String theCode, String theDisplay, ValueSet theVs) {
|
||||
|
||||
if (theVs != null && isNotBlank(theCode)) {
|
||||
for (ConceptSetComponent next : theVs.getCompose().getInclude()) {
|
||||
if (isBlank(theSystem) || theSystem.equals(next.getSystem())) {
|
||||
for (ConceptReferenceComponent nextCode : next.getConcept()) {
|
||||
if (theCode.equals(nextCode.getCode())) {
|
||||
CodeType code = new CodeType(theCode);
|
||||
return new ValidationResult(new ConceptDefinitionComponent(code));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
boolean caseSensitive = true;
|
||||
if (isNotBlank(theSystem)) {
|
||||
CodeSystem system = fetchCodeSystem(theSystem);
|
||||
if (system == null) {
|
||||
return new ValidationResult(IssueSeverity.INFORMATION, "Code " + theSystem + "/" + theCode + " was not validated because the code system is not present");
|
||||
}
|
||||
|
||||
if (system.hasCaseSensitive()) {
|
||||
caseSensitive = system.getCaseSensitive();
|
||||
}
|
||||
}
|
||||
|
||||
String wantCode = theCode;
|
||||
if (!caseSensitive) {
|
||||
wantCode = wantCode.toUpperCase();
|
||||
}
|
||||
|
||||
ValueSetExpansionOutcome expandedValueSet = null;
|
||||
|
||||
/*
|
||||
* The following valueset is a special case, since the BCP codesystem is very difficult to expand
|
||||
*/
|
||||
if (theVs != null && "http://hl7.org/fhir/ValueSet/languages".equals(theVs.getId())) {
|
||||
ValueSet expansion = new ValueSet();
|
||||
for (ConceptSetComponent nextInclude : theVs.getCompose().getInclude()) {
|
||||
for (ConceptReferenceComponent nextConcept : nextInclude.getConcept()) {
|
||||
expansion.getExpansion().addContains().setCode(nextConcept.getCode()).setDisplay(nextConcept.getDisplay());
|
||||
}
|
||||
}
|
||||
expandedValueSet = new ValueSetExpansionOutcome(expansion);
|
||||
}
|
||||
|
||||
/*
|
||||
* The following valueset is a special case, since the mime types codesystem is very difficult to expand
|
||||
*/
|
||||
if (theVs != null && "http://hl7.org/fhir/ValueSet/mimetypes".equals(theVs.getId())) {
|
||||
ValueSet expansion = new ValueSet();
|
||||
expansion.getExpansion().addContains().setCode(theCode).setSystem(theSystem).setDisplay(theDisplay);
|
||||
expandedValueSet = new ValueSetExpansionOutcome(expansion);
|
||||
}
|
||||
|
||||
if (expandedValueSet == null) {
|
||||
expandedValueSet = expand(theVs, null);
|
||||
}
|
||||
|
||||
for (ValueSetExpansionContainsComponent next : expandedValueSet.getValueset().getExpansion().getContains()) {
|
||||
String nextCode = next.getCode();
|
||||
if (!caseSensitive) {
|
||||
nextCode = nextCode.toUpperCase();
|
||||
}
|
||||
|
||||
if (nextCode.equals(wantCode)) {
|
||||
if (theSystem == null || next.getSystem().equals(theSystem)) {
|
||||
ConceptDefinitionComponent definition = new ConceptDefinitionComponent();
|
||||
definition.setCode(next.getCode());
|
||||
definition.setDisplay(next.getDisplay());
|
||||
ValidationResult retVal = new ValidationResult(definition);
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return new ValidationResult(IssueSeverity.ERROR, "Unknown code[" + theCode + "] in system[" + theSystem + "]");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValidationResult validateCode(TerminologyServiceOptions theOptions, String code, ValueSet vs) {
|
||||
return validateCode(theOptions, null, code, null, vs);
|
||||
}
|
||||
|
||||
@Override
|
||||
@CoverageIgnore
|
||||
public List<MetadataResource> allConformanceResources() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateSnapshot(StructureDefinition p) throws FHIRException {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameters getExpansionParameters() {
|
||||
return myExpansionProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpansionProfile(Parameters theExpParameters) {
|
||||
myExpansionProfile = theExpParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
@CoverageIgnore
|
||||
public boolean hasCache() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expand(ValueSet theSource, Parameters theProfile) {
|
||||
ValueSetExpansionOutcome vso;
|
||||
try {
|
||||
vso = getExpander().expand(theSource, theProfile);
|
||||
} catch (InvalidRequestException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
if (vso.getError() != null) {
|
||||
throw new InvalidRequestException(vso.getError());
|
||||
} else {
|
||||
return vso;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expandVS(ValueSet theSource, boolean theCacheOk, boolean theHeiarchical) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expandVS(ConceptSetComponent theInc, boolean theHeiarchical) throws TerminologyServiceException {
|
||||
return myValidationSupport.expandValueSet(myCtx, theInc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ILoggingService getLogger() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogger(ILoggingService theLogger) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getVersion() {
|
||||
return myCtx.getVersion().getVersion().getFhirVersionString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public UcumService getUcumService() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUcumService(UcumService ucumService) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNoTerminologyServer() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TranslationServices translator() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureMap> listTransforms() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureMap getTransform(String url) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getOverrideVersionNs() {
|
||||
return myOverrideVersionNs;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverrideVersionNs(String value) {
|
||||
myOverrideVersionNs = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchTypeDefinition(String typeName) {
|
||||
return fetchResource(StructureDefinition.class, "http://hl7.org/fhir/StructureDefinition/" + typeName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getTypeNames() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends org.hl7.fhir.r5.model.Resource> T fetchResource(Class<T> theClass, String theUri) {
|
||||
if (myValidationSupport == null) {
|
||||
return null;
|
||||
} else {
|
||||
@SuppressWarnings("unchecked")
|
||||
T retVal = (T) myFetchedResourceCache.get(theUri, t -> myValidationSupport.fetchResource(myCtx, theClass, theUri));
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends org.hl7.fhir.r5.model.Resource> T fetchResourceWithException(Class<T> theClass, String theUri) throws FHIRException {
|
||||
T retVal = fetchResource(theClass, theUri);
|
||||
if (retVal == null) {
|
||||
throw new FHIRException("Could not find resource: " + theUri);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hl7.fhir.r5.model.Resource fetchResourceById(String theType, String theUri) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends org.hl7.fhir.r5.model.Resource> boolean hasResource(Class<T> theClass_, String theUri) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void cacheResource(org.hl7.fhir.r5.model.Resource theRes) throws FHIRException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getResourceNamesAsSet() {
|
||||
return myCtx.getResourceNames();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionOutcome expandVS(ElementDefinitionBindingComponent theBinding, boolean theCacheOk, boolean theHeiarchical) throws FHIRException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package org.hl7.fhir.r5.hapi.ctx;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.support.IContextValidationSupport;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.CodeSystem;
|
||||
import org.hl7.fhir.r5.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
import org.hl7.fhir.r5.model.ValueSet;
|
||||
import org.hl7.fhir.r5.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r5.terminologies.ValueSetExpander;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface IValidationSupport
|
||||
extends IContextValidationSupport<ConceptSetComponent, ValueSetExpander.ValueSetExpansionOutcome, StructureDefinition, CodeSystem, ConceptDefinitionComponent, IssueSeverity> {
|
||||
|
||||
/**
|
||||
* Expands the given portion of a ValueSet
|
||||
*
|
||||
* @param theInclude The portion to include
|
||||
* @return The expansion
|
||||
*/
|
||||
@Override
|
||||
ValueSetExpander.ValueSetExpansionOutcome expandValueSet(FhirContext theContext, ConceptSetComponent theInclude);
|
||||
|
||||
/**
|
||||
* Load and return all possible structure definitions
|
||||
*/
|
||||
@Override
|
||||
List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext);
|
||||
|
||||
/**
|
||||
* Fetch a code system by Uri
|
||||
*
|
||||
* @param uri Canonical Uri of the code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
@Override
|
||||
CodeSystem fetchCodeSystem(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Fetch a valueset by Uri
|
||||
*
|
||||
* @param uri Canonical Uri of the ValueSet
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
ValueSet fetchValueSet(FhirContext theContext, String uri);
|
||||
|
||||
/**
|
||||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||
* ValueSet)
|
||||
*
|
||||
* @param theContext The HAPI FHIR Context object current in use by the validator
|
||||
* @param theClass The type of the resource to load
|
||||
* @param theUri The resource URI
|
||||
* @return Returns the resource, or <code>null</code> if no resource with the
|
||||
* given URI can be found
|
||||
*/
|
||||
@Override
|
||||
<T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri);
|
||||
|
||||
@Override
|
||||
StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl);
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if codes in the given code system can be expanded
|
||||
* or validated
|
||||
*
|
||||
* @param theSystem The URI for the code system, e.g. <code>"http://loinc.org"</code>
|
||||
* @return Returns <code>true</code> if codes in the given code system can be
|
||||
* validated
|
||||
*/
|
||||
@Override
|
||||
boolean isCodeSystemSupported(FhirContext theContext, String theSystem);
|
||||
|
||||
/**
|
||||
* Generate a snapshot from the given differential profile.
|
||||
*
|
||||
* @param theInput
|
||||
* @param theUrl
|
||||
* @param theWebUrl
|
||||
* @param theProfileName
|
||||
* @return Returns null if this module does not know how to handle this request
|
||||
*/
|
||||
StructureDefinition generateSnapshot(StructureDefinition theInput, String theUrl, String theWebUrl, String theProfileName);
|
||||
|
||||
/**
|
||||
* Validates that the given code exists and if possible returns a display
|
||||
* name. This method is called to check codes which are found in "example"
|
||||
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||
*
|
||||
* @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>"
|
||||
* @param theCode The code, e.g. "<code>1234-5</code>"
|
||||
* @param theDisplay The display name, if it should also be validated
|
||||
* @return Returns a validation result object
|
||||
*/
|
||||
@Override
|
||||
CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
|
||||
|
||||
class CodeValidationResult extends IContextValidationSupport.CodeValidationResult<ConceptDefinitionComponent, IssueSeverity> {
|
||||
|
||||
public CodeValidationResult(ConceptDefinitionComponent theNext) {
|
||||
super(theNext);
|
||||
}
|
||||
|
||||
public CodeValidationResult(IssueSeverity theSeverity, String theMessage) {
|
||||
super(theSeverity, theMessage);
|
||||
}
|
||||
|
||||
public CodeValidationResult(IssueSeverity severity, String message, ConceptDefinitionComponent definition) {
|
||||
super(severity, message, definition);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getDisplay() {
|
||||
String retVal = null;
|
||||
if (isOk()) {
|
||||
retVal = asConceptDefinition().getDisplay();
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
package org.hl7.fhir.r5.hapi.fhirpath;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.fluentpath.FluentPathExecutionException;
|
||||
import ca.uhn.fhir.fluentpath.IFluentPath;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.model.Base;
|
||||
import org.hl7.fhir.r5.utils.FHIRPathEngine;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class FhirPathR5 implements IFluentPath {
|
||||
|
||||
private FHIRPathEngine myEngine;
|
||||
|
||||
public FhirPathR5(FhirContext theCtx) {
|
||||
if (!(theCtx.getValidationSupport() instanceof IValidationSupport)) {
|
||||
throw new IllegalStateException("Validation support module configured on context appears to be for the wrong FHIR version- Does not extend " + IValidationSupport.class.getName());
|
||||
}
|
||||
IValidationSupport validationSupport = (IValidationSupport) theCtx.getValidationSupport();
|
||||
myEngine = new FHIRPathEngine(new HapiWorkerContext(theCtx, validationSupport));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public <T extends IBase> List<T> evaluate(IBase theInput, String thePath, Class<T> theReturnType) {
|
||||
List<Base> result;
|
||||
try {
|
||||
result = myEngine.evaluate((Base) theInput, thePath);
|
||||
} catch (FHIRException e) {
|
||||
throw new FluentPathExecutionException(e);
|
||||
}
|
||||
|
||||
for (Base next : result) {
|
||||
if (!theReturnType.isAssignableFrom(next.getClass())) {
|
||||
throw new FluentPathExecutionException("FluentPath expression \"" + thePath + "\" returned unexpected type " + next.getClass().getSimpleName() + " - Expected " + theReturnType.getName());
|
||||
}
|
||||
}
|
||||
|
||||
return (List<T>) result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBase> Optional<T> evaluateFirst(IBase theInput, String thePath, Class<T> theReturnType) {
|
||||
return evaluate(theInput, thePath, theReturnType).stream().findFirst();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
package org.hl7.fhir.r5.hapi.rest.server;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.rest.annotation.GraphQL;
|
||||
import ca.uhn.fhir.rest.annotation.GraphQLQuery;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Initialize;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r5.context.IWorkerContext;
|
||||
import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
import org.hl7.fhir.r5.utils.GraphQLEngine;
|
||||
import org.hl7.fhir.utilities.graphql.ObjectValue;
|
||||
import org.hl7.fhir.utilities.graphql.Parser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
public class GraphQLProvider {
|
||||
private final IWorkerContext myWorkerContext;
|
||||
private Logger ourLog = LoggerFactory.getLogger(GraphQLProvider.class);
|
||||
private GraphQLEngine.IGraphQLStorageServices myStorageServices;
|
||||
|
||||
/**
|
||||
* Constructor which uses a default context and validation support object
|
||||
*
|
||||
* @param theStorageServices The storage services (this object will be used to retrieve various resources as required by the GraphQL engine)
|
||||
*/
|
||||
public GraphQLProvider(GraphQLEngine.IGraphQLStorageServices theStorageServices) {
|
||||
this(FhirContext.forR5(), new DefaultProfileValidationSupport(), theStorageServices);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor which uses the given worker context
|
||||
*
|
||||
* @param theFhirContext The HAPI FHIR Context object
|
||||
* @param theValidationSupport The HAPI Validation Support object
|
||||
* @param theStorageServices The storage services (this object will be used to retrieve various resources as required by the GraphQL engine)
|
||||
*/
|
||||
public GraphQLProvider(FhirContext theFhirContext, IValidationSupport theValidationSupport, GraphQLEngine.IGraphQLStorageServices theStorageServices) {
|
||||
myWorkerContext = new HapiWorkerContext(theFhirContext, theValidationSupport);
|
||||
myStorageServices = theStorageServices;
|
||||
}
|
||||
|
||||
@GraphQL
|
||||
public String graphql(ServletRequestDetails theRequestDetails, @IdParam IIdType theId, @GraphQLQuery String theQuery) {
|
||||
|
||||
GraphQLEngine engine = new GraphQLEngine(myWorkerContext);
|
||||
engine.setAppInfo(theRequestDetails);
|
||||
engine.setServices(myStorageServices);
|
||||
try {
|
||||
engine.setGraphQL(Parser.parse(theQuery));
|
||||
} catch (Exception theE) {
|
||||
throw new InvalidRequestException("Unable to parse GraphQL Expression: " + theE.toString());
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
if (theId != null) {
|
||||
Resource focus = myStorageServices.lookup(theRequestDetails, theId.getResourceType(), theId.getIdPart());
|
||||
engine.setFocus(focus);
|
||||
}
|
||||
engine.execute();
|
||||
|
||||
StringBuilder outputBuilder = new StringBuilder();
|
||||
ObjectValue output = engine.getOutput();
|
||||
output.write(outputBuilder, 0, "\n");
|
||||
|
||||
return outputBuilder.toString();
|
||||
|
||||
} catch (Exception e) {
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("Unable to execute GraphQL Expression: ");
|
||||
int statusCode = 500;
|
||||
if (e instanceof BaseServerResponseException) {
|
||||
b.append("HTTP ");
|
||||
statusCode = ((BaseServerResponseException) e).getStatusCode();
|
||||
b.append(statusCode);
|
||||
b.append(" ");
|
||||
} else {
|
||||
// This means it's a bug, so let's log
|
||||
ourLog.error("Failure during GraphQL processing", e);
|
||||
}
|
||||
b.append(e.getMessage());
|
||||
throw new UnclassifiedServerFailureException(statusCode, b.toString());
|
||||
}
|
||||
}
|
||||
|
||||
@Initialize
|
||||
public void initialize(RestfulServer theServer) {
|
||||
ourLog.trace("Initializing GraphQL provider");
|
||||
if (theServer.getFhirContext().getVersion().getVersion() != FhirVersionEnum.R5) {
|
||||
throw new ConfigurationException("Can not use " + getClass().getName() + " provider on server with FHIR " + theServer.getFhirContext().getVersion().getVersion().name() + " context");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,396 @@
|
|||
package org.hl7.fhir.r5.hapi.rest.server;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.r5.model.Bundle;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleLinkComponent;
|
||||
import org.hl7.fhir.r5.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r5.model.Bundle.SearchEntryMode;
|
||||
import org.hl7.fhir.r5.model.DomainResource;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.Resource;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class R5BundleFactory implements IVersionSpecificBundleFactory {
|
||||
private String myBase;
|
||||
private Bundle myBundle;
|
||||
private FhirContext myContext;
|
||||
|
||||
public R5BundleFactory(FhirContext theContext) {
|
||||
myContext = theContext;
|
||||
}
|
||||
|
||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
||||
|
||||
for (IBaseResource next : theResult) {
|
||||
if (next.getIdElement().isEmpty() == false) {
|
||||
addedResourceIds.add(next.getIdElement());
|
||||
}
|
||||
}
|
||||
|
||||
for (IBaseResource nextBaseRes : theResult) {
|
||||
Resource next = (Resource) nextBaseRes;
|
||||
Set<String> containedIds = new HashSet<String>();
|
||||
if (next instanceof DomainResource) {
|
||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
||||
if (nextContained.getIdElement().isEmpty() == false) {
|
||||
containedIds.add(nextContained.getIdElement().getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
|
||||
do {
|
||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<>();
|
||||
|
||||
for (IBaseReference nextRef : references) {
|
||||
IAnyResource nextRes = (IAnyResource) nextRef.getResource();
|
||||
if (nextRes != null) {
|
||||
if (nextRes.getIdElement().hasIdPart()) {
|
||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
||||
// Don't add contained IDs as top level resources
|
||||
continue;
|
||||
}
|
||||
|
||||
IIdType id = nextRes.getIdElement();
|
||||
if (id.hasResourceType() == false) {
|
||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
||||
id = id.withResourceType(resName);
|
||||
}
|
||||
|
||||
if (!addedResourceIds.contains(id)) {
|
||||
addedResourceIds.add(id);
|
||||
addedResourcesThisPass.add(nextRes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Linked resources may themselves have linked resources
|
||||
references = new ArrayList<>();
|
||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, IBaseReference.class);
|
||||
references.addAll(newReferences);
|
||||
}
|
||||
|
||||
includedResources.addAll(addedResourcesThisPass);
|
||||
|
||||
} while (references.isEmpty() == false);
|
||||
|
||||
BundleEntryComponent entry = myBundle.addEntry().setResource(next);
|
||||
if (next.getIdElement().hasBaseUrl()) {
|
||||
entry.setFullUrl(next.getId());
|
||||
}
|
||||
|
||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
||||
if (httpVerb != null) {
|
||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
||||
entry.getRequest().getUrlElement().setValue(next.getId());
|
||||
}
|
||||
if ("DELETE".equals(httpVerb)) {
|
||||
entry.setResource(null);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually add the resources to the bundle
|
||||
*/
|
||||
for (IBaseResource next : includedResources) {
|
||||
BundleEntryComponent entry = myBundle.addEntry();
|
||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||
if (next.getIdElement().hasBaseUrl()) {
|
||||
entry.setFullUrl(next.getIdElement().getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||
ensureBundle();
|
||||
|
||||
List<IAnyResource> includedResources = new ArrayList<IAnyResource>();
|
||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
||||
|
||||
for (IBaseResource next : theResult) {
|
||||
if (next.getIdElement().isEmpty() == false) {
|
||||
addedResourceIds.add(next.getIdElement());
|
||||
}
|
||||
}
|
||||
|
||||
for (IBaseResource next : theResult) {
|
||||
|
||||
Set<String> containedIds = new HashSet<String>();
|
||||
|
||||
if (next instanceof DomainResource) {
|
||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
||||
if (isNotBlank(nextContained.getId())) {
|
||||
containedIds.add(nextContained.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
||||
do {
|
||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||
|
||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IAnyResource nextRes = (IAnyResource) nextRefInfo.getResourceReference().getResource();
|
||||
if (nextRes != null) {
|
||||
if (nextRes.getIdElement().hasIdPart()) {
|
||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
||||
// Don't add contained IDs as top level resources
|
||||
continue;
|
||||
}
|
||||
|
||||
IIdType id = nextRes.getIdElement();
|
||||
if (id.hasResourceType() == false) {
|
||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
||||
id = id.withResourceType(resName);
|
||||
}
|
||||
|
||||
if (!addedResourceIds.contains(id)) {
|
||||
addedResourceIds.add(id);
|
||||
addedResourcesThisPass.add(nextRes);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
includedResources.addAll(addedResourcesThisPass);
|
||||
|
||||
// Linked resources may themselves have linked resources
|
||||
references = new ArrayList<>();
|
||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
||||
references.addAll(newReferences);
|
||||
}
|
||||
} while (references.isEmpty() == false);
|
||||
|
||||
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
||||
Resource nextAsResource = (Resource) next;
|
||||
IIdType id = populateBundleEntryFullUrl(next, entry);
|
||||
|
||||
// Populate Request
|
||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(nextAsResource);
|
||||
if (httpVerb != null) {
|
||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
||||
if (id != null) {
|
||||
entry.getRequest().setUrl(id.getValue());
|
||||
}
|
||||
}
|
||||
if ("DELETE".equals(httpVerb)) {
|
||||
entry.setResource(null);
|
||||
}
|
||||
|
||||
// Populate Bundle.entry.response
|
||||
if (theBundleType != null) {
|
||||
switch (theBundleType) {
|
||||
case BATCH_RESPONSE:
|
||||
case TRANSACTION_RESPONSE:
|
||||
case HISTORY:
|
||||
if ("1".equals(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("201 Created");
|
||||
} else if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setStatus("200 OK");
|
||||
}
|
||||
if (isNotBlank(id.getVersionIdPart())) {
|
||||
entry.getResponse().setEtag(RestfulServerUtils.createEtag(id.getVersionIdPart()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Populate Bundle.entry.search
|
||||
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
||||
if (searchMode != null) {
|
||||
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Actually add the resources to the bundle
|
||||
*/
|
||||
for (IAnyResource next : includedResources) {
|
||||
BundleEntryComponent entry = myBundle.addEntry();
|
||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||
populateBundleEntryFullUrl(next, entry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addRootPropertiesToBundle(String theId, String theServerBase, String theLinkSelf, String theLinkPrev, String theLinkNext, Integer theTotalResults, BundleTypeEnum theBundleType,
|
||||
IPrimitiveType<Date> theLastUpdated) {
|
||||
ensureBundle();
|
||||
|
||||
myBase = theServerBase;
|
||||
|
||||
if (myBundle.getIdElement().isEmpty()) {
|
||||
myBundle.setId(theId);
|
||||
}
|
||||
if (myBundle.getIdElement().isEmpty()) {
|
||||
myBundle.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
if (myBundle.getMeta().getLastUpdated() == null && theLastUpdated != null) {
|
||||
myBundle.getMeta().getLastUpdatedElement().setValueAsString(theLastUpdated.getValueAsString());
|
||||
}
|
||||
|
||||
if (!hasLink(Constants.LINK_SELF, myBundle) && isNotBlank(theLinkSelf)) {
|
||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theLinkSelf);
|
||||
}
|
||||
if (!hasLink(Constants.LINK_NEXT, myBundle) && isNotBlank(theLinkNext)) {
|
||||
myBundle.addLink().setRelation(Constants.LINK_NEXT).setUrl(theLinkNext);
|
||||
}
|
||||
if (!hasLink(Constants.LINK_PREVIOUS, myBundle) && isNotBlank(theLinkPrev)) {
|
||||
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS).setUrl(theLinkPrev);
|
||||
}
|
||||
|
||||
if (myBundle.getTypeElement().isEmpty() && theBundleType != null) {
|
||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
||||
}
|
||||
|
||||
if (myBundle.getTotalElement().isEmpty() && theTotalResults != null) {
|
||||
myBundle.getTotalElement().setValue(theTotalResults);
|
||||
}
|
||||
}
|
||||
|
||||
private void ensureBundle() {
|
||||
if (myBundle == null) {
|
||||
myBundle = new Bundle();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBaseResource getResourceBundle() {
|
||||
return myBundle;
|
||||
}
|
||||
|
||||
private boolean hasLink(String theLinkType, Bundle theBundle) {
|
||||
for (BundleLinkComponent next : theBundle.getLink()) {
|
||||
if (theLinkType.equals(next.getRelation())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
||||
BundleTypeEnum theBundleType) {
|
||||
myBundle = new Bundle();
|
||||
|
||||
myBundle.setId(UUID.randomUUID().toString());
|
||||
|
||||
myBundle.getMeta().setLastUpdated(new Date());
|
||||
|
||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
||||
|
||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
||||
for (IBaseResource nextBaseRes : theResources) {
|
||||
Resource next = (Resource) nextBaseRes;
|
||||
BundleEntryComponent nextEntry = myBundle.addEntry();
|
||||
|
||||
nextEntry.setResource(next);
|
||||
if (next.getIdElement().isEmpty()) {
|
||||
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
||||
} else {
|
||||
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
||||
if (next.getIdElement().isAbsolute()) {
|
||||
nextEntry.getRequest().setUrl(next.getId());
|
||||
} else {
|
||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
||||
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(), next.getIdElement().getVersionIdPart()).getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
addResourcesForSearch(theResources);
|
||||
}
|
||||
|
||||
myBundle.getTotalElement().setValue(theTotalResults);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||
myBundle = (Bundle) theBundle;
|
||||
}
|
||||
|
||||
private IIdType populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
||||
IIdType idElement = null;
|
||||
if (next.getIdElement().hasBaseUrl()) {
|
||||
idElement = next.getIdElement();
|
||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||
} else {
|
||||
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
||||
idElement = next.getIdElement();
|
||||
idElement = idElement.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||
}
|
||||
}
|
||||
return idElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> toListOfResources() {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
for (BundleEntryComponent next : myBundle.getEntry()) {
|
||||
if (next.getResource() != null) {
|
||||
retVal.add(next.getResource());
|
||||
} else if (next.getResponse().getLocationElement().isEmpty() == false) {
|
||||
IdType id = new IdType(next.getResponse().getLocation());
|
||||
String resourceType = id.getResourceType();
|
||||
if (isNotBlank(resourceType)) {
|
||||
IAnyResource res = (IAnyResource) myContext.getResourceDefinition(resourceType).newInstance();
|
||||
res.setId(id);
|
||||
retVal.add(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,602 @@
|
|||
package org.hl7.fhir.r5.hapi.rest.server;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Metadata;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.Bindings;
|
||||
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerConfiguration;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.method.*;
|
||||
import ca.uhn.fhir.rest.server.method.OperationMethodBinding.ReturnType;
|
||||
import ca.uhn.fhir.rest.server.method.SearchParameter;
|
||||
import ca.uhn.fhir.rest.server.util.BaseServerCapabilityStatementProvider;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.exceptions.FHIRException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.CapabilityStatement.*;
|
||||
import org.hl7.fhir.r5.model.Enumerations.PublicationStatus;
|
||||
import org.hl7.fhir.r5.model.OperationDefinition.OperationDefinitionParameterComponent;
|
||||
import org.hl7.fhir.r5.model.OperationDefinition.OperationKind;
|
||||
import org.hl7.fhir.r5.model.OperationDefinition.OperationParameterUse;
|
||||
|
||||
import javax.servlet.ServletContext;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.util.*;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
/**
|
||||
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
|
||||
*
|
||||
* <p>
|
||||
* Note: This class is safe to extend, but it is important to note that the same instance of {@link CapabilityStatement} is always returned unless {@link #setCache(boolean)} is called with a value of
|
||||
* <code>false</code>. This means that if you are adding anything to the returned conformance instance on each call you should call <code>setCache(false)</code> in your provider constructor.
|
||||
* </p>
|
||||
*/
|
||||
public class ServerCapabilityStatementProvider extends BaseServerCapabilityStatementProvider implements IServerConformanceProvider<CapabilityStatement> {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerCapabilityStatementProvider.class);
|
||||
private String myPublisher = "Not provided";
|
||||
|
||||
/**
|
||||
* No-arg constructor and setter so that the ServerConformanceProvider can be Spring-wired with the RestfulService avoiding the potential reference cycle that would happen.
|
||||
*/
|
||||
public ServerCapabilityStatementProvider() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @deprecated Use no-args constructor instead. Deprecated in 4.0.0
|
||||
*/
|
||||
@Deprecated
|
||||
public ServerCapabilityStatementProvider(RestfulServer theRestfulServer) {
|
||||
this();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor - This is intended only for JAX-RS server
|
||||
*/
|
||||
public ServerCapabilityStatementProvider(RestfulServerConfiguration theServerConfiguration) {
|
||||
super(theServerConfiguration);
|
||||
}
|
||||
|
||||
private void checkBindingForSystemOps(CapabilityStatementRestComponent rest, Set<SystemRestfulInteraction> systemOps, BaseMethodBinding<?> nextMethodBinding) {
|
||||
if (nextMethodBinding.getRestOperationType() != null) {
|
||||
String sysOpCode = nextMethodBinding.getRestOperationType().getCode();
|
||||
if (sysOpCode != null) {
|
||||
SystemRestfulInteraction sysOp;
|
||||
try {
|
||||
sysOp = SystemRestfulInteraction.fromCode(sysOpCode);
|
||||
} catch (FHIRException e) {
|
||||
return;
|
||||
}
|
||||
if (sysOp == null) {
|
||||
return;
|
||||
}
|
||||
if (systemOps.contains(sysOp) == false) {
|
||||
systemOps.add(sysOp);
|
||||
rest.addInteraction().setCode(sysOp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private DateTimeType conformanceDate(RequestDetails theRequestDetails) {
|
||||
IPrimitiveType<Date> buildDate = getServerConfiguration(theRequestDetails).getConformanceDate();
|
||||
if (buildDate != null && buildDate.getValue() != null) {
|
||||
try {
|
||||
return new DateTimeType(buildDate.getValueAsString());
|
||||
} catch (DataFormatException e) {
|
||||
// fall through
|
||||
}
|
||||
}
|
||||
return DateTimeType.now();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null (although this is not enforced). The
|
||||
* value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
|
||||
*/
|
||||
public String getPublisher() {
|
||||
return myPublisher;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null (although this is not enforced). The
|
||||
* value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
|
||||
*/
|
||||
public void setPublisher(String thePublisher) {
|
||||
myPublisher = thePublisher;
|
||||
}
|
||||
|
||||
@SuppressWarnings("EnumSwitchStatementWhichMissesCases")
|
||||
@Override
|
||||
@Metadata
|
||||
public CapabilityStatement getServerConformance(HttpServletRequest theRequest, RequestDetails theRequestDetails) {
|
||||
|
||||
RestfulServerConfiguration configuration = getServerConfiguration(theRequestDetails);
|
||||
Bindings bindings = configuration.provideBindings();
|
||||
|
||||
CapabilityStatement retVal = new CapabilityStatement();
|
||||
|
||||
retVal.setPublisher(myPublisher);
|
||||
retVal.setDateElement(conformanceDate(theRequestDetails));
|
||||
retVal.setFhirVersion(Enumerations.FHIRVersion.fromCode(FhirVersionEnum.R5.getFhirVersionString()));
|
||||
|
||||
ServletContext servletContext = (ServletContext) (theRequest == null ? null : theRequest.getAttribute(RestfulServer.SERVLET_CONTEXT_ATTRIBUTE));
|
||||
String serverBase = configuration.getServerAddressStrategy().determineServerBase(servletContext, theRequest);
|
||||
retVal
|
||||
.getImplementation()
|
||||
.setUrl(serverBase)
|
||||
.setDescription(configuration.getImplementationDescription());
|
||||
|
||||
retVal.setKind(CapabilityStatementKind.INSTANCE);
|
||||
retVal.getSoftware().setName(configuration.getServerName());
|
||||
retVal.getSoftware().setVersion(configuration.getServerVersion());
|
||||
retVal.addFormat(Constants.CT_FHIR_XML_NEW);
|
||||
retVal.addFormat(Constants.CT_FHIR_JSON_NEW);
|
||||
retVal.setStatus(PublicationStatus.ACTIVE);
|
||||
|
||||
CapabilityStatementRestComponent rest = retVal.addRest();
|
||||
rest.setMode(RestfulCapabilityMode.SERVER);
|
||||
|
||||
Set<SystemRestfulInteraction> systemOps = new HashSet<>();
|
||||
Set<String> operationNames = new HashSet<>();
|
||||
|
||||
Map<String, List<BaseMethodBinding<?>>> resourceToMethods = configuration.collectMethodBindings();
|
||||
for (Entry<String, List<BaseMethodBinding<?>>> nextEntry : resourceToMethods.entrySet()) {
|
||||
|
||||
if (nextEntry.getKey().isEmpty() == false) {
|
||||
Set<TypeRestfulInteraction> resourceOps = new HashSet<>();
|
||||
CapabilityStatementRestResourceComponent resource = rest.addResource();
|
||||
String resourceName = nextEntry.getKey();
|
||||
RuntimeResourceDefinition def = configuration.getFhirContext().getResourceDefinition(resourceName);
|
||||
resource.getTypeElement().setValue(def.getName());
|
||||
resource.getProfileElement().setValue((def.getResourceProfile(serverBase)));
|
||||
|
||||
TreeSet<String> includes = new TreeSet<>();
|
||||
|
||||
// Map<String, CapabilityStatement.RestResourceSearchParam> nameToSearchParam = new HashMap<String,
|
||||
// CapabilityStatement.RestResourceSearchParam>();
|
||||
for (BaseMethodBinding<?> nextMethodBinding : nextEntry.getValue()) {
|
||||
if (nextMethodBinding.getRestOperationType() != null) {
|
||||
String resOpCode = nextMethodBinding.getRestOperationType().getCode();
|
||||
if (resOpCode != null) {
|
||||
TypeRestfulInteraction resOp;
|
||||
try {
|
||||
resOp = TypeRestfulInteraction.fromCode(resOpCode);
|
||||
} catch (Exception e) {
|
||||
resOp = null;
|
||||
}
|
||||
if (resOp != null) {
|
||||
if (resourceOps.contains(resOp) == false) {
|
||||
resourceOps.add(resOp);
|
||||
resource.addInteraction().setCode(resOp);
|
||||
}
|
||||
if ("vread".equals(resOpCode)) {
|
||||
// vread implies read
|
||||
resOp = TypeRestfulInteraction.READ;
|
||||
if (resourceOps.contains(resOp) == false) {
|
||||
resourceOps.add(resOp);
|
||||
resource.addInteraction().setCode(resOp);
|
||||
}
|
||||
}
|
||||
|
||||
if (nextMethodBinding.isSupportsConditional()) {
|
||||
switch (resOp) {
|
||||
case CREATE:
|
||||
resource.setConditionalCreate(true);
|
||||
break;
|
||||
case DELETE:
|
||||
if (nextMethodBinding.isSupportsConditionalMultiple()) {
|
||||
resource.setConditionalDelete(ConditionalDeleteStatus.MULTIPLE);
|
||||
} else {
|
||||
resource.setConditionalDelete(ConditionalDeleteStatus.SINGLE);
|
||||
}
|
||||
break;
|
||||
case UPDATE:
|
||||
resource.setConditionalUpdate(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
|
||||
|
||||
if (nextMethodBinding instanceof SearchMethodBinding) {
|
||||
SearchMethodBinding methodBinding = (SearchMethodBinding) nextMethodBinding;
|
||||
if (methodBinding.getQueryName() != null) {
|
||||
String queryName = bindings.getNamedSearchMethodBindingToName().get(methodBinding);
|
||||
if (operationNames.add(queryName)) {
|
||||
rest.addOperation().setName(methodBinding.getQueryName()).setDefinition(("OperationDefinition/" + queryName));
|
||||
}
|
||||
} else {
|
||||
handleNamelessSearchMethodBinding(resource, def, includes, (SearchMethodBinding) nextMethodBinding, theRequestDetails);
|
||||
}
|
||||
} else if (nextMethodBinding instanceof OperationMethodBinding) {
|
||||
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
|
||||
String opName = bindings.getOperationBindingToName().get(methodBinding);
|
||||
if (operationNames.add(opName)) {
|
||||
// Only add each operation (by name) once
|
||||
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName));
|
||||
}
|
||||
}
|
||||
|
||||
resource.getInteraction().sort(new Comparator<ResourceInteractionComponent>() {
|
||||
@Override
|
||||
public int compare(ResourceInteractionComponent theO1, ResourceInteractionComponent theO2) {
|
||||
TypeRestfulInteraction o1 = theO1.getCode();
|
||||
TypeRestfulInteraction o2 = theO2.getCode();
|
||||
if (o1 == null && o2 == null) {
|
||||
return 0;
|
||||
}
|
||||
if (o1 == null) {
|
||||
return 1;
|
||||
}
|
||||
if (o2 == null) {
|
||||
return -1;
|
||||
}
|
||||
return o1.ordinal() - o2.ordinal();
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
for (String nextInclude : includes) {
|
||||
resource.addSearchInclude(nextInclude);
|
||||
}
|
||||
} else {
|
||||
for (BaseMethodBinding<?> nextMethodBinding : nextEntry.getValue()) {
|
||||
checkBindingForSystemOps(rest, systemOps, nextMethodBinding);
|
||||
if (nextMethodBinding instanceof OperationMethodBinding) {
|
||||
OperationMethodBinding methodBinding = (OperationMethodBinding) nextMethodBinding;
|
||||
String opName = bindings.getOperationBindingToName().get(methodBinding);
|
||||
if (operationNames.add(opName)) {
|
||||
ourLog.debug("Found bound operation: {}", opName);
|
||||
rest.addOperation().setName(methodBinding.getName().substring(1)).setDefinition(("OperationDefinition/" + opName));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void handleNamelessSearchMethodBinding(CapabilityStatementRestResourceComponent resource, RuntimeResourceDefinition def, TreeSet<String> includes,
|
||||
SearchMethodBinding searchMethodBinding, RequestDetails theRequestDetails) {
|
||||
includes.addAll(searchMethodBinding.getIncludes());
|
||||
|
||||
List<IParameter> params = searchMethodBinding.getParameters();
|
||||
List<SearchParameter> searchParameters = new ArrayList<>();
|
||||
for (IParameter nextParameter : params) {
|
||||
if ((nextParameter instanceof SearchParameter)) {
|
||||
searchParameters.add((SearchParameter) nextParameter);
|
||||
}
|
||||
}
|
||||
sortSearchParameters(searchParameters);
|
||||
if (!searchParameters.isEmpty()) {
|
||||
// boolean allOptional = searchParameters.get(0).isRequired() == false;
|
||||
//
|
||||
// OperationDefinition query = null;
|
||||
// if (!allOptional) {
|
||||
// RestOperation operation = rest.addOperation();
|
||||
// query = new OperationDefinition();
|
||||
// operation.setDefinition(new ResourceReferenceDt(query));
|
||||
// query.getDescriptionElement().setValue(searchMethodBinding.getDescription());
|
||||
// query.addUndeclaredExtension(false, ExtensionConstants.QUERY_RETURN_TYPE, new CodeDt(resourceName));
|
||||
// for (String nextInclude : searchMethodBinding.getIncludes()) {
|
||||
// query.addUndeclaredExtension(false, ExtensionConstants.QUERY_ALLOWED_INCLUDE, new StringDt(nextInclude));
|
||||
// }
|
||||
// }
|
||||
|
||||
for (SearchParameter nextParameter : searchParameters) {
|
||||
|
||||
String nextParamName = nextParameter.getName();
|
||||
|
||||
String chain = null;
|
||||
String nextParamUnchainedName = nextParamName;
|
||||
if (nextParamName.contains(".")) {
|
||||
chain = nextParamName.substring(nextParamName.indexOf('.') + 1);
|
||||
nextParamUnchainedName = nextParamName.substring(0, nextParamName.indexOf('.'));
|
||||
}
|
||||
|
||||
String nextParamDescription = nextParameter.getDescription();
|
||||
|
||||
/*
|
||||
* If the parameter has no description, default to the one from the resource
|
||||
*/
|
||||
if (StringUtils.isBlank(nextParamDescription)) {
|
||||
RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName);
|
||||
if (paramDef != null) {
|
||||
nextParamDescription = paramDef.getDescription();
|
||||
}
|
||||
}
|
||||
|
||||
CapabilityStatementRestResourceSearchParamComponent param = resource.addSearchParam();
|
||||
param.setName(nextParamUnchainedName);
|
||||
|
||||
// if (StringUtils.isNotBlank(chain)) {
|
||||
// param.addChain(chain);
|
||||
// }
|
||||
//
|
||||
// if (nextParameter.getParamType() == RestSearchParameterTypeEnum.REFERENCE) {
|
||||
// for (String nextWhitelist : new TreeSet<String>(nextParameter.getQualifierWhitelist())) {
|
||||
// if (nextWhitelist.startsWith(".")) {
|
||||
// param.addChain(nextWhitelist.substring(1));
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
param.setDocumentation(nextParamDescription);
|
||||
if (nextParameter.getParamType() != null) {
|
||||
param.getTypeElement().setValueAsString(nextParameter.getParamType().getCode());
|
||||
}
|
||||
for (Class<? extends IBaseResource> nextTarget : nextParameter.getDeclaredTypes()) {
|
||||
RuntimeResourceDefinition targetDef = getServerConfiguration(theRequestDetails).getFhirContext().getResourceDefinition(nextTarget);
|
||||
if (targetDef != null) {
|
||||
ResourceType code;
|
||||
try {
|
||||
code = ResourceType.fromCode(targetDef.getName());
|
||||
} catch (FHIRException e) {
|
||||
code = null;
|
||||
}
|
||||
// if (code != null) {
|
||||
// param.addTarget(targetDef.getName());
|
||||
// }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Read(type = OperationDefinition.class)
|
||||
public OperationDefinition readOperationDefinition(@IdParam IdType theId, RequestDetails theRequestDetails) {
|
||||
if (theId == null || theId.hasIdPart() == false) {
|
||||
throw new ResourceNotFoundException(theId);
|
||||
}
|
||||
RestfulServerConfiguration configuration = getServerConfiguration(theRequestDetails);
|
||||
Bindings bindings = configuration.provideBindings();
|
||||
|
||||
List<OperationMethodBinding> operationBindings = bindings.getOperationNameToBindings().get(theId.getIdPart());
|
||||
if (operationBindings != null && !operationBindings.isEmpty()) {
|
||||
return readOperationDefinitionForOperation(operationBindings);
|
||||
}
|
||||
List<SearchMethodBinding> searchBindings = bindings.getSearchNameToBindings().get(theId.getIdPart());
|
||||
if (searchBindings != null && !searchBindings.isEmpty()) {
|
||||
return readOperationDefinitionForNamedSearch(searchBindings);
|
||||
}
|
||||
throw new ResourceNotFoundException(theId);
|
||||
}
|
||||
|
||||
private OperationDefinition readOperationDefinitionForNamedSearch(List<SearchMethodBinding> bindings) {
|
||||
OperationDefinition op = new OperationDefinition();
|
||||
op.setStatus(PublicationStatus.ACTIVE);
|
||||
op.setKind(OperationKind.QUERY);
|
||||
op.setAffectsState(false);
|
||||
|
||||
op.setSystem(false);
|
||||
op.setType(false);
|
||||
op.setInstance(false);
|
||||
|
||||
Set<String> inParams = new HashSet<>();
|
||||
|
||||
for (SearchMethodBinding binding : bindings) {
|
||||
if (isNotBlank(binding.getDescription())) {
|
||||
op.setDescription(binding.getDescription());
|
||||
}
|
||||
if (isBlank(binding.getResourceProviderResourceName())) {
|
||||
op.setSystem(true);
|
||||
} else {
|
||||
op.setType(true);
|
||||
op.addResourceElement().setValue(binding.getResourceProviderResourceName());
|
||||
}
|
||||
op.setCode(binding.getQueryName());
|
||||
for (IParameter nextParamUntyped : binding.getParameters()) {
|
||||
if (nextParamUntyped instanceof SearchParameter) {
|
||||
SearchParameter nextParam = (SearchParameter) nextParamUntyped;
|
||||
if (!inParams.add(nextParam.getName())) {
|
||||
continue;
|
||||
}
|
||||
OperationDefinitionParameterComponent param = op.addParameter();
|
||||
param.setUse(OperationParameterUse.IN);
|
||||
param.setType("string");
|
||||
param.getSearchTypeElement().setValueAsString(nextParam.getParamType().getCode());
|
||||
param.setMin(nextParam.isRequired() ? 1 : 0);
|
||||
param.setMax("1");
|
||||
param.setName(nextParam.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (isBlank(op.getName())) {
|
||||
if (isNotBlank(op.getDescription())) {
|
||||
op.setName(op.getDescription());
|
||||
} else {
|
||||
op.setName(op.getCode());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
private OperationDefinition readOperationDefinitionForOperation(List<OperationMethodBinding> bindings) {
|
||||
OperationDefinition op = new OperationDefinition();
|
||||
op.setStatus(PublicationStatus.ACTIVE);
|
||||
op.setKind(OperationKind.OPERATION);
|
||||
op.setAffectsState(false);
|
||||
|
||||
// We reset these to true below if we find a binding that can handle the level
|
||||
op.setSystem(false);
|
||||
op.setType(false);
|
||||
op.setInstance(false);
|
||||
|
||||
Set<String> inParams = new HashSet<>();
|
||||
Set<String> outParams = new HashSet<>();
|
||||
|
||||
for (OperationMethodBinding sharedDescription : bindings) {
|
||||
if (isNotBlank(sharedDescription.getDescription())) {
|
||||
op.setDescription(sharedDescription.getDescription());
|
||||
}
|
||||
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
||||
op.setInstance(true);
|
||||
}
|
||||
if (sharedDescription.isCanOperateAtServerLevel()) {
|
||||
op.setSystem(true);
|
||||
}
|
||||
if (sharedDescription.isCanOperateAtTypeLevel()) {
|
||||
op.setType(true);
|
||||
}
|
||||
if (!sharedDescription.isIdempotent()) {
|
||||
op.setAffectsState(!sharedDescription.isIdempotent());
|
||||
}
|
||||
op.setCode(sharedDescription.getName().substring(1));
|
||||
if (sharedDescription.isCanOperateAtInstanceLevel()) {
|
||||
op.setInstance(sharedDescription.isCanOperateAtInstanceLevel());
|
||||
}
|
||||
if (sharedDescription.isCanOperateAtServerLevel()) {
|
||||
op.setSystem(sharedDescription.isCanOperateAtServerLevel());
|
||||
}
|
||||
if (isNotBlank(sharedDescription.getResourceName())) {
|
||||
op.addResourceElement().setValue(sharedDescription.getResourceName());
|
||||
}
|
||||
|
||||
for (IParameter nextParamUntyped : sharedDescription.getParameters()) {
|
||||
if (nextParamUntyped instanceof OperationParameter) {
|
||||
OperationParameter nextParam = (OperationParameter) nextParamUntyped;
|
||||
OperationDefinitionParameterComponent param = op.addParameter();
|
||||
if (!inParams.add(nextParam.getName())) {
|
||||
continue;
|
||||
}
|
||||
param.setUse(OperationParameterUse.IN);
|
||||
if (nextParam.getParamType() != null) {
|
||||
param.setType(nextParam.getParamType());
|
||||
}
|
||||
if (nextParam.getSearchParamType() != null) {
|
||||
param.getSearchTypeElement().setValueAsString(nextParam.getSearchParamType());
|
||||
}
|
||||
param.setMin(nextParam.getMin());
|
||||
param.setMax(nextParam.getMax() == -1 ? "*" : Integer.toString(nextParam.getMax()));
|
||||
param.setName(nextParam.getName());
|
||||
}
|
||||
}
|
||||
|
||||
for (ReturnType nextParam : sharedDescription.getReturnParams()) {
|
||||
if (!outParams.add(nextParam.getName())) {
|
||||
continue;
|
||||
}
|
||||
OperationDefinitionParameterComponent param = op.addParameter();
|
||||
param.setUse(OperationParameterUse.OUT);
|
||||
if (nextParam.getType() != null) {
|
||||
param.setType(nextParam.getType());
|
||||
}
|
||||
param.setMin(nextParam.getMin());
|
||||
param.setMax(nextParam.getMax() == -1 ? "*" : Integer.toString(nextParam.getMax()));
|
||||
param.setName(nextParam.getName());
|
||||
}
|
||||
}
|
||||
|
||||
if (isBlank(op.getName())) {
|
||||
if (isNotBlank(op.getDescription())) {
|
||||
op.setName(op.getDescription());
|
||||
} else {
|
||||
op.setName(op.getCode());
|
||||
}
|
||||
}
|
||||
|
||||
if (op.hasSystem() == false) {
|
||||
op.setSystem(false);
|
||||
}
|
||||
if (op.hasInstance() == false) {
|
||||
op.setInstance(false);
|
||||
}
|
||||
|
||||
return op;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the cache property (default is true). If set to true, the same response will be returned for each invocation.
|
||||
* <p>
|
||||
* See the class documentation for an important note if you are extending this class
|
||||
* </p>
|
||||
*
|
||||
* @deprecated Since 4.0.0 - This method no longer does anything
|
||||
*/
|
||||
@Deprecated
|
||||
public ServerCapabilityStatementProvider setCache(boolean theCache) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRestfulServer(RestfulServer theRestfulServer) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
private void sortRuntimeSearchParameters(List<RuntimeSearchParam> searchParameters) {
|
||||
Collections.sort(searchParameters, new Comparator<RuntimeSearchParam>() {
|
||||
@Override
|
||||
public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) {
|
||||
return theO1.getName().compareTo(theO2.getName());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sortSearchParameters(List<SearchParameter> searchParameters) {
|
||||
Collections.sort(searchParameters, new Comparator<SearchParameter>() {
|
||||
@Override
|
||||
public int compare(SearchParameter theO1, SearchParameter theO2) {
|
||||
if (theO1.isRequired() == theO2.isRequired()) {
|
||||
return theO1.getName().compareTo(theO2.getName());
|
||||
}
|
||||
if (theO1.isRequired()) {
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package org.hl7.fhir.r5.hapi.rest.server;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2015 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.Read;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.IdType;
|
||||
import org.hl7.fhir.r5.model.StructureDefinition;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
|
||||
public class ServerProfileProvider implements IResourceProvider {
|
||||
|
||||
private final FhirContext myContext;
|
||||
private final RestfulServer myRestfulServer;
|
||||
|
||||
public ServerProfileProvider(RestfulServer theServer) {
|
||||
myContext = theServer.getFhirContext();
|
||||
myRestfulServer = theServer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return StructureDefinition.class;
|
||||
}
|
||||
|
||||
@Read()
|
||||
public StructureDefinition getProfileById(ServletRequestDetails theRequest, @IdParam IdType theId) {
|
||||
RuntimeResourceDefinition retVal = myContext.getResourceDefinitionById(theId.getIdPart());
|
||||
if (retVal==null) {
|
||||
return null;
|
||||
}
|
||||
String serverBase = getServerBase(theRequest);
|
||||
return (StructureDefinition) retVal.toProfile(serverBase);
|
||||
}
|
||||
|
||||
@Search()
|
||||
public List<StructureDefinition> getAllProfiles(ServletRequestDetails theRequest) {
|
||||
final String serverBase = getServerBase(theRequest);
|
||||
List<RuntimeResourceDefinition> defs = new ArrayList<RuntimeResourceDefinition>(myContext.getResourceDefinitionsWithExplicitId());
|
||||
Collections.sort(defs, new Comparator<RuntimeResourceDefinition>() {
|
||||
@Override
|
||||
public int compare(RuntimeResourceDefinition theO1, RuntimeResourceDefinition theO2) {
|
||||
int cmp = theO1.getName().compareTo(theO2.getName());
|
||||
if (cmp==0) {
|
||||
cmp=theO1.getResourceProfile(serverBase).compareTo(theO2.getResourceProfile(serverBase));
|
||||
}
|
||||
return cmp;
|
||||
}});
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<StructureDefinition>();
|
||||
for (RuntimeResourceDefinition next : defs) {
|
||||
retVal.add((StructureDefinition) next.toProfile(serverBase));
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private String getServerBase(ServletRequestDetails theHttpRequest) {
|
||||
return myRestfulServer.getServerBaseForRequest(theHttpRequest);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,212 @@
|
|||
# This file contains version definitions
|
||||
# Generated: 2019-08-05T14:22:40.297-04:00
|
||||
|
||||
resource.Account=org.hl7.fhir.r5.model.Account
|
||||
resource.ActivityDefinition=org.hl7.fhir.r5.model.ActivityDefinition
|
||||
resource.AdverseEvent=org.hl7.fhir.r5.model.AdverseEvent
|
||||
resource.AllergyIntolerance=org.hl7.fhir.r5.model.AllergyIntolerance
|
||||
resource.Appointment=org.hl7.fhir.r5.model.Appointment
|
||||
resource.AppointmentResponse=org.hl7.fhir.r5.model.AppointmentResponse
|
||||
resource.AuditEvent=org.hl7.fhir.r5.model.AuditEvent
|
||||
resource.Basic=org.hl7.fhir.r5.model.Basic
|
||||
resource.Binary=org.hl7.fhir.r5.model.Binary
|
||||
resource.BiologicallyDerivedProduct=org.hl7.fhir.r5.model.BiologicallyDerivedProduct
|
||||
resource.BodyStructure=org.hl7.fhir.r5.model.BodyStructure
|
||||
resource.Bundle=org.hl7.fhir.r5.model.Bundle
|
||||
resource.CapabilityStatement=org.hl7.fhir.r5.model.CapabilityStatement
|
||||
resource.CarePlan=org.hl7.fhir.r5.model.CarePlan
|
||||
resource.CareTeam=org.hl7.fhir.r5.model.CareTeam
|
||||
resource.CatalogEntry=org.hl7.fhir.r5.model.CatalogEntry
|
||||
resource.ChargeItem=org.hl7.fhir.r5.model.ChargeItem
|
||||
resource.ChargeItemDefinition=org.hl7.fhir.r5.model.ChargeItemDefinition
|
||||
resource.Claim=org.hl7.fhir.r5.model.Claim
|
||||
resource.ClaimResponse=org.hl7.fhir.r5.model.ClaimResponse
|
||||
resource.ClinicalImpression=org.hl7.fhir.r5.model.ClinicalImpression
|
||||
resource.CodeSystem=org.hl7.fhir.r5.model.CodeSystem
|
||||
resource.Communication=org.hl7.fhir.r5.model.Communication
|
||||
resource.CommunicationRequest=org.hl7.fhir.r5.model.CommunicationRequest
|
||||
resource.CompartmentDefinition=org.hl7.fhir.r5.model.CompartmentDefinition
|
||||
resource.Composition=org.hl7.fhir.r5.model.Composition
|
||||
resource.ConceptMap=org.hl7.fhir.r5.model.ConceptMap
|
||||
resource.Condition=org.hl7.fhir.r5.model.Condition
|
||||
resource.Consent=org.hl7.fhir.r5.model.Consent
|
||||
resource.Contract=org.hl7.fhir.r5.model.Contract
|
||||
resource.Coverage=org.hl7.fhir.r5.model.Coverage
|
||||
resource.CoverageEligibilityRequest=org.hl7.fhir.r5.model.CoverageEligibilityRequest
|
||||
resource.CoverageEligibilityResponse=org.hl7.fhir.r5.model.CoverageEligibilityResponse
|
||||
resource.DetectedIssue=org.hl7.fhir.r5.model.DetectedIssue
|
||||
resource.Device=org.hl7.fhir.r5.model.Device
|
||||
resource.DeviceDefinition=org.hl7.fhir.r5.model.DeviceDefinition
|
||||
resource.DeviceMetric=org.hl7.fhir.r5.model.DeviceMetric
|
||||
resource.DeviceRequest=org.hl7.fhir.r5.model.DeviceRequest
|
||||
resource.DeviceUseStatement=org.hl7.fhir.r5.model.DeviceUseStatement
|
||||
resource.DiagnosticReport=org.hl7.fhir.r5.model.DiagnosticReport
|
||||
resource.DocumentManifest=org.hl7.fhir.r5.model.DocumentManifest
|
||||
resource.DocumentReference=org.hl7.fhir.r5.model.DocumentReference
|
||||
resource.EffectEvidenceSynthesis=org.hl7.fhir.r5.model.EffectEvidenceSynthesis
|
||||
resource.Encounter=org.hl7.fhir.r5.model.Encounter
|
||||
resource.Endpoint=org.hl7.fhir.r5.model.Endpoint
|
||||
resource.EnrollmentRequest=org.hl7.fhir.r5.model.EnrollmentRequest
|
||||
resource.EnrollmentResponse=org.hl7.fhir.r5.model.EnrollmentResponse
|
||||
resource.EpisodeOfCare=org.hl7.fhir.r5.model.EpisodeOfCare
|
||||
resource.EventDefinition=org.hl7.fhir.r5.model.EventDefinition
|
||||
resource.Evidence=org.hl7.fhir.r5.model.Evidence
|
||||
resource.EvidenceVariable=org.hl7.fhir.r5.model.EvidenceVariable
|
||||
resource.ExampleScenario=org.hl7.fhir.r5.model.ExampleScenario
|
||||
resource.ExplanationOfBenefit=org.hl7.fhir.r5.model.ExplanationOfBenefit
|
||||
resource.FamilyMemberHistory=org.hl7.fhir.r5.model.FamilyMemberHistory
|
||||
resource.Flag=org.hl7.fhir.r5.model.Flag
|
||||
resource.Goal=org.hl7.fhir.r5.model.Goal
|
||||
resource.GraphDefinition=org.hl7.fhir.r5.model.GraphDefinition
|
||||
resource.Group=org.hl7.fhir.r5.model.Group
|
||||
resource.GuidanceResponse=org.hl7.fhir.r5.model.GuidanceResponse
|
||||
resource.HealthcareService=org.hl7.fhir.r5.model.HealthcareService
|
||||
resource.ImagingStudy=org.hl7.fhir.r5.model.ImagingStudy
|
||||
resource.Immunization=org.hl7.fhir.r5.model.Immunization
|
||||
resource.ImmunizationEvaluation=org.hl7.fhir.r5.model.ImmunizationEvaluation
|
||||
resource.ImmunizationRecommendation=org.hl7.fhir.r5.model.ImmunizationRecommendation
|
||||
resource.ImplementationGuide=org.hl7.fhir.r5.model.ImplementationGuide
|
||||
resource.InsurancePlan=org.hl7.fhir.r5.model.InsurancePlan
|
||||
resource.Invoice=org.hl7.fhir.r5.model.Invoice
|
||||
resource.Library=org.hl7.fhir.r5.model.Library
|
||||
resource.Linkage=org.hl7.fhir.r5.model.Linkage
|
||||
resource.List=org.hl7.fhir.r5.model.ListResource
|
||||
resource.Location=org.hl7.fhir.r5.model.Location
|
||||
resource.Measure=org.hl7.fhir.r5.model.Measure
|
||||
resource.MeasureReport=org.hl7.fhir.r5.model.MeasureReport
|
||||
resource.Media=org.hl7.fhir.r5.model.Media
|
||||
resource.Medication=org.hl7.fhir.r5.model.Medication
|
||||
resource.MedicationAdministration=org.hl7.fhir.r5.model.MedicationAdministration
|
||||
resource.MedicationDispense=org.hl7.fhir.r5.model.MedicationDispense
|
||||
resource.MedicationKnowledge=org.hl7.fhir.r5.model.MedicationKnowledge
|
||||
resource.MedicationRequest=org.hl7.fhir.r5.model.MedicationRequest
|
||||
resource.MedicationStatement=org.hl7.fhir.r5.model.MedicationStatement
|
||||
resource.MedicinalProduct=org.hl7.fhir.r5.model.MedicinalProduct
|
||||
resource.MedicinalProductAuthorization=org.hl7.fhir.r5.model.MedicinalProductAuthorization
|
||||
resource.MedicinalProductContraindication=org.hl7.fhir.r5.model.MedicinalProductContraindication
|
||||
resource.MedicinalProductIndication=org.hl7.fhir.r5.model.MedicinalProductIndication
|
||||
resource.MedicinalProductIngredient=org.hl7.fhir.r5.model.MedicinalProductIngredient
|
||||
resource.MedicinalProductInteraction=org.hl7.fhir.r5.model.MedicinalProductInteraction
|
||||
resource.MedicinalProductManufactured=org.hl7.fhir.r5.model.MedicinalProductManufactured
|
||||
resource.MedicinalProductPackaged=org.hl7.fhir.r5.model.MedicinalProductPackaged
|
||||
resource.MedicinalProductPharmaceutical=org.hl7.fhir.r5.model.MedicinalProductPharmaceutical
|
||||
resource.MedicinalProductUndesirableEffect=org.hl7.fhir.r5.model.MedicinalProductUndesirableEffect
|
||||
resource.MessageDefinition=org.hl7.fhir.r5.model.MessageDefinition
|
||||
resource.MessageHeader=org.hl7.fhir.r5.model.MessageHeader
|
||||
resource.MolecularSequence=org.hl7.fhir.r5.model.MolecularSequence
|
||||
resource.NamingSystem=org.hl7.fhir.r5.model.NamingSystem
|
||||
resource.NutritionOrder=org.hl7.fhir.r5.model.NutritionOrder
|
||||
resource.Observation=org.hl7.fhir.r5.model.Observation
|
||||
resource.ObservationDefinition=org.hl7.fhir.r5.model.ObservationDefinition
|
||||
resource.OperationDefinition=org.hl7.fhir.r5.model.OperationDefinition
|
||||
resource.OperationOutcome=org.hl7.fhir.r5.model.OperationOutcome
|
||||
resource.Organization=org.hl7.fhir.r5.model.Organization
|
||||
resource.OrganizationAffiliation=org.hl7.fhir.r5.model.OrganizationAffiliation
|
||||
resource.Parameters=org.hl7.fhir.r5.model.Parameters
|
||||
resource.Patient=org.hl7.fhir.r5.model.Patient
|
||||
resource.PaymentNotice=org.hl7.fhir.r5.model.PaymentNotice
|
||||
resource.PaymentReconciliation=org.hl7.fhir.r5.model.PaymentReconciliation
|
||||
resource.Person=org.hl7.fhir.r5.model.Person
|
||||
resource.PlanDefinition=org.hl7.fhir.r5.model.PlanDefinition
|
||||
resource.Practitioner=org.hl7.fhir.r5.model.Practitioner
|
||||
resource.PractitionerRole=org.hl7.fhir.r5.model.PractitionerRole
|
||||
resource.Procedure=org.hl7.fhir.r5.model.Procedure
|
||||
resource.Provenance=org.hl7.fhir.r5.model.Provenance
|
||||
resource.Questionnaire=org.hl7.fhir.r5.model.Questionnaire
|
||||
resource.QuestionnaireResponse=org.hl7.fhir.r5.model.QuestionnaireResponse
|
||||
resource.RelatedPerson=org.hl7.fhir.r5.model.RelatedPerson
|
||||
resource.RequestGroup=org.hl7.fhir.r5.model.RequestGroup
|
||||
resource.ResearchDefinition=org.hl7.fhir.r5.model.ResearchDefinition
|
||||
resource.ResearchElementDefinition=org.hl7.fhir.r5.model.ResearchElementDefinition
|
||||
resource.ResearchStudy=org.hl7.fhir.r5.model.ResearchStudy
|
||||
resource.ResearchSubject=org.hl7.fhir.r5.model.ResearchSubject
|
||||
resource.RiskAssessment=org.hl7.fhir.r5.model.RiskAssessment
|
||||
resource.RiskEvidenceSynthesis=org.hl7.fhir.r5.model.RiskEvidenceSynthesis
|
||||
resource.Schedule=org.hl7.fhir.r5.model.Schedule
|
||||
resource.SearchParameter=org.hl7.fhir.r5.model.SearchParameter
|
||||
resource.ServiceRequest=org.hl7.fhir.r5.model.ServiceRequest
|
||||
resource.Slot=org.hl7.fhir.r5.model.Slot
|
||||
resource.Specimen=org.hl7.fhir.r5.model.Specimen
|
||||
resource.SpecimenDefinition=org.hl7.fhir.r5.model.SpecimenDefinition
|
||||
resource.StructureDefinition=org.hl7.fhir.r5.model.StructureDefinition
|
||||
resource.StructureMap=org.hl7.fhir.r5.model.StructureMap
|
||||
resource.Subscription=org.hl7.fhir.r5.model.Subscription
|
||||
resource.Substance=org.hl7.fhir.r5.model.Substance
|
||||
resource.SubstanceNucleicAcid=org.hl7.fhir.r5.model.SubstanceNucleicAcid
|
||||
resource.SubstancePolymer=org.hl7.fhir.r5.model.SubstancePolymer
|
||||
resource.SubstanceProtein=org.hl7.fhir.r5.model.SubstanceProtein
|
||||
resource.SubstanceReferenceInformation=org.hl7.fhir.r5.model.SubstanceReferenceInformation
|
||||
resource.SubstanceSourceMaterial=org.hl7.fhir.r5.model.SubstanceSourceMaterial
|
||||
resource.SubstanceSpecification=org.hl7.fhir.r5.model.SubstanceSpecification
|
||||
resource.SupplyDelivery=org.hl7.fhir.r5.model.SupplyDelivery
|
||||
resource.SupplyRequest=org.hl7.fhir.r5.model.SupplyRequest
|
||||
resource.Task=org.hl7.fhir.r5.model.Task
|
||||
resource.TerminologyCapabilities=org.hl7.fhir.r5.model.TerminologyCapabilities
|
||||
resource.TestReport=org.hl7.fhir.r5.model.TestReport
|
||||
resource.TestScript=org.hl7.fhir.r5.model.TestScript
|
||||
resource.ValueSet=org.hl7.fhir.r5.model.ValueSet
|
||||
resource.VerificationResult=org.hl7.fhir.r5.model.VerificationResult
|
||||
resource.VisionPrescription=org.hl7.fhir.r5.model.VisionPrescription
|
||||
|
||||
datatype.Address=org.hl7.fhir.r5.model.Address
|
||||
datatype.Age=org.hl7.fhir.r5.model.Age
|
||||
datatype.Annotation=org.hl7.fhir.r5.model.Annotation
|
||||
datatype.Attachment=org.hl7.fhir.r5.model.Attachment
|
||||
datatype.BackboneElement=org.hl7.fhir.r5.model.BackboneType
|
||||
datatype.CodeableConcept=org.hl7.fhir.r5.model.CodeableConcept
|
||||
datatype.Coding=org.hl7.fhir.r5.model.Coding
|
||||
datatype.ContactDetail=org.hl7.fhir.r5.model.ContactDetail
|
||||
datatype.ContactPoint=org.hl7.fhir.r5.model.ContactPoint
|
||||
datatype.Contributor=org.hl7.fhir.r5.model.Contributor
|
||||
datatype.Count=org.hl7.fhir.r5.model.Count
|
||||
datatype.DataRequirement=org.hl7.fhir.r5.model.DataRequirement
|
||||
datatype.Distance=org.hl7.fhir.r5.model.Distance
|
||||
datatype.Dosage=org.hl7.fhir.r5.model.Dosage
|
||||
datatype.Duration=org.hl7.fhir.r5.model.Duration
|
||||
datatype.ElementDefinition=org.hl7.fhir.r5.model.ElementDefinition
|
||||
datatype.Expression=org.hl7.fhir.r5.model.Expression
|
||||
datatype.Extension=org.hl7.fhir.r5.model.Extension
|
||||
datatype.HumanName=org.hl7.fhir.r5.model.HumanName
|
||||
datatype.Identifier=org.hl7.fhir.r5.model.Identifier
|
||||
datatype.MarketingStatus=org.hl7.fhir.r5.model.MarketingStatus
|
||||
datatype.Meta=org.hl7.fhir.r5.model.Meta
|
||||
datatype.Money=org.hl7.fhir.r5.model.Money
|
||||
datatype.MoneyQuantity=org.hl7.fhir.r5.model.MoneyQuantity
|
||||
datatype.Narrative=org.hl7.fhir.r5.model.Narrative
|
||||
datatype.ParameterDefinition=org.hl7.fhir.r5.model.ParameterDefinition
|
||||
datatype.Period=org.hl7.fhir.r5.model.Period
|
||||
datatype.Population=org.hl7.fhir.r5.model.Population
|
||||
datatype.ProdCharacteristic=org.hl7.fhir.r5.model.ProdCharacteristic
|
||||
datatype.ProductShelfLife=org.hl7.fhir.r5.model.ProductShelfLife
|
||||
datatype.Quantity=org.hl7.fhir.r5.model.Quantity
|
||||
datatype.Range=org.hl7.fhir.r5.model.Range
|
||||
datatype.Ratio=org.hl7.fhir.r5.model.Ratio
|
||||
datatype.Reference=org.hl7.fhir.r5.model.Reference
|
||||
datatype.RelatedArtifact=org.hl7.fhir.r5.model.RelatedArtifact
|
||||
datatype.SampledData=org.hl7.fhir.r5.model.SampledData
|
||||
datatype.Signature=org.hl7.fhir.r5.model.Signature
|
||||
datatype.SimpleQuantity=org.hl7.fhir.r5.model.SimpleQuantity
|
||||
datatype.SubstanceAmount=org.hl7.fhir.r5.model.SubstanceAmount
|
||||
datatype.Timing=org.hl7.fhir.r5.model.Timing
|
||||
datatype.TriggerDefinition=org.hl7.fhir.r5.model.TriggerDefinition
|
||||
datatype.UsageContext=org.hl7.fhir.r5.model.UsageContext
|
||||
datatype.base64Binary=org.hl7.fhir.r5.model.Base64BinaryType
|
||||
datatype.boolean=org.hl7.fhir.r5.model.BooleanType
|
||||
datatype.canonical=org.hl7.fhir.r5.model.CanonicalType
|
||||
datatype.code=org.hl7.fhir.r5.model.CodeType
|
||||
datatype.code.2=org.hl7.fhir.r5.model.Enumeration
|
||||
datatype.date=org.hl7.fhir.r5.model.DateType
|
||||
datatype.dateTime=org.hl7.fhir.r5.model.DateTimeType
|
||||
datatype.decimal=org.hl7.fhir.r5.model.DecimalType
|
||||
datatype.id=org.hl7.fhir.r5.model.IdType
|
||||
datatype.instant=org.hl7.fhir.r5.model.InstantType
|
||||
datatype.integer=org.hl7.fhir.r5.model.IntegerType
|
||||
datatype.markdown=org.hl7.fhir.r5.model.MarkdownType
|
||||
datatype.oid=org.hl7.fhir.r5.model.OidType
|
||||
datatype.positiveInt=org.hl7.fhir.r5.model.PositiveIntType
|
||||
datatype.string=org.hl7.fhir.r5.model.StringType
|
||||
datatype.time=org.hl7.fhir.r5.model.TimeType
|
||||
datatype.unsignedInt=org.hl7.fhir.r5.model.UnsignedIntType
|
||||
datatype.uri=org.hl7.fhir.r5.model.UriType
|
||||
datatype.url=org.hl7.fhir.r5.model.UrlType
|
||||
datatype.xhtml=org.hl7.fhir.utilities.xhtml.XhtmlNode
|
|
@ -1,8 +1,8 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||
|
@ -30,9 +30,10 @@ import org.apache.http.message.BasicHeader;
|
|||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.hamcrest.core.StringContains;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.*;
|
||||
import org.hl7.fhir.r5.model.Bundle.BundleType;
|
||||
import org.hl7.fhir.r5.model.Bundle.HTTPVerb;
|
||||
import org.junit.*;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
|
||||
|
@ -43,10 +44,10 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.io.StringReader;
|
||||
import java.nio.charset.Charset;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
@ -101,40 +102,11 @@ public class GenericClientTest {
|
|||
}
|
||||
|
||||
private String extractBody(ArgumentCaptor<HttpUriRequest> capt, int count) throws IOException {
|
||||
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(count)).getEntity().getContent(), "UTF-8");
|
||||
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(count)).getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
return body;
|
||||
}
|
||||
|
||||
private String getPatientFeedWithOneResult() {
|
||||
return ClientR4Test.getPatientFeedWithOneResult(ourCtx);
|
||||
// //@formatter:off
|
||||
// String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" +
|
||||
// "<title/>\n" +
|
||||
// "<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" +
|
||||
// "<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" +
|
||||
// "<author>\n" +
|
||||
// "<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" +
|
||||
// "</author>\n" +
|
||||
// "<entry>\n" +
|
||||
// "<content type=\"text/xml\">"
|
||||
// + "<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||
// + "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>"
|
||||
// + "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>"
|
||||
// + "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>"
|
||||
// + "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>"
|
||||
// + "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>"
|
||||
// + "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>"
|
||||
// + "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />"
|
||||
// + "</Patient>"
|
||||
// + "</content>\n"
|
||||
// + " </entry>\n"
|
||||
// + "</feed>";
|
||||
// //@formatter:on
|
||||
// return msg;
|
||||
}
|
||||
|
||||
private String getResourceResult() {
|
||||
//@formatter:off
|
||||
String msg =
|
||||
"<Patient xmlns=\"http://hl7.org/fhir\">"
|
||||
+ "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>"
|
||||
|
@ -145,7 +117,6 @@ public class GenericClientTest {
|
|||
+ "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>"
|
||||
+ "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />"
|
||||
+ "</Patient>";
|
||||
//@formatter:on
|
||||
return msg;
|
||||
}
|
||||
|
||||
|
@ -159,7 +130,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -184,7 +155,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -209,7 +180,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -231,9 +202,9 @@ public class GenericClientTest {
|
|||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -258,9 +229,9 @@ public class GenericClientTest {
|
|||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -296,7 +267,6 @@ public class GenericClientTest {
|
|||
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
|
||||
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(count).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
|
||||
assertThat(extractBody(capt, count), containsString("value=\"John\""));
|
||||
count++;
|
||||
|
||||
}
|
||||
|
||||
|
@ -309,9 +279,9 @@ public class GenericClientTest {
|
|||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -331,7 +301,7 @@ public class GenericClientTest {
|
|||
/*
|
||||
* Try fluent options
|
||||
*/
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
client.create().resource(p1).execute();
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(1).getURI().toString());
|
||||
assertEquals(1, capt.getAllValues().get(count).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
|
||||
|
@ -339,7 +309,7 @@ public class GenericClientTest {
|
|||
count++;
|
||||
|
||||
String resourceText = "<Patient xmlns=\"http://hl7.org/fhir\"> </Patient>";
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
client.create().resource(resourceText).execute();
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(2).getURI().toString());
|
||||
assertEquals(resourceText, IOUtils.toString(((HttpPost) capt.getAllValues().get(2)).getEntity().getContent()));
|
||||
|
@ -357,9 +327,9 @@ public class GenericClientTest {
|
|||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -386,9 +356,9 @@ public class GenericClientTest {
|
|||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -410,9 +380,9 @@ public class GenericClientTest {
|
|||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ooStr), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ooStr), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -421,16 +391,16 @@ public class GenericClientTest {
|
|||
|
||||
assertEquals("http://example.com/fhir/Patient/123", capt.getValue().getURI().toString());
|
||||
assertEquals("DELETE", capt.getValue().getMethod());
|
||||
assertEquals("testDelete01", outcome.getIssueFirstRep().getLocation().get(0).getValue());
|
||||
Assert.assertEquals("testDelete01", outcome.getIssueFirstRep().getLocation().get(0).getValue());
|
||||
assertEquals("myHeaderValue", capt.getValue().getFirstHeader("myHeaderName").getValue());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("LKJHLKJGLKJKLL"), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("LKJHLKJGLKJKLL"), StandardCharsets.UTF_8));
|
||||
outcome = (OperationOutcome) client.delete().resourceById(new IdType("Location", "123", "456")).prettyPrint().encodedJson().execute();
|
||||
|
||||
assertEquals("http://example.com/fhir/Location/123?_pretty=true", capt.getAllValues().get(1).getURI().toString());
|
||||
assertEquals("DELETE", capt.getValue().getMethod());
|
||||
|
||||
assertEquals(null, outcome);
|
||||
Assert.assertEquals(null, outcome);
|
||||
|
||||
}
|
||||
|
||||
|
@ -446,7 +416,7 @@ public class GenericClientTest {
|
|||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
|
||||
return new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -463,7 +433,7 @@ public class GenericClientTest {
|
|||
.execute();
|
||||
assertEquals("http://example.com/fhir/_history", capt.getAllValues().get(idx).getURI().toString());
|
||||
assertEquals("myHeaderValue", capt.getValue().getFirstHeader("myHeaderName").getValue());
|
||||
assertEquals(1, response.getEntry().size());
|
||||
Assert.assertEquals(1, response.getEntry().size());
|
||||
idx++;
|
||||
|
||||
response = client
|
||||
|
@ -474,7 +444,7 @@ public class GenericClientTest {
|
|||
.withAdditionalHeader("myHeaderName", "myHeaderValue2")
|
||||
.execute();
|
||||
assertEquals("http://example.com/fhir/Patient/_history", capt.getAllValues().get(idx).getURI().toString());
|
||||
assertEquals(1, response.getEntry().size());
|
||||
Assert.assertEquals(1, response.getEntry().size());
|
||||
assertEquals("myHeaderValue1", capt.getValue().getHeaders("myHeaderName")[0].getValue());
|
||||
assertEquals("myHeaderValue2", capt.getValue().getHeaders("myHeaderName")[1].getValue());
|
||||
idx++;
|
||||
|
@ -485,7 +455,7 @@ public class GenericClientTest {
|
|||
.andReturnBundle(Bundle.class)
|
||||
.execute();
|
||||
assertEquals("http://example.com/fhir/Patient/123/_history", capt.getAllValues().get(idx).getURI().toString());
|
||||
assertEquals(1, response.getEntry().size());
|
||||
Assert.assertEquals(1, response.getEntry().size());
|
||||
idx++;
|
||||
}
|
||||
|
||||
|
@ -517,7 +487,7 @@ public class GenericClientTest {
|
|||
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
|
||||
|
@ -536,12 +506,12 @@ public class GenericClientTest {
|
|||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return (new ReaderInputStream(new StringReader(getPatientFeedWithOneResult()), Charset.forName("UTF-8")));
|
||||
return (new ReaderInputStream(new StringReader(getPatientFeedWithOneResult()), StandardCharsets.UTF_8));
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -566,7 +536,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(respString), StandardCharsets.UTF_8));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[0]);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
|
@ -596,8 +566,8 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
Header[] headers = new Header[] {
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
Header[] headers = new Header[]{
|
||||
new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
|
||||
new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
|
||||
};
|
||||
|
@ -613,11 +583,11 @@ public class GenericClientTest {
|
|||
|
||||
assertThat(response.getNameFirstRep().getFamily(), StringContains.containsString("Cardinal"));
|
||||
|
||||
assertEquals("http://foo.com/Patient/123/_history/2333", response.getIdElement().getValue());
|
||||
Assert.assertEquals("http://foo.com/Patient/123/_history/2333", response.getIdElement().getValue());
|
||||
|
||||
InstantType lm = response.getMeta().getLastUpdatedElement();
|
||||
lm.setTimeZoneZulu(true);
|
||||
assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString());
|
||||
Assert.assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString());
|
||||
|
||||
}
|
||||
|
||||
|
@ -630,8 +600,8 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
Header[] headers = new Header[] {
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
Header[] headers = new Header[]{
|
||||
new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
|
||||
new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
|
||||
};
|
||||
|
@ -645,22 +615,22 @@ public class GenericClientTest {
|
|||
assertThat(response.getNameFirstRep().getFamily(), StringContains.containsString("Cardinal"));
|
||||
assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count++).getURI().toString());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = (Patient) client.read().resource("Patient").withId("1234").execute();
|
||||
assertThat(response.getNameFirstRep().getFamily(), StringContains.containsString("Cardinal"));
|
||||
assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count++).getURI().toString());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = (Patient) client.read().resource("Patient").withId(567L).execute();
|
||||
assertThat(response.getNameFirstRep().getFamily(), StringContains.containsString("Cardinal"));
|
||||
assertEquals("http://example.com/fhir/Patient/567", capt.getAllValues().get(count++).getURI().toString());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = client.read().resource(Patient.class).withIdAndVersion("1234", "22").execute();
|
||||
assertThat(response.getNameFirstRep().getFamily(), StringContains.containsString("Cardinal"));
|
||||
assertEquals("http://example.com/fhir/Patient/1234/_history/22", capt.getAllValues().get(count++).getURI().toString());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = client.read().resource(Patient.class).withUrl("http://foo/Patient/22").execute();
|
||||
assertThat(response.getNameFirstRep().getFamily(), StringContains.containsString("Cardinal"));
|
||||
assertEquals("http://foo/Patient/22", capt.getAllValues().get(count++).getURI().toString());
|
||||
|
@ -676,8 +646,8 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
Header[] headers = new Header[] {new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
Header[] headers = new Header[]{new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
|
||||
new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
|
||||
};
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
|
||||
|
@ -692,7 +662,7 @@ public class GenericClientTest {
|
|||
assertThat(response.getNameFirstRep().getFamily(), StringContains.containsString("Cardinal"));
|
||||
assertEquals("http://somebase.com/path/to/base/Patient/1234", capt.getAllValues().get(0).getURI().toString());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = client
|
||||
.read()
|
||||
.resource(Patient.class)
|
||||
|
@ -713,7 +683,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -737,7 +707,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -767,7 +737,7 @@ public class GenericClientTest {
|
|||
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
|
||||
|
@ -784,7 +754,7 @@ public class GenericClientTest {
|
|||
|
||||
ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(response));
|
||||
|
||||
assertEquals("PRP1660", BundleUtil.toListOfResourcesOfType(ourCtx, response, Patient.class).get(0).getIdentifier().get(0).getValue());
|
||||
Assert.assertEquals("PRP1660", BundleUtil.toListOfResourcesOfType(ourCtx, response, Patient.class).get(0).getIdentifier().get(0).getValue());
|
||||
|
||||
try {
|
||||
client
|
||||
|
@ -811,7 +781,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://foo");
|
||||
|
||||
|
@ -823,7 +793,7 @@ public class GenericClientTest {
|
|||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + UrlUtil.escapeUrlParam("FOO\\$BAR$2001-01-01"), capt.getValue().getURI().toString());
|
||||
Assert.assertEquals("http://foo/Observation?" + Observation.SP_CODE_VALUE_DATE + "=" + UrlUtil.escapeUrlParam("FOO\\$BAR$2001-01-01"), capt.getValue().getURI().toString());
|
||||
|
||||
}
|
||||
|
||||
|
@ -840,7 +810,7 @@ public class GenericClientTest {
|
|||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
|
||||
return new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -902,7 +872,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -925,7 +895,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -950,7 +920,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -974,7 +944,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -998,7 +968,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1022,7 +992,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1047,7 +1017,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1059,7 +1029,7 @@ public class GenericClientTest {
|
|||
|
||||
assertEquals("http://example.com/fhir/Patient?name=james", capt.getValue().getURI().toString());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = client.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.NAME.matches().values("AAA", "BBB", "C,C"))
|
||||
|
@ -1080,7 +1050,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(t-> new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(t -> new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1123,7 +1093,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1147,7 +1117,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1174,7 +1144,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1188,7 +1158,7 @@ public class GenericClientTest {
|
|||
assertEquals("http://example.com/fhir/Patient?identifier=http%3A%2F%2Fexample.com%2Ffhir%7CZZZ", capt.getValue().getURI().toString());
|
||||
assertEquals("myHeaderValue", capt.getValue().getFirstHeader("myHeaderName").getValue());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = client.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.IDENTIFIER.exactly().code("ZZZ"))
|
||||
|
@ -1197,7 +1167,7 @@ public class GenericClientTest {
|
|||
|
||||
assertEquals("http://example.com/fhir/Patient?identifier=ZZZ", capt.getAllValues().get(1).getURI().toString());
|
||||
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
response = client.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.IDENTIFIER.exactly().codings(new Coding("A", "B", "ZZZ"), new Coding("C", "D", "ZZZ")))
|
||||
|
@ -1223,7 +1193,7 @@ public class GenericClientTest {
|
|||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
|
||||
return new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1269,7 +1239,7 @@ public class GenericClientTest {
|
|||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
|
||||
return new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1309,7 +1279,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1317,7 +1287,7 @@ public class GenericClientTest {
|
|||
.forResource(Patient.class)
|
||||
.include(Patient.INCLUDE_ORGANIZATION)
|
||||
.include(Patient.INCLUDE_LINK.asRecursive())
|
||||
.include(Patient.INCLUDE_ALL.asNonRecursive())
|
||||
.include(IBaseResource.INCLUDE_ALL.asNonRecursive())
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
|
@ -1338,7 +1308,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1362,7 +1332,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1391,7 +1361,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1401,7 +1371,7 @@ public class GenericClientTest {
|
|||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
assertEquals(1, response.getEntry().size());
|
||||
Assert.assertEquals(1, response.getEntry().size());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
|
@ -1414,7 +1384,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
client.setPrettyPrint(true);
|
||||
|
@ -1439,7 +1409,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1466,7 +1436,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "INTERNAL ERRORS"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1494,7 +1464,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1517,7 +1487,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1541,7 +1511,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
// Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08
|
||||
// GMT"),
|
||||
// new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
|
||||
|
@ -1575,7 +1545,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1584,7 +1554,7 @@ public class GenericClientTest {
|
|||
.execute();
|
||||
|
||||
assertEquals("http://example.com/fhir", capt.getValue().getURI().toString());
|
||||
assertEquals(input.getEntry().get(0).getResource().getId(), response.getEntry().get(0).getResource().getId());
|
||||
Assert.assertEquals(input.getEntry().get(0).getResource().getId(), response.getEntry().get(0).getResource().getId());
|
||||
assertEquals(EncodingEnum.JSON.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
|
||||
|
||||
}
|
||||
|
@ -1600,7 +1570,7 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1610,7 +1580,7 @@ public class GenericClientTest {
|
|||
.execute();
|
||||
|
||||
assertEquals("http://example.com/fhir", capt.getValue().getURI().toString());
|
||||
assertEquals(input.getEntry().get(0).getResource().getId(), response.getEntry().get(0).getResource().getId());
|
||||
Assert.assertEquals(input.getEntry().get(0).getResource().getId(), response.getEntry().get(0).getResource().getId());
|
||||
assertEquals(EncodingEnum.XML.getResourceContentTypeNonLegacy() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(0).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
|
||||
|
||||
}
|
||||
|
@ -1625,9 +1595,9 @@ public class GenericClientTest {
|
|||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1662,13 +1632,13 @@ public class GenericClientTest {
|
|||
/*
|
||||
* Try fluent options
|
||||
*/
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
client.update().resource(p1).withId("123").execute();
|
||||
assertEquals(3, capt.getAllValues().size());
|
||||
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(2).getURI().toString());
|
||||
|
||||
String resourceText = "<Patient xmlns=\"http://hl7.org/fhir\"> </Patient>";
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
client.update().resource(resourceText).withId("123").execute();
|
||||
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(3).getURI().toString());
|
||||
assertEquals(resourceText, IOUtils.toString(((HttpPut) capt.getAllValues().get(3)).getEntity().getContent()));
|
||||
|
@ -1686,9 +1656,9 @@ public class GenericClientTest {
|
|||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22")});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), StandardCharsets.UTF_8));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
|
@ -1731,8 +1701,8 @@ public class GenericClientTest {
|
|||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
|
||||
Header[] headers = new Header[] {
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), StandardCharsets.UTF_8));
|
||||
Header[] headers = new Header[]{
|
||||
new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
|
||||
new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
|
||||
};
|
||||
|
@ -1759,9 +1729,9 @@ public class GenericClientTest {
|
|||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {});
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[]{});
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ourCtx.newXmlParser().encodeResourceToString(oo)), Charset.forName("UTF-8")));
|
||||
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ourCtx.newXmlParser().encodeResourceToString(oo)), StandardCharsets.UTF_8));
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
@ -1773,10 +1743,22 @@ public class GenericClientTest {
|
|||
MethodOutcome resp = client.validate(p1);
|
||||
assertEquals("http://example.com/fhir/Patient/$validate", capt.getValue().getURI().toString());
|
||||
oo = (OperationOutcome) resp.getOperationOutcome();
|
||||
assertEquals("OOOK", oo.getIssueFirstRep().getDiagnostics());
|
||||
Assert.assertEquals("OOOK", oo.getIssueFirstRep().getDiagnostics());
|
||||
|
||||
}
|
||||
|
||||
private String getPatientFeedWithOneResult() {
|
||||
|
||||
Bundle retVal = new Bundle();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily("Cardinal").addGiven("John");
|
||||
p.addIdentifier().setValue("PRP1660");
|
||||
retVal.addEntry().setResource(p);
|
||||
|
||||
return ourCtx.newXmlParser().encodeResourceToString(retVal);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
@ -1784,7 +1766,7 @@ public class GenericClientTest {
|
|||
|
||||
@BeforeClass
|
||||
public static void beforeClass() {
|
||||
ourCtx = FhirContext.forR4();
|
||||
ourCtx = FhirContext.forR5();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,144 @@
|
|||
package ca.uhn.fhir.rest.server;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||
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.param.TokenAndListParam;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.validation.FhirValidator;
|
||||
import ca.uhn.fhir.validation.ValidationResult;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.servlet.ServletHandler;
|
||||
import org.eclipse.jetty.servlet.ServletHolder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r5.model.HumanName;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class SearchR5Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchR5Test.class);
|
||||
private static CloseableHttpClient ourClient;
|
||||
private static FhirContext ourCtx = FhirContext.forR5();
|
||||
private static TokenAndListParam ourIdentifiers;
|
||||
private static String ourLastMethod;
|
||||
private static int ourPort;
|
||||
|
||||
private static Server ourServer;
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourLastMethod = null;
|
||||
ourIdentifiers = null;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearch() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=foo%7Cbar&_pretty=true");
|
||||
try (CloseableHttpResponse status = ourClient.execute(httpGet)) {
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(responseContent);
|
||||
// validate(ourCtx.newJsonParser().parseResource(responseContent));
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
|
||||
assertEquals("search", ourLastMethod);
|
||||
|
||||
assertEquals("foo", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getSystem());
|
||||
assertEquals("bar", ourIdentifiers.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValue());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void validate(IBaseResource theResource) {
|
||||
FhirValidator validatorModule = ourCtx.newValidator();
|
||||
ValidationResult result = validatorModule.validateWithResult(theResource);
|
||||
if (!result.isSuccessful()) {
|
||||
fail(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
@Override
|
||||
public Class<? extends IBaseResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
@Search()
|
||||
public List search(
|
||||
@RequiredParam(name = Patient.SP_IDENTIFIER) TokenAndListParam theIdentifiers) {
|
||||
ourLastMethod = "search";
|
||||
ourIdentifiers = theIdentifiers;
|
||||
ArrayList<Patient> retVal = new ArrayList<>();
|
||||
|
||||
for (int i = 0; i < 200; i++) {
|
||||
Patient patient = new Patient();
|
||||
patient.getIdElement().setValue("Patient/" + i + "/_history/222");
|
||||
ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.put(patient, BundleEntrySearchModeEnum.INCLUDE.getCode());
|
||||
patient.addName(new HumanName().setFamily("FAMILY"));
|
||||
patient.setActive(true);
|
||||
retVal.add(patient);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
JettyUtil.closeServer(ourServer);
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws Exception {
|
||||
ourServer = new Server(0);
|
||||
|
||||
DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider();
|
||||
|
||||
ServletHandler proxyHandler = new ServletHandler();
|
||||
RestfulServer servlet = new RestfulServer(ourCtx);
|
||||
servlet.setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
servlet.setPagingProvider(new FifoMemoryPagingProvider(10));
|
||||
|
||||
servlet.setResourceProviders(patientProvider);
|
||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||
ourServer.setHandler(proxyHandler);
|
||||
JettyUtil.startServer(ourServer);
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
builder.setConnectionManager(connectionManager);
|
||||
ourClient = builder.build();
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.eclipse" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.apache" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.thymeleaf" additivity="false" level="warn">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<!--
|
||||
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="trace">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
-->
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -0,0 +1,53 @@
|
|||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>4.0.0-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>hapi-fhir-validation-resources-r5</artifactId>
|
||||
<packaging>bundle</packaging>
|
||||
|
||||
<name>HAPI FHIR - Validation Resources (FHIR R5)</name>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.apache.felix</groupId>
|
||||
<artifactId>maven-bundle-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
<configuration>
|
||||
<instructions>
|
||||
<Fragment-Host>
|
||||
ca.uhn.hapi.fhir.hapi-fhir-base
|
||||
</Fragment-Host>
|
||||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue