Improve multiversion support

This commit is contained in:
James Agnew
2019-02-11 08:59:37 -05:00
parent e21e00cf09
commit c604d8be53
13 changed files with 458 additions and 159 deletions

View File

@@ -1,29 +1,16 @@
package ca.uhn.fhir.jpa.demo; package ca.uhn.fhir.jpa.starter;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.sql.Driver; import java.sql.Driver;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.model.entity.ModelConfig; 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 org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.hl7.fhir.instance.model.Subscription; import org.hl7.fhir.instance.model.Subscription;
import org.springframework.beans.factory.annotation.Autowire; import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement; import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3; import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
@@ -35,7 +22,7 @@ import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
*/ */
@Configuration @Configuration
@EnableTransactionManagement() @EnableTransactionManagement()
public class FhirServerConfig extends BaseJavaConfigDstu3 { public class FhirServerConfigCommon {
/** /**
* Configure FHIR properties around the the JPA server via this bean * Configure FHIR properties around the the JPA server via this bean
@@ -63,19 +50,6 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
return new ModelConfig(); return new ModelConfig();
} }
/**
* We override the paging provider definition so that we can customize
* the default/max page sizes for search results. You can set these however
* you want, although very large page sizes will require a lot of RAM.
*/
@Override
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
return pagingProvider;
}
/** /**
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a * The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
* directory called "jpaserver_derby_files". * directory called "jpaserver_derby_files".
@@ -93,31 +67,6 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
return retVal; return retVal;
} }
@Override
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName(HapiProperties.getPersistenceUnitName());
try {
retVal.setDataSource(dataSource());
} catch (Exception e) {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
}
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = HapiProperties.getProperties();
if (extraProperties == null) {
extraProperties = new Properties();
}
return extraProperties;
}
/** /**
* Do some fancy logging to create a nice access log that has details about each incoming request. * Do some fancy logging to create a nice access log that has details about each incoming request.
@@ -140,16 +89,4 @@ public class FhirServerConfig extends BaseJavaConfigDstu3 {
return retVal; return retVal;
} }
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
SubscriptionsRequireManualActivationInterceptorDstu3 retVal = new SubscriptionsRequireManualActivationInterceptorDstu3();
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
} }

View File

@@ -0,0 +1,57 @@
package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
@Autowired
private DataSource myDataSource;
/**
* We override the paging provider definition so that we can customize
* the default/max page sizes for search results. You can set these however
* you want, although very large page sizes will require a lot of RAM.
*/
@Override
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
return pagingProvider;
}
@Override
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName(HapiProperties.getPersistenceUnitName());
try {
retVal.setDataSource(myDataSource);
} catch (Exception e) {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
}
retVal.setJpaProperties(HapiProperties.getProperties());
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
}

View File

@@ -0,0 +1,57 @@
package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
@Autowired
private DataSource myDataSource;
/**
* We override the paging provider definition so that we can customize
* the default/max page sizes for search results. You can set these however
* you want, although very large page sizes will require a lot of RAM.
*/
@Override
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
return pagingProvider;
}
@Override
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName(HapiProperties.getPersistenceUnitName());
try {
retVal.setDataSource(myDataSource);
} catch (Exception e) {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
}
retVal.setJpaProperties(HapiProperties.getProperties());
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
}

View File

@@ -0,0 +1,57 @@
package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigR4;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
@Configuration
public class FhirServerConfigR4 extends BaseJavaConfigR4 {
@Autowired
private DataSource myDataSource;
/**
* We override the paging provider definition so that we can customize
* the default/max page sizes for search results. You can set these however
* you want, although very large page sizes will require a lot of RAM.
*/
@Override
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
return pagingProvider;
}
@Override
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
retVal.setPersistenceUnitName(HapiProperties.getPersistenceUnitName());
try {
retVal.setDataSource(myDataSource);
} catch (Exception e) {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
}
retVal.setJpaProperties(HapiProperties.getProperties());
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
}

View File

@@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.demo; package ca.uhn.fhir.jpa.starter;
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Configuration;

View File

