Add test data library endpoints to public server

This commit is contained in:
jamesagnew 2016-05-22 14:28:17 -04:00
parent a65191baa2
commit 831729b558
17 changed files with 692 additions and 214 deletions

View File

@ -34,13 +34,17 @@ import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import ca.uhn.fhirtest.config.TestDstu3Config;
import ca.uhn.fhirtest.config.TdlDstu2Config;
import ca.uhn.fhirtest.config.TdlDstu3Config;
import ca.uhn.fhirtest.config.TestDstu2Config;
public class TestRestfulServer extends RestfulServer {
public static final String FHIR_BASEURL_DSTU1 = "fhir.baseurl.dstu1";
public static final String FHIR_BASEURL_DSTU2 = "fhir.baseurl.dstu2";
public static final String FHIR_BASEURL_DSTU3 = "fhir.baseurl.dstu3";
public static final String FHIR_BASEURL_DSTU1 = "fhir.baseurl.dstu1";
public static final String FHIR_BASEURL_TDL2 = "fhir.baseurl.tdl2";
public static final String FHIR_BASEURL_TDL3 = "fhir.baseurl.tdl3";
private static final long serialVersionUID = 1L;
@ -92,11 +96,18 @@ public class TestRestfulServer extends RestfulServer {
baseUrlProperty = FHIR_BASEURL_DSTU1;
break;
}
case "TDL2":
case "DSTU2": {
myAppCtx = new AnnotationConfigWebApplicationContext();
myAppCtx.setServletConfig(getServletConfig());
myAppCtx.setParent(parentAppCtx);
myAppCtx.register(TestDstu2Config.class, WebsocketDstu2Config.class);
if ("TDL2".equals(fhirVersionParam.trim().toUpperCase())) {
myAppCtx.register(TdlDstu2Config.class);
baseUrlProperty = FHIR_BASEURL_TDL2;
} else {
myAppCtx.register(TestDstu2Config.class, WebsocketDstu2Config.class);
baseUrlProperty = FHIR_BASEURL_DSTU2;
}
myAppCtx.refresh();
setFhirContext(FhirContext.forDstu2());
beans = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
@ -106,14 +117,20 @@ public class TestRestfulServer extends RestfulServer {
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, myAppCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription(implDesc);
setServerConformanceProvider(confProvider);
baseUrlProperty = FHIR_BASEURL_DSTU2;
break;
}
case "TDL3":
case "DSTU3": {
myAppCtx = new AnnotationConfigWebApplicationContext();
myAppCtx.setServletConfig(getServletConfig());
myAppCtx.setParent(parentAppCtx);
myAppCtx.register(TestDstu3Config.class, WebsocketDstu3Config.class);
if ("TDL2".equals(fhirVersionParam.trim().toUpperCase())) {
myAppCtx.register(TdlDstu3Config.class);
baseUrlProperty = FHIR_BASEURL_TDL3;
} else {
myAppCtx.register(TestDstu3Config.class, WebsocketDstu3Config.class);
baseUrlProperty = FHIR_BASEURL_DSTU3;
}
myAppCtx.refresh();
setFhirContext(FhirContext.forDstu3());
beans = myAppCtx.getBean("myResourceProvidersDstu3", List.class);
@ -123,7 +140,6 @@ public class TestRestfulServer extends RestfulServer {
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription(implDesc);
setServerConformanceProvider(confProvider);
baseUrlProperty = FHIR_BASEURL_DSTU3;
break;
}
default:

View File

@ -0,0 +1,93 @@
package ca.uhn.fhirtest.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.to.FhirTesterMvcConfig;
import ca.uhn.fhir.to.TesterConfig;
//@formatter:off
/**
* This spring config file configures the web testing module. It serves two
* purposes:
* 1. It imports FhirTesterMvcConfig, which is the spring config for the
* tester itself
* 2. It tells the tester which server(s) to talk to, via the testerConfig()
* method below
*/
//@Configuration
//@Import(FhirTesterMvcConfig.class)
//@ComponentScan(basePackages = "ca.uhn.fhirtest.mvc")
@Configuration
@Import(FhirTesterMvcConfig.class)
public class FhirTesterConfig {
/**
* This bean tells the testing webpage which servers it should configure itself
* to communicate with. In this example we configure it to talk to the local
* server, as well as one public server. If you are creating a project to
* deploy somewhere else, you might choose to only put your own server's
* address here.
*
* Note the use of the ${serverBase} variable below. This will be replaced with
* the base URL as reported by the server itself. Often for a simple Tomcat
* (or other container) installation, this will end up being something
* like "http://localhost:8080/hapi-fhir-jpaserver-example". If you are
* deploying your server to a place with a fully qualified domain name,
* you might want to use that instead of using the variable.
*/
@Bean
public TesterConfig testerConfig() {
TesterConfig retVal = new TesterConfig();
retVal
.addServer()
.withId("hapi_dev")
.withFhirVersion(FhirVersionEnum.DSTU2)
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu2")
.withName("UHN/HAPI Server (DSTU2 FHIR)")
.addServer()
.withId("home_21")
.withFhirVersion(FhirVersionEnum.DSTU3)
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu3")
.withName("UHN/HAPI Server (STU3 FHIR)")
.addServer()
.withId("home")
.withFhirVersion(FhirVersionEnum.DSTU1)
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu1")
.withName("UHN/HAPI Server (DSTU1 FHIR)")
.addServer()
.withId("tdl_d2")
.withFhirVersion(FhirVersionEnum.DSTU2)
.withBaseUrl("http://fhirtest.uhn.ca/testDataLibraryDstu2")
.withName("Test Data Library (DSTU2 FHIR)")
.allowsApiKey()
.addServer()
.withId("tdl_d3")
.withFhirVersion(FhirVersionEnum.DSTU3)
.withBaseUrl("http://fhirtest.uhn.ca/testDataLibraryStu3")
.withName("Test Data Library (DSTU3 FHIR)")
.allowsApiKey()
.addServer()
.withId("hi2")
.withFhirVersion(FhirVersionEnum.DSTU2)
.withBaseUrl("http://fhir2.healthintersections.com.au/open")
.withName("Health Intersections (DSTU2 FHIR)")
.addServer()
.withId("hi3")
.withFhirVersion(FhirVersionEnum.DSTU3)
.withBaseUrl("http://fhir3.healthintersections.com.au/open")
.withName("Health Intersections (STU3 FHIR)")
.addServer()
.withId("spark2")
.withFhirVersion(FhirVersionEnum.DSTU2)
.withBaseUrl("http://spark-dstu2.furore.com/fhir")
.withName("Spark - Furore (DSTU2 FHIR)");
return retVal;
}
}
//@formatter:on

View File

@ -0,0 +1,121 @@
package ca.uhn.fhirtest.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
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.DependsOn;
import org.springframework.context.annotation.Import;
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 ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhirtest.interceptor.TdlSecurityInterceptor;
@Configuration
@Import(CommonConfig.class)
@EnableTransactionManagement()
public class TdlDstu2Config extends BaseJavaConfigDstu2 {
public static final String FHIR_LUCENE_LOCATION_DSTU2 = "${fhir.lucene.location.tdl2}";
public static final String FHIR_DB_LOCATION_DSTU2 = "${fhir.db.location.tdl2}";
@Value(FHIR_DB_LOCATION_DSTU2)
private String myFhirDbLocation;
@Value(FHIR_LUCENE_LOCATION_DSTU2)
private String myFhirLuceneLocation;
/**
* This lets the "@Value" fields reference properties from the properties file
*/
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean
public IServerInterceptor securityInterceptor() {
return new TdlSecurityInterceptor();
}
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
retVal.setAllowInlineMatchUrlReferences(true);
retVal.setAllowExternalReferences(true);
retVal.getTreatBaseUrlsAsLocal().add("http://fhirtest.uhn.ca/testDataLibraryDstu2");
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/testDataLibraryDstu2");
return retVal;
}
@Bean(name = "myPersistenceDataSourceDstu1", destroyMethod = "close")
@DependsOn("dbServer")
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.ClientDriver());
// retVal.setUrl("jdbc:derby:directory:" + myFhirDbLocation + ";create=true");
retVal.setUrl("jdbc:derby://localhost:1527/" + myFhirDbLocation + ";create=true");
retVal.setUsername("SA");
retVal.setPassword("SA");
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu2");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
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.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.default.directory_provider" ,"filesystem");
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");
return extraProperties;
}
@Bean(autowire=Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
return new SubscriptionsRequireManualActivationInterceptorDstu2();
}
}