@@ -1,12 +1,11 @@
package ca.uhn.fhir.jpa.demo; package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.ETagSupportEnum; import ca.uhn.fhir.rest.server.ETagSupportEnum;
import com.google.common.annotations.VisibleForTesting;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.Properties; import java.util.Properties;
@@ -30,22 +29,35 @@ public class HapiProperties {
public static final String TEST_PORT = "test.port"; public static final String TEST_PORT = "test.port";
public static final String SERVER_NAME = "server.name"; public static final String SERVER_NAME = "server.name";
public static final String SERVER_ID = "server.id"; public static final String SERVER_ID = "server.id";
private static Properties properties;
private static final String HAPI_PROPERTIES = "hapi.properties"; private static final String HAPI_PROPERTIES = "hapi.properties";
private static final String FHIR_VERSION = "fhir_version"; static final String FHIR_VERSION = "fhir_version";
private static final String DEFAULT_ENCODING = "default_encoding"; private static final String DEFAULT_ENCODING = "default_encoding";
private static final String ETAG_SUPPORT = "etag_support"; private static final String ETAG_SUPPORT = "etag_support";
private static Properties properties;
/**
* Force the configuration to be reloaded
*/
public static void forceReload() {
properties = null;
getProperties();
}
/**
* This is mostly here for unit tests. Use the actual properties file
* to set values
*/
@VisibleForTesting
public static void setProperty(String theKey, String theValue) {
getProperties().setProperty(theKey, theValue);
}
public static Properties getProperties() { public static Properties getProperties() {
if (properties == null) { if (properties == null) {
// Load the configurable properties file // Load the configurable properties file
InputStream in = null; try (InputStream in = HapiProperties.class.getClassLoader().getResourceAsStream(HAPI_PROPERTIES)){
try {
in = HapiProperties.class.getClassLoader().getResourceAsStream(HAPI_PROPERTIES);
HapiProperties.properties = new Properties(); HapiProperties.properties = new Properties();
HapiProperties.properties.load(in); HapiProperties.properties.load(in);
in.close();
} catch (Exception e) { } catch (Exception e) {
throw new ConfigurationException("Could not load HAPI properties", e); throw new ConfigurationException("Could not load HAPI properties", e);
} }
@@ -197,7 +209,7 @@ public class HapiProperties {
} }
public static String getServerBase() { public static String getServerBase() {
return HapiProperties.getProperty(SERVER_BASE, "/baseDstu3"); return HapiProperties.getProperty(SERVER_BASE, "/fhir");
} }
public static String getServerName() { public static String getServerName() {

View File

@@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.demo; package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
@@ -10,6 +10,7 @@ import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3; import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3; import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3; 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.JpaSystemProviderR4;
import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4; import ca.uhn.fhir.jpa.provider.r4.TerminologyUploaderProviderR4;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
@@ -21,21 +22,20 @@ import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor; import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Meta; import org.hl7.fhir.dstu3.model.Meta;
import org.hl7.fhir.instance.model.Subscription; import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletException; import javax.servlet.ServletException;
import java.util.List; import java.util.List;
public class JpaServerDemo extends RestfulServer { public class JpaRestfulServer extends RestfulServer {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final Logger ourLog = LoggerFactory.getLogger(JpaServerDemo.class); private AnnotationConfigApplicationContext appCtx;
private WebApplicationContext myAppCtx; @Override
public void destroy() {
appCtx.close();
}
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
@@ -43,69 +43,61 @@ public class JpaServerDemo extends RestfulServer {
super.initialize(); super.initialize();
/* /*
* We want to support FHIR DSTU2 format. This means that the server * Create a FhirContext object that uses the version of FHIR
* will use the DSTU2 bundle format and other DSTU2 encoding changes. * specified in the properties file.
*
* If you want to use DSTU1 instead, change the following line, and change the 2 occurrences of dstu2 in web.xml to dstu1
*/ */
FhirVersionEnum fhirVersion = HapiProperties.getFhirVersion(); FhirVersionEnum fhirVersion = HapiProperties.getFhirVersion();
setFhirContext(new FhirContext(fhirVersion)); setFhirContext(new FhirContext(fhirVersion));
// Get the spring context from the web container (it's declared in web.xml) appCtx = new AnnotationConfigApplicationContext();
myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
/* /*
* The BaseJavaConfigDstu2.java class is a spring configuration * ResourceProviders are fetched from the Spring context
* file which is automatically generated as a part of hapi-fhir-jpaserver-base and
* contains bean definitions for a resource provider for each resource type
*/
String resourceProviderBeanName;
if (fhirVersion == FhirVersionEnum.DSTU2) {
resourceProviderBeanName = "myResourceProvidersDstu2";
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
resourceProviderBeanName = "myResourceProvidersDstu3";
} else if (fhirVersion == FhirVersionEnum.R4) {
resourceProviderBeanName = "myResourceProviderR4";
} else {
throw new IllegalStateException();
}
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
setResourceProviders(beans);
/*
* The system provider implements non-resource-type methods, such as
* transaction, and global history.
*/ */
List<IResourceProvider> resourceProviders;
Object systemProvider; Object systemProvider;
if (fhirVersion == FhirVersionEnum.DSTU2) { if (fhirVersion == FhirVersionEnum.DSTU2) {
systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class); appCtx.register(FhirServerConfigDstu2.class, FhirServerConfigCommon.class);
appCtx.refresh();
resourceProviders = appCtx.getBean("myResourceProvidersDstu2", List.class);
systemProvider = appCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
} else if (fhirVersion == FhirVersionEnum.DSTU3) { } else if (fhirVersion == FhirVersionEnum.DSTU3) {
systemProvider = myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class); appCtx.register(FhirServerConfigDstu3.class, FhirServerConfigCommon.class);
appCtx.refresh();
resourceProviders = appCtx.getBean("myResourceProvidersDstu3", List.class);
systemProvider = appCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class);
} else if (fhirVersion == FhirVersionEnum.R4) { } else if (fhirVersion == FhirVersionEnum.R4) {
systemProvider = myAppCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class); appCtx.register(FhirServerConfigR4.class, FhirServerConfigCommon.class);
appCtx.refresh();
resourceProviders = appCtx.getBean("myResourceProvidersR4", List.class);
systemProvider = appCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class);
} else { } else {
throw new IllegalStateException(); throw new IllegalStateException();
} }
setPlainProviders(systemProvider); registerProviders(resourceProviders);
registerProvider(systemProvider);
/* /*
* The conformance provider exports the supported resources, search parameters, etc for * The conformance provider exports the supported resources, search parameters, etc for
* this server. The JPA version adds resource counts to the exported statement, so it * this server. The JPA version adds resourceProviders counts to the exported statement, so it
* is a nice addition. * is a nice addition.
*
* You can also create your own subclass of the conformance provider if you need to
* provide further customization of your server's CapabilityStatement
*/ */
if (fhirVersion == FhirVersionEnum.DSTU2) { if (fhirVersion == FhirVersionEnum.DSTU2) {
IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class); IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDao = appCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, myAppCtx.getBean(DaoConfig.class)); JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, appCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server"); confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server");
setServerConformanceProvider(confProvider); setServerConformanceProvider(confProvider);
} else if (fhirVersion == FhirVersionEnum.DSTU3) { } else if (fhirVersion == FhirVersionEnum.DSTU3) {
IFhirSystemDao<Bundle, Meta> systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class); IFhirSystemDao<Bundle, Meta> systemDao = appCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class)); JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, appCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server"); confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server");
setServerConformanceProvider(confProvider); setServerConformanceProvider(confProvider);
} else if (fhirVersion == FhirVersionEnum.R4) { } else if (fhirVersion == FhirVersionEnum.R4) {
IFhirSystemDao<Bundle, Meta> systemDao = myAppCtx.getBean("mySystemDaoR4", IFhirSystemDao.class); IFhirSystemDao<org.hl7.fhir.r4.model.Bundle, org.hl7.fhir.r4.model.Meta> systemDao = appCtx.getBean("mySystemDaoR4", IFhirSystemDao.class);
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class)); JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, appCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription("HAPI FHIR R4 Server"); confProvider.setImplementationDescription("HAPI FHIR R4 Server");
setServerConformanceProvider(confProvider); setServerConformanceProvider(confProvider);
} else { } else {
@@ -134,20 +126,19 @@ public class JpaServerDemo extends RestfulServer {
setDefaultResponseEncoding(HapiProperties.getDefaultEncoding()); setDefaultResponseEncoding(HapiProperties.getDefaultEncoding());
/* /*
* -- New in HAPI FHIR 1.5 --
* This configures the server to page search results to and from * This configures the server to page search results to and from
* the database, instead of only paging them to memory. This may mean * the database, instead of only paging them to memory. This may mean
* a performance hit when performing searches that return lots of results, * a performance hit when performing searches that return lots of results,
* but makes the server much more scalable. * but makes the server much more scalable.
*/ */
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class)); setPagingProvider(appCtx.getBean(DatabaseBackedPagingProvider.class));
/* /*
* This interceptor formats the output using nice colourful * This interceptor formats the output using nice colourful
* HTML output when the request is detected to come from a * HTML output when the request is detected to come from a
* browser. * browser.
*/ */
ResponseHighlighterInterceptor responseHighlighterInterceptor = myAppCtx.getBean(ResponseHighlighterInterceptor.class); ResponseHighlighterInterceptor responseHighlighterInterceptor = appCtx.getBean(ResponseHighlighterInterceptor.class);
this.registerInterceptor(responseHighlighterInterceptor); this.registerInterceptor(responseHighlighterInterceptor);
/* /*
@@ -170,16 +161,16 @@ public class JpaServerDemo extends RestfulServer {
*/ */
if (false) { // <-- DISABLED RIGHT NOW if (false) { // <-- DISABLED RIGHT NOW
if (fhirVersion == FhirVersionEnum.DSTU3) { if (fhirVersion == FhirVersionEnum.DSTU3) {
registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class)); registerProvider(appCtx.getBean(TerminologyUploaderProviderDstu3.class));
} else if (fhirVersion == FhirVersionEnum.R4) { } else if (fhirVersion == FhirVersionEnum.R4) {
registerProvider(myAppCtx.getBean(TerminologyUploaderProviderR4.class)); registerProvider(appCtx.getBean(TerminologyUploaderProviderR4.class));
} }
} }
// If you want to enable the $trigger-subscription operation to allow // If you want to enable the $trigger-subscription operation to allow
// manual triggering of a subscription delivery, enable this provider // manual triggering of a subscription delivery, enable this provider
if (false) { // <-- DISABLED RIGHT NOW if (false) { // <-- DISABLED RIGHT NOW
SubscriptionTriggeringProvider retriggeringProvider = myAppCtx.getBean(SubscriptionTriggeringProvider.class); SubscriptionTriggeringProvider retriggeringProvider = appCtx.getBean(SubscriptionTriggeringProvider.class);
registerProvider(retriggeringProvider); registerProvider(retriggeringProvider);
} }
} }