View File

@ -0,0 +1,167 @@
package ca.uhn.fhirtest.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
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.DependsOn;
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 ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import ca.uhn.fhirtest.interceptor.TdlSecurityInterceptor;
@Configuration
@Import(CommonConfig.class)
@EnableTransactionManagement()
public class TdlDstu3Config extends BaseJavaConfigDstu3 {
public static final String FHIR_LUCENE_LOCATION_DSTU3 = "${fhir.lucene.location.tdl3}";
public static final String FHIR_DB_LOCATION_DSTU3 = "${fhir.db.location.tdl3}";
@Value(FHIR_DB_LOCATION_DSTU3)
private String myFhirDbLocation;
@Value(FHIR_LUCENE_LOCATION_DSTU3)
private String myFhirLuceneLocation;
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
retVal.setAllowInlineMatchUrlReferences(true);
retVal.setAllowExternalReferences(true);
retVal.getTreatBaseUrlsAsLocal().add("http://fhirtest.uhn.ca/testDataLibraryStu3");
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/testDataLibraryStu3");
return retVal;
}
@Bean
public IServerInterceptor securityInterceptor() {
return new TdlSecurityInterceptor();
}
@Bean(name = "myPersistenceDataSourceDstu3", destroyMethod = "close")
@DependsOn("dbServer")
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.ClientDriver());
// retVal.setUrl("jdbc:derby:directory:" + myFhirDbLocation + ";create=true");
retVal.setUrl("jdbc:derby://localhost:1527/" + myFhirDbLocation + ";create=true");
retVal.setUsername("SA");
retVal.setPassword("SA");
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu3");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
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.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.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(instanceValidatorDstu3());
requestValidator.setIgnoreValidatorExceptions(true);
return requestValidator;
}
/**
* Bean which validates outgoing responses
*/
@Bean
@Lazy
public ResponseValidatingInterceptor responseValidatingInterceptor() {
ResponseValidatingInterceptor responseValidator = new ResponseValidatingInterceptor();
responseValidator.setResponseHeaderValueNoIssues("Validation did not detect any issues");
responseValidator.setFailOnSeverity(null);
responseValidator.setAddResponseHeaderOnSeverity(null);
responseValidator.setAddResponseOutcomeHeaderOnSeverity(ResultSeverityEnum.INFORMATION);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.METADATA);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_SERVER);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.GET_PAGE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_INSTANCE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_SYSTEM);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.HISTORY_TYPE);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.SEARCH_SYSTEM);
responseValidator.addExcludeOperationType(RestOperationTypeEnum.SEARCH_TYPE);
responseValidator.addValidatorModule(instanceValidatorDstu3());
responseValidator.setIgnoreValidatorExceptions(true);
return responseValidator;
}
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
return new SubscriptionsRequireManualActivationInterceptorDstu3();
}
@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();
}
}

View File

@ -0,0 +1,57 @@
package ca.uhn.fhirtest.interceptor;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
public class TdlSecurityInterceptor extends AuthorizationInterceptor {
private HashSet<String> myTokens;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TdlSecurityInterceptor.class);
public TdlSecurityInterceptor() {
String passwordsString = System.getProperty("fhir.tdlpass");
String[] passwords = passwordsString.split(",");
myTokens = new HashSet<String>(Arrays.asList(passwords));
ourLog.info("We have {} valid security tokens", myTokens.size());
}
@Override
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
String authHeader = theRequestDetails.getHeader("Authorization");
if (isBlank(authHeader)) {
return new RuleBuilder()
.allow().read().allResources().withAnyId().andThen()
.allow().metadata().andThen()
.denyAll("Anonymous write access denied on this server")
.build();
}
if (!authHeader.startsWith("Bearer ")) {
throw new ForbiddenOperationException("Invalid bearer token, must be in the form \"Authorization: Bearer [token]\"");
}
String token = authHeader.substring("Bearer ".length()).trim();
if (!myTokens.contains(token)) {
ourLog.error("Invalid token '{}' - Valid are: {}", token, myTokens);
throw new ForbiddenOperationException("Unknown/expired bearer token");
}
ourLog.info("User logged in with bearer token: " + token.substring(0, 4) + "...");
return new RuleBuilder()
.allowAll()
.build();
}
}