View File

@@ -1,7 +1,19 @@
# Adjust this to set the version of FHIR supported by this server. See
# FhirVersionEnum for a list of available constants.
fhir_version=DSTU3 fhir_version=DSTU3
# This is the address that the FHIR server will report as its own address.
# If this server will be deployed (for example) to an internet accessible
# server, put the DNS name of that server here.
server_address=http://localhost/fhir/
# This is the context path for the FHIR endpoint. If this is changed, the
# setting above should also be changed.
server.base=/fhir
default_encoding=JSON default_encoding=JSON
etag_support=ENABLED etag_support=ENABLED
server_address=http://mydomain.com/fhir/baseDstu3
default_page_size=20 default_page_size=20
max_page_size=200 max_page_size=200
allow_multiple_delete=true allow_multiple_delete=true
@@ -16,10 +28,10 @@ datasource.driver=org.apache.derby.jdbc.EmbeddedDriver
datasource.url=jdbc:derby:directory:target/jpaserver_derby_files;create=true datasource.url=jdbc:derby:directory:target/jpaserver_derby_files;create=true
datasource.username= datasource.username=
datasource.password= datasource.password=
server.base=/baseDstu3
server.name=Local Tester server.name=Local Tester
server.id=home server.id=home
test.port= test.port=
hibernate.dialect=ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect hibernate.dialect=ca.uhn.fhir.jpa.util.DerbyTenSevenHapiFhirDialect
hibernate.search.model_mapping=ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory hibernate.search.model_mapping=ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory
hibernate.format_sql=false hibernate.format_sql=false