View File

@ -1,48 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p" xmlns:tx="http://www.springframework.org/schema/tx" xmlns:task="http://www.springframework.org/schema/task" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-2.0.xsd
"
default-autowire="no" default-lazy-init="false">
<context:annotation-config />
<context:mbean-server />
<bean id="myDaoConfig" class="ca.uhn.fhir.jpa.dao.DaoConfig">
<property name="subscriptionEnabled" value="true"></property>
<property name="subscriptionPurgeInactiveAfterSeconds" value="3600" /> <!-- 1 hour -->
<property name="subscriptionPollDelay" value="5000"></property>
<property name="allowMultipleDelete" value="true"/>
</bean>
<util:list id="myServerInterceptors">
<ref bean="myLoggingInterceptor"/>
</util:list>
<!--for mysql-->
<!--
<bean id="dbServer" class="ca.uhn.fhirtest.MySqlServer">
</bean>
-->
<bean id="dbServer" class="ca.uhn.fhirtest.DerbyNetworkServer">
</bean>
<!--
Do some fancy logging to create a nice access log that has details
about each incoming request.
-->
<bean id="myLoggingInterceptor" class="ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor">
<property name="loggerName" value="fhirtest.access"/>
<property name="messageFormat"
value="Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]"/>
<property name="logExceptions" value="true"/>
<property name="errorMessageFormat" value="ERROR - ${requestVerb} ${requestUrl}"/>
</bean>
</beans>

View File

@ -1,16 +0,0 @@
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context" xmlns:security="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
xsi:schemaLocation="http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2-2.0.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<context:component-scan base-package="ca.uhn.fhirtest.mvc" />
<mvc:annotation-driven />
</beans>

View File