View File

@@ -5,6 +5,7 @@
metadata-complete="false" metadata-complete="false"
version="3.1"> version="3.1">
<!--
<listener> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener> </listener>
@@ -17,12 +18,12 @@
<context-param> <context-param>
<param-name>contextConfigLocation</param-name> <param-name>contextConfigLocation</param-name>
<param-value> <param-value>
ca.uhn.fhir.jpa.demo.FhirServerConfig ca.uhn.fhir.jpa.starter.FhirServerConfig
</param-value> </param-value>
</context-param> </context-param>
-->
<!-- Servlets --> <!-- Servlets -->
<servlet> <servlet>
<servlet-name>spring</servlet-name> <servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
@@ -32,28 +33,20 @@
</init-param> </init-param>
<init-param> <init-param>
<param-name>contextConfigLocation</param-name> <param-name>contextConfigLocation</param-name>
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfig</param-value> <param-value>ca.uhn.fhir.jpa.starter.FhirTesterConfig</param-value>
</init-param> </init-param>
<load-on-startup>2</load-on-startup> <load-on-startup>2</load-on-startup>
</servlet> </servlet>
<servlet> <servlet>
<servlet-name>fhirServlet</servlet-name> <servlet-name>fhirServlet</servlet-name>
<servlet-class>ca.uhn.fhir.jpa.demo.JpaServerDemo</servlet-class> <servlet-class>ca.uhn.fhir.jpa.starter.JpaRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>FHIR JPA Server</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
<param-value>DSTU3</param-value>
</init-param>
<load-on-startup>1</load-on-startup> <load-on-startup>1</load-on-startup>
</servlet> </servlet>
<servlet-mapping> <servlet-mapping>
<servlet-name>fhirServlet</servlet-name> <servlet-name>fhirServlet</servlet-name>
<url-pattern>/baseDstu3/*</url-pattern> <url-pattern>/fhir/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet-mapping> <servlet-mapping>

View File

@@ -0,0 +1,94 @@
package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Patient;
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.util.PortUtil;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
public class ExampleServerDstu2IT {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
private static IGenericClient ourClient;
private static FhirContext ourCtx;
private static int ourPort;
private static Server ourServer;
private static String ourServerBase;
static {
HapiProperties.forceReload();
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "DSTU2");
HapiProperties.setProperty(HapiProperties.TEST_PORT, Integer.toString(PortUtil.findFreePort()));
ourCtx = FhirContext.forDstu2();
ourPort = HapiProperties.getTestPort();
}
@Test
public void testCreateAndRead() throws IOException {
ourLog.info("Base URL is: http://localhost:" + ourPort + HapiProperties.getServerBase());
String methodName = "testCreateResourceConditional";
Patient pt = new Patient();
pt.addName().addFamily(methodName);
IIdType id = ourClient.create().resource(pt).execute().getId();
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
assertEquals(methodName, pt2.getName().get(0).getFamily().get(0).getValue());
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
/*
* This runs under maven, and I'm not sure how else to figure out the target directory from code..
*/
String path = ExampleServerDstu2IT.class.getClassLoader().getResource(".keep_hapi-fhir-jpaserver-starter").getPath();
path = new File(path).getParent();
path = new File(path).getParent();
path = new File(path).getParent();
ourLog.info("Project base path is: {}", path);
if (ourPort == 0) {
ourPort = RandomServerPortProvider.findFreePort();
}
ourServer = new Server(ourPort);
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter");
webAppContext.setParentLoaderPriority(true);
ourServer.setHandler(webAppContext);
ourServer.start();
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
ourServerBase = "http://localhost:" + ourPort + HapiProperties.getServerBase();
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
ourClient.registerInterceptor(new LoggingInterceptor(true));
}
public static void main(String[] theArgs) throws Exception {
ourPort = 8080;
beforeClass();
}
}

View File

@@ -1,10 +1,11 @@
package ca.uhn.fhir.jpa.demo; package ca.uhn.fhir.jpa.starter;
import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertEquals;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import ca.uhn.fhir.util.PortUtil;
import org.eclipse.jetty.server.Server; import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext; import org.eclipse.jetty.webapp.WebAppContext;
import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Patient;
@@ -16,9 +17,9 @@ import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
public class ExampleServerIT { public class ExampleServerDstu3IT {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerIT.class); private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu3IT.class);
private static IGenericClient ourClient; private static IGenericClient ourClient;
private static FhirContext ourCtx; private static FhirContext ourCtx;
private static int ourPort; private static int ourPort;
@@ -27,16 +28,10 @@ public class ExampleServerIT {
private static String ourServerBase; private static String ourServerBase;
static { static {
switch (HapiProperties.getFhirVersion()) { HapiProperties.forceReload();
case DSTU2: HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "DSTU3");
ourCtx = FhirContext.forDstu2(); HapiProperties.setProperty(HapiProperties.TEST_PORT, Integer.toString(PortUtil.findFreePort()));
case R4:
ourCtx = FhirContext.forR4();
case DSTU3:
default:
ourCtx = FhirContext.forDstu3(); ourCtx = FhirContext.forDstu3();
}
ourPort = HapiProperties.getTestPort(); ourPort = HapiProperties.getTestPort();
} }
@@ -63,7 +58,7 @@ public class ExampleServerIT {
/* /*
* This runs under maven, and I'm not sure how else to figure out the target directory from code.. * This runs under maven, and I'm not sure how else to figure out the target directory from code..
*/ */
String path = ExampleServerIT.class.getClassLoader().getResource(".keep_hapi-fhir-jpaserver-starter").getPath(); String path = ExampleServerDstu3IT.class.getClassLoader().getResource(".keep_hapi-fhir-jpaserver-starter").getPath();
path = new File(path).getParent(); path = new File(path).getParent();
path = new File(path).getParent(); path = new File(path).getParent();
path = new File(path).getParent(); path = new File(path).getParent();

View File

@@ -0,0 +1,94 @@
package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
import ca.uhn.fhir.util.PortUtil;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.File;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
public class ExampleServerR4IT {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerR4IT.class);
private static IGenericClient ourClient;
private static FhirContext ourCtx;
private static int ourPort;
private static Server ourServer;
private static String ourServerBase;
static {
HapiProperties.forceReload();
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R4");
HapiProperties.setProperty(HapiProperties.TEST_PORT, Integer.toString(PortUtil.findFreePort()));
ourCtx = FhirContext.forR4();
ourPort = HapiProperties.getTestPort();
}
@Test
public void testCreateAndRead() throws IOException {
ourLog.info("Base URL is: http://localhost:" + ourPort + HapiProperties.getServerBase());
String methodName = "testCreateResourceConditional";
Patient pt = new Patient();
pt.addName().setFamily(methodName);
IIdType id = ourClient.create().resource(pt).execute().getId();
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
assertEquals(methodName, pt2.getName().get(0).getFamily());
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
@BeforeClass
public static void beforeClass() throws Exception {
/*
* This runs under maven, and I'm not sure how else to figure out the target directory from code..
*/
String path = ExampleServerR4IT.class.getClassLoader().getResource(".keep_hapi-fhir-jpaserver-starter").getPath();
path = new File(path).getParent();
path = new File(path).getParent();
path = new File(path).getParent();
ourLog.info("Project base path is: {}", path);
if (ourPort == 0) {
ourPort = RandomServerPortProvider.findFreePort();
}
ourServer = new Server(ourPort);
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/");
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter");
webAppContext.setParentLoaderPriority(true);
ourServer.setHandler(webAppContext);
ourServer.start();
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
ourServerBase = "http://localhost:" + ourPort + HapiProperties.getServerBase();
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
ourClient.registerInterceptor(new LoggingInterceptor(true));
}
public static void main(String[] theArgs) throws Exception {
ourPort = 8080;
beforeClass();
}
}

View File

@@ -1,4 +1,4 @@
package ca.uhn.fhir.jpa.demo; package ca.uhn.fhir.jpa.starter;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;