@ -18,63 +18,28 @@
</param-value>
</context-param>
<!--
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/hapi-fhir-server-config.xml
/WEB-INF/hapi-fhir-tester-application-context.xml
/WEB-INF/hapi-fhir-tester-config.xml
</param-value>
</context-param>
-->
<!--
classpath:/hapi-fhir-server-database-config-dstu1.xml
classpath:/hapi-fhir-server-database-config-dstu2.xml
classpath:hapi-fhir-server-resourceproviders-dstu1.xml
classpath:hapi-fhir-server-resourceproviders-dstu2.xml
classpath:fhir-spring-subscription-config-dstu2.xml
classpath:fhir-spring-search-config-dstu2.xml
-->
<!-- Servlets -->
<!-- Servlets -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/hapi-fhir-tester-application-context.xml
/WEB-INF/hapi-fhir-tester-config.xml
</param-value>
<param-value>ca.uhn.fhirtest.config.FhirTesterConfig</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<!--
<servlet>
<servlet-name>fhirServletBase</servlet-name>
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>UHN Test Server (Base / DSTU1 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
<param-value>BASE</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
-->
<servlet>
<servlet-name>fhirServletDstu1</servlet-name>
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>UHN Test Server (DSTU 1 Resources)</param-value>
<param-value>UHN Test Server (DSTU1 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
@ -88,7 +53,7 @@
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>UHN Test Server (DSTU 2 Resources)</param-value>
<param-value>UHN Test Server (DSTU2 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
@ -102,7 +67,7 @@
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>UHN Test Server (DSTU 3 Resources)</param-value>
<param-value>UHN Test Server (STU3 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
@ -111,6 +76,34 @@
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>fhirServletTdl2</servlet-name>
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>Test Data Library (DSTU2 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
<param-value>TDL2</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>fhirServletTdl3</servlet-name>
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>FHIR Test Data Library (STU3 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
<param-value>TDL3</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>fhirServletDstu1</servlet-name>
<url-pattern>/base/*</url-pattern>
@ -134,6 +127,24 @@
<servlet-name>fhirServletDstu3</servlet-name>
<url-pattern>/baseDstu3/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServletDstu3</servlet-name>
<url-pattern>/baseStu3/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServletTdl2</servlet-name>
<url-pattern>/testDataLibraryDstu2/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServletTdl3</servlet-name>
<url-pattern>/testDataLibraryDstu3/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServletTdl3</servlet-name>
<url-pattern>/testDataLibraryStu3/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServletDstu2</servlet-name>

View File

@ -1,5 +1,7 @@
package ca.uhn.fhirtest;
import java.util.UUID;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.hl7.fhir.dstu3.model.Organization;
@ -20,18 +22,25 @@ public class UhnFhirTestApp {
public static void main(String[] args) throws Exception {
int myPort = 8888;
String base = "http://localhost:" + myPort + "/baseDstu3";
String base = "http://localhost:" + myPort + "/baseDstu2";
// new File("target/testdb").mkdirs();
System.setProperty("fhir.db.location", "./target/testdb");
System.setProperty("fhir.db.location.dstu2", "./target/testdb_dstu2");
System.setProperty("fhir.db.location.dstu3", "./target/testdb_dstu3");
System.setProperty("fhir.lucene.location.dstu2", "./target/testlucene_dstu2");
System.setProperty("fhir.db.location.dstu3", "./target/testdb_dstu3");
System.setProperty("fhir.lucene.location.dstu3", "./target/testlucene_dstu3");
System.setProperty("fhir.db.location.tdl2", "./target/testdb_tdl2");
System.setProperty("fhir.lucene.location.tdl2", "./target/testlucene_tdl2");
System.setProperty("fhir.db.location.tdl3", "./target/testdb_tdl3");
System.setProperty("fhir.lucene.location.tdl3", "./target/testlucene_tdl3");
System.setProperty("fhir.baseurl.dstu1", base.replace("Dstu2", "Dstu1"));
System.setProperty("fhir.baseurl.dstu2", base);
System.setProperty("fhir.baseurl.dstu3", base.replace("Dstu2", "Dstu3"));
System.setProperty("fhir.baseurl.tdl2", base.replace("baseDstu2", "testDataLibraryDstu2"));
System.setProperty("fhir.baseurl.tdl3", base.replace("baseDstu2", "testDataLibraryStu3"));
System.setProperty("fhir.tdlpass", "aa,bb");
Server server = new Server(myPort);
WebAppContext root = new WebAppContext();
@ -53,7 +62,7 @@ public class UhnFhirTestApp {
// base = "http://fhir.healthintersections.com.au/open";
// base = "http://spark.furore.com/fhir";
if (true) {
if (false) {
FhirContext ctx = FhirContext.forDstu3();
IGenericClient client = ctx.newRestfulGenericClient(base);
// client.setLogRequestAndResponse(true);
@ -67,7 +76,7 @@ public class UhnFhirTestApp {
p1.getMeta().addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource");
p1.addIdentifier().setSystem("foo:bar").setValue("12345");
p1.addName().addFamily("Smith").addGiven("John");
p1.getManagingOrganization().setReferenceElement(orgId);
p1.getManagingOrganization().setReferenceElement(orgId.toUnqualifiedVersionless());
Subscription subs = new Subscription();
subs.setStatus(SubscriptionStatus.ACTIVE);

View File

@ -83,9 +83,11 @@ public class BaseController {
final String serverId = theRequest.getServerIdWithDefault(myConfig);
final String serverBase = theRequest.getServerBase(theServletRequest, myConfig);
final String serverName = theRequest.getServerName(myConfig);
final String apiKey = theRequest.getApiKey(theServletRequest, myConfig);
theModel.put("serverId", serverId);
theModel.put("base", serverBase);
theModel.put("baseName", serverName);
theModel.put("apiKey", apiKey);
theModel.put("resourceName", defaultString(theRequest.getResource()));
theModel.put("encoding", theRequest.getEncoding());
theModel.put("pretty", theRequest.getPretty());

View File

@ -20,6 +20,7 @@ public class TesterConfig {
public static final String SYSPROP_FORCE_SERVERS = "ca.uhn.fhir.to.TesterConfig_SYSPROP_FORCE_SERVERS";
private ITestingUiClientFactory myClientFactory;
private LinkedHashMap<String, Boolean> myIdToAllowsApiKey = new LinkedHashMap<String, Boolean>();
private LinkedHashMap<String, FhirVersionEnum> myIdToFhirVersion = new LinkedHashMap<String, FhirVersionEnum>();
private LinkedHashMap<String, String> myIdToServerBase = new LinkedHashMap<String, String>();
private LinkedHashMap<String, String> myIdToServerName = new LinkedHashMap<String, String>();
@ -41,6 +42,7 @@ public class TesterConfig {
myIdToFhirVersion.put(next.myId, next.myVersion);
myIdToServerBase.put(next.myId, next.myBaseUrl);
myIdToServerName.put(next.myId, next.myName);
myIdToAllowsApiKey.put(next.myId, next.myAllowsApiKey);
}
myServerBuilders.clear();
}
@ -53,6 +55,10 @@ public class TesterConfig {
return true;
}
public LinkedHashMap<String, Boolean> getIdToAllowsApiKey() {
return myIdToAllowsApiKey;
}
public LinkedHashMap<String, FhirVersionEnum> getIdToFhirVersion() {
return myIdToFhirVersion;
}
@ -131,11 +137,14 @@ public class TesterConfig {
public interface IServerBuilderStep5 {
IServerBuilderStep1 addServer();
IServerBuilderStep5 allowsApiKey();
}
public class ServerBuilder implements IServerBuilderStep1, IServerBuilderStep2, IServerBuilderStep3, IServerBuilderStep4, IServerBuilderStep5 {
private boolean myAllowsApiKey;
private String myBaseUrl;
private String myId;
private String myName;
@ -148,6 +157,12 @@ public class TesterConfig {
return retVal;
}
@Override
public IServerBuilderStep5 allowsApiKey() {
myAllowsApiKey = true;
return this;
}
@Override
public IServerBuilderStep4 withBaseUrl(String theBaseUrl) {
Validate.notBlank(theBaseUrl, "theBaseUrl can not be blank");

View File

@ -0,0 +1,27 @@
package ca.uhn.fhir.to.client;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.client.IGenericClient;
import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor;
import ca.uhn.fhir.util.ITestingUiClientFactory;
public class BearerTokenClientFactory implements ITestingUiClientFactory {
@Override
public IGenericClient newClient(FhirContext theFhirContext, HttpServletRequest theRequest, String theServerBaseUrl) {
// Create a client
IGenericClient client = theFhirContext.newRestfulGenericClient(theServerBaseUrl);
String apiKey = theRequest.getParameter("apiKey");
if (isNotBlank(apiKey)) {
client.registerInterceptor(new BearerTokenAuthInterceptor(apiKey));
}
return client;
}
}

View File

@ -187,4 +187,18 @@ public class HomeRequest {
return theCtx.newXmlParser();
}
public String getApiKey(HttpServletRequest theServletRequest, TesterConfig theConfig) {
Boolean allowsApiKey;
if (isBlank(myServerId) && !theConfig.getIdToFhirVersion().containsKey(myServerId)) {
allowsApiKey = theConfig.getIdToAllowsApiKey().entrySet().iterator().next().getValue();
} else {
allowsApiKey = theConfig.getIdToAllowsApiKey().get(myServerId);
}
if (!Boolean.TRUE.equals(allowsApiKey)) {
return null;
}
return defaultString(theServletRequest.getParameter("apiKey"));
}
}

View File

@ -30,8 +30,13 @@
th:text="${extraBreadcrumb}"></span>
</div>
</div>
<div class="navbar-collapse collapse">
<ul class="nav navbar-nav navbar-right">
<!--
Server Selection Dropdown
-->
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span id="serverSelectorFhirIcon" class="glyphicon glyphicon-fire topbarIcon" />&nbsp;<span id="serverSelectorName" th:text="'Server: ' + ${baseName}" />&nbsp;<span class="caret" /></a>
<ul class="dropdown-menu" role="menu">
@ -45,9 +50,38 @@
</li>
</ul>
</li>
<!--
Security Dropdown
-->
<th:block th:if="${apiKey != null}">
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown"><span class="fa fa-key topbarIcon" />&nbsp;API Key&nbsp;<span class="caret" /></a>
<ul class="dropdown-menu" role="menu">
<div style="padding: 10px;">
<p>If your chosen server requires an API key / Bearer token, enter it here:</p>
<input type="text" name="apiKey" id="apiKey" th:value="${apiKey}"/>
<script type="text/javascript">
$('#apiKey').on('click', function(event){
// The event won't be propagated up to the document NODE and
// therefore delegated events won't be fired
event.stopPropagation();
});
</script>
</div>
</ul>
</li>
</th:block>
<!--
SourceCode / About this Server
-->
<th:block th:include="tmpl-navbar-top-farright :: farright"/>
</ul>
</div>
</div>
</div>
</html>

View File

@ -24,98 +24,13 @@ import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
@Configuration
@EnableTransactionManagement()
public class FhirServerConfig extends BaseJavaConfigDstu2 {
public class FhirServerConfig {
/**
* Configure FHIR properties around the the JPA server via this bean
*/
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
return retVal;
}
/**
* 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".
*
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
*/
@Bean(destroyMethod = "close")
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
retVal.setUrl("jdbc:derby:directory:target/jpaserver_derby_files;create=true");
retVal.setUsername("");
retVal.setPassword("");
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
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.default.directory_provider", "filesystem");
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
return extraProperties;
}
/**
* Do some fancy logging to create a nice access log that has details about each incoming request.
*/
public IServerInterceptor loggingInterceptor() {
LoggingInterceptor retVal = new LoggingInterceptor();
retVal.setLoggerName("fhirtest.access");
retVal.setMessageFormat(
"Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]");
retVal.setLogExceptions(true);
retVal.setErrorMessageFormat("ERROR - ${requestVerb} ${requestUrl}");
return retVal;
}
/**
* This interceptor adds some pretty syntax highlighting in responses when a browser is detected
*/
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor responseHighlighterInterceptor() {
ResponseHighlighterInterceptor retVal = new ResponseHighlighterInterceptor();
return retVal;
}
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
SubscriptionsRequireManualActivationInterceptorDstu2 retVal = new SubscriptionsRequireManualActivationInterceptorDstu2();
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.test;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.to.FhirTesterMvcConfig;
import ca.uhn.fhir.to.TesterConfig;
//@formatter:off
/**
* This spring config file configures the web testing module. It serves two
* purposes:
* 1. It imports FhirTesterMvcConfig, which is the spring config for the
* tester itself
* 2. It tells the tester which server(s) to talk to, via the testerConfig()
* method below
*/
@Configuration
@Import(FhirTesterMvcConfig.class)
public class FhirTesterConfig {
/**
* This bean tells the testing webpage which servers it should configure itself
* to communicate with. In this example we configure it to talk to the local
* server, as well as one public server. If you are creating a project to
* deploy somewhere else, you might choose to only put your own server's
* address here.
*
* Note the use of the ${serverBase} variable below. This will be replaced with
* the base URL as reported by the server itself. Often for a simple Tomcat
* (or other container) installation, this will end up being something
* like "http://localhost:8080/hapi-fhir-jpaserver-example". If you are
* deploying your server to a place with a fully qualified domain name,
* you might want to use that instead of using the variable.
*/
@Bean
public TesterConfig testerConfig() {
TesterConfig retVal = new TesterConfig();
retVal
.addServer()
.withId("hapi")
.withFhirVersion(FhirVersionEnum.DSTU2)
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu2")
.withName("Public HAPI Test Server")
.allowsApiKey()
.addServer()
.withId("home")
.withFhirVersion(FhirVersionEnum.DSTU2)
.withBaseUrl("${serverBase}/baseDstu2")
.withName("Local Tester");
return retVal;
}
}
//@formatter:on

View File

@ -6,27 +6,31 @@
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/hapi-fhir-tester-application-context.xml
classpath:hapi-fhir-tester-config.xml
ca.uhn.fhir.jpa.test.FhirServerConfig
</param-value>
</context-param>
<!-- Processes application requests -->
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/hapi-fhir-tester-application-context.xml
classpath:hapi-fhir-tester-config.xml
</param-value>
<param-name>contextClass</param-name>
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>ca.uhn.fhir.jpa.test.FhirTesterConfig</param-value>
</init-param>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>