Fixed FHIR subscriptions with criteria previously limited to 10, added fhir criteria validation before create/update, added dstu2 configurations
This commit is contained in:
parent
959cb700fd
commit
ad3d5489ea
|
@ -2046,7 +2046,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
return paramMap;
|
||||
}
|
||||
|
||||
protected static List<NameValuePair> translateMatchUrl(String theMatchUrl) {
|
||||
public static List<NameValuePair> translateMatchUrl(String theMatchUrl) {
|
||||
List<NameValuePair> parameters;
|
||||
String matchUrl = theMatchUrl;
|
||||
int questionMarkIndex = matchUrl.indexOf('?');
|
||||
|
|
|
@ -29,9 +29,12 @@ import javax.annotation.PostConstruct;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
@ -63,6 +66,7 @@ import ca.uhn.fhir.rest.server.interceptor.*;
|
|||
|
||||
public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterceptorAdapter {
|
||||
|
||||
private static final Integer MAX_SUBSCRIPTION_RESULTS = 10000;
|
||||
private static volatile ExecutorService executor;
|
||||
private final static int MAX_THREADS = 1;
|
||||
|
||||
|
@ -71,13 +75,13 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
|||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
private boolean myNotifyOnDelete = false;
|
||||
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
||||
|
||||
@Autowired
|
||||
@Qualifier("mySubscriptionDaoDstu2")
|
||||
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
||||
|
||||
private boolean myNotifyOnDelete = false;
|
||||
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
||||
|
||||
/**
|
||||
* Check subscriptions and send notifications or payload
|
||||
*
|
||||
|
@ -205,6 +209,7 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
|||
req.setSubRequest(true);
|
||||
|
||||
IFhirResourceDao<? extends IBaseResource> responseDao = mySubscriptionDao.getDao(responseResourceDef.getImplementingClass());
|
||||
responseCriteriaUrl.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
|
||||
return responseResults;
|
||||
}
|
||||
|
@ -265,7 +270,12 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
|||
RequestDetails req = new ServletSubRequestDetails();
|
||||
req.setSubRequest(true);
|
||||
|
||||
map.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||
IBundleProvider subscriptionBundleList = mySubscriptionDao.search(map, req);
|
||||
if (subscriptionBundleList.size() >= MAX_SUBSCRIPTION_RESULTS) {
|
||||
ourLog.error("Currently over "+MAX_SUBSCRIPTION_RESULTS+" subscriptions. Some subscriptions have not been loaded.");
|
||||
}
|
||||
|
||||
List<IBaseResource> resourceList = subscriptionBundleList.getResources(0, subscriptionBundleList.size());
|
||||
|
||||
for (IBaseResource resource : resourceList) {
|
||||
|
@ -398,4 +408,58 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
|||
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
|
||||
mySubscriptionDao = theSubscriptionDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
|
||||
//check the subscription criteria to see if its valid before creating or updating a subscription
|
||||
if (RestOperationTypeEnum.CREATE.equals(theOperation) || RestOperationTypeEnum.UPDATE.equals(theOperation)) {
|
||||
String resourceType = theDetails.getResourceType();
|
||||
ourLog.info("prehandled resource type: " + resourceType);
|
||||
if (resourceType != null && resourceType.equals(Subscription.class.getSimpleName())) {
|
||||
Subscription subscription = (Subscription) theDetails.getResource();
|
||||
if (subscription != null) {
|
||||
checkSubscriptionCriterias(subscription);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.incomingRequestPreHandled(theOperation, theDetails);
|
||||
}
|
||||
|
||||
private void checkSubscriptionCriterias(Subscription subscription){
|
||||
try {
|
||||
IBundleProvider results = executeSubscriptionCriteria(subscription, null);
|
||||
}catch (Exception e){
|
||||
throw new InvalidRequestException("Invalid criteria");
|
||||
}
|
||||
}
|
||||
|
||||
private IBundleProvider executeSubscriptionCriteria(Subscription subscription, IIdType idType){
|
||||
//run the subscriptions query and look for matches, add the id as part of the criteria to avoid getting matches of previous resources rather than the recent resource
|
||||
String criteria = subscription.getCriteria();
|
||||
if(idType != null) {
|
||||
criteria += "&_id=" + idType.getResourceType() + "/" + idType.getIdPart();
|
||||
}
|
||||
|
||||
IBundleProvider results = getBundleProvider(criteria);
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encoding from the criteria or return JSON encoding if its not found
|
||||
*
|
||||
* @param criteria
|
||||
* @return
|
||||
*/
|
||||
private EncodingEnum getEncoding(String criteria) {
|
||||
//check criteria
|
||||
String params = criteria.substring(criteria.indexOf('?') + 1);
|
||||
List<NameValuePair> paramValues = URLEncodedUtils.parse(params, Constants.CHARSET_UTF8, '&');
|
||||
for (NameValuePair nameValuePair : paramValues) {
|
||||
if (Constants.PARAM_FORMAT.equals(nameValuePair.getName())) {
|
||||
return EncodingEnum.forContentType(nameValuePair.getValue());
|
||||
}
|
||||
}
|
||||
return EncodingEnum.JSON;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -30,9 +30,12 @@ import javax.annotation.PostConstruct;
|
|||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.client.utils.URLEncodedUtils;
|
||||
import org.apache.http.entity.ContentType;
|
||||
import org.apache.http.entity.StringEntity;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
|
@ -61,6 +64,7 @@ import ca.uhn.fhir.rest.server.interceptor.*;
|
|||
|
||||
public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterceptorAdapter {
|
||||
|
||||
private static final Integer MAX_SUBSCRIPTION_RESULTS = 10000;
|
||||
private static volatile ExecutorService executor;
|
||||
private final static int MAX_THREADS = 1;
|
||||
|
||||
|
@ -68,21 +72,12 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
|||
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
||||
public void setFhirContext(FhirContext theFhirContext) {
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
|
||||
mySubscriptionDao = theSubscriptionDao;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
@Qualifier("mySubscriptionDaoDstu3")
|
||||
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
||||
|
||||
private boolean notifyOnDelete = false;
|
||||
|
||||
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
||||
|
||||
/**
|
||||
|
@ -205,6 +200,7 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
|||
req.setSubRequest(true);
|
||||
|
||||
IFhirResourceDao<? extends IBaseResource> responseDao = mySubscriptionDao.getDao(responseResourceDef.getImplementingClass());
|
||||
responseCriteriaUrl.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
|
||||
return responseResults;
|
||||
}
|
||||
|
@ -254,7 +250,6 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
|||
return entity;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read the existing subscriptions from the database
|
||||
*/
|
||||
|
@ -266,7 +261,12 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
|||
RequestDetails req = new ServletSubRequestDetails();
|
||||
req.setSubRequest(true);
|
||||
|
||||
map.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||
IBundleProvider subscriptionBundleList = mySubscriptionDao.search(map, req);
|
||||
if (subscriptionBundleList.size() >= MAX_SUBSCRIPTION_RESULTS) {
|
||||
ourLog.error("Currently over "+MAX_SUBSCRIPTION_RESULTS+" subscriptions. Some subscriptions have not been loaded.");
|
||||
}
|
||||
|
||||
List<IBaseResource> resourceList = subscriptionBundleList.getResources(0, subscriptionBundleList.size());
|
||||
|
||||
for (IBaseResource resource : resourceList) {
|
||||
|
@ -388,7 +388,69 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
|||
}
|
||||
}
|
||||
|
||||
public void setFhirContext(FhirContext theFhirContext) {
|
||||
myFhirContext = theFhirContext;
|
||||
}
|
||||
|
||||
public void setNotifyOnDelete(boolean notifyOnDelete) {
|
||||
this.notifyOnDelete = notifyOnDelete;
|
||||
}
|
||||
|
||||
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
|
||||
mySubscriptionDao = theSubscriptionDao;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theDetails) {
|
||||
//check the subscription criteria to see if its valid before creating or updating a subscription
|
||||
if (RestOperationTypeEnum.CREATE.equals(theOperation) || RestOperationTypeEnum.UPDATE.equals(theOperation)) {
|
||||
String resourceType = theDetails.getResourceType();
|
||||
ourLog.info("prehandled resource type: " + resourceType);
|
||||
if (resourceType != null && resourceType.equals(Subscription.class.getSimpleName())) {
|
||||
Subscription subscription = (Subscription) theDetails.getResource();
|
||||
if (subscription != null) {
|
||||
checkSubscriptionCriterias(subscription);
|
||||
}
|
||||
}
|
||||
}
|
||||
super.incomingRequestPreHandled(theOperation, theDetails);
|
||||
}
|
||||
|
||||
private void checkSubscriptionCriterias(Subscription subscription){
|
||||
try {
|
||||
IBundleProvider results = executeSubscriptionCriteria(subscription, null);
|
||||
}catch (Exception e){
|
||||
throw new InvalidRequestException("Invalid criteria");
|
||||
}
|
||||
}
|
||||
|
||||
private IBundleProvider executeSubscriptionCriteria(Subscription subscription, IIdType idType){
|
||||
//run the subscriptions query and look for matches, add the id as part of the criteria to avoid getting matches of previous resources rather than the recent resource
|
||||
String criteria = subscription.getCriteria();
|
||||
if(idType != null) {
|
||||
criteria += "&_id=" + idType.getResourceType() + "/" + idType.getIdPart();
|
||||
}
|
||||
|
||||
IBundleProvider results = getBundleProvider(criteria);
|
||||
return results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the encoding from the criteria or return JSON encoding if its not found
|
||||
*
|
||||
* @param criteria
|
||||
* @return
|
||||
*/
|
||||
private EncodingEnum getEncoding(String criteria) {
|
||||
//check criteria
|
||||
String params = criteria.substring(criteria.indexOf('?') + 1);
|
||||
List<NameValuePair> paramValues = URLEncodedUtils.parse(params, Constants.CHARSET_UTF8, '&');
|
||||
for (NameValuePair nameValuePair : paramValues) {
|
||||
if (Constants.PARAM_FORMAT.equals(nameValuePair.getName())) {
|
||||
return EncodingEnum.forContentType(nameValuePair.getValue());
|
||||
}
|
||||
}
|
||||
return EncodingEnum.JSON;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,125 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
|
||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
|
||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||
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.context.annotation.Bean;
|
||||
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 javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Properties;
|
||||
|
||||
/**
|
||||
* This is the primary configuration file for the example server
|
||||
*/
|
||||
@Configuration
|
||||
@EnableTransactionManagement()
|
||||
public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
||||
|
||||
/**
|
||||
* 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");
|
||||
// extraProperties.put("hibernate.search.default.worker.execution", "async");
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.to.FhirTesterMvcConfig;
|
||||
import ca.uhn.fhir.to.TesterConfig;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
//@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 FhirTesterConfigDstu2 {
|
||||
|
||||
/**
|
||||
* 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("home")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU2)
|
||||
.withBaseUrl("${serverBase}/baseDstu2")
|
||||
.withName("Local Tester")
|
||||
.addServer()
|
||||
.withId("hapi")
|
||||
.withFhirVersion(FhirVersionEnum.DSTU2)
|
||||
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu2")
|
||||
.withName("Public HAPI Test Server");
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
//@formatter:on
|
|
@ -0,0 +1,169 @@
|
|||
|
||||
package ca.uhn.fhir.jpa.demo;
|
||||
|
||||
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.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu1;
|
||||
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1;
|
||||
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.IResourceProvider;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Meta;
|
||||
import org.springframework.web.context.ContextLoaderListener;
|
||||
import org.springframework.web.context.WebApplicationContext;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public class JpaServerDemoDstu2 extends RestfulServer {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private WebApplicationContext myAppCtx;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
/*
|
||||
* We want to support FHIR DSTU2 format. This means that the server
|
||||
* will use the DSTU2 bundle format and other DSTU2 encoding changes.
|
||||
*
|
||||
* 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 = FhirVersionEnum.DSTU2;
|
||||
setFhirContext(new FhirContext(fhirVersion));
|
||||
|
||||
// Get the spring context from the web container (it's declared in web.xml)
|
||||
myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
||||
|
||||
/*
|
||||
* The BaseJavaConfigDstu2.java class is a spring configuration
|
||||
* 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.DSTU1) {
|
||||
resourceProviderBeanName = "myResourceProvidersDstu1";
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
resourceProviderBeanName = "myResourceProvidersDstu2";
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
resourceProviderBeanName = "myResourceProvidersDstu3";
|
||||
} 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.
|
||||
*/
|
||||
Object systemProvider;
|
||||
if (fhirVersion == FhirVersionEnum.DSTU1) {
|
||||
systemProvider = myAppCtx.getBean("mySystemProviderDstu1", JpaSystemProviderDstu1.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
systemProvider = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
systemProvider = myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
setPlainProviders(systemProvider);
|
||||
|
||||
/*
|
||||
* 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
|
||||
* is a nice addition.
|
||||
*/
|
||||
if (fhirVersion == FhirVersionEnum.DSTU1) {
|
||||
IFhirSystemDao<List<IResource>, MetaDt> systemDao = myAppCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu1 confProvider = new JpaConformanceProviderDstu1(this, systemDao);
|
||||
confProvider.setImplementationDescription("Example Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao,
|
||||
myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription("Example Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
IFhirSystemDao<Bundle, Meta> systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao,
|
||||
myAppCtx.getBean(DaoConfig.class));
|
||||
confProvider.setImplementationDescription("Example Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
/*
|
||||
* Enable ETag Support (this is already the default)
|
||||
*/
|
||||
setETagSupport(ETagSupportEnum.ENABLED);
|
||||
|
||||
/*
|
||||
* This server tries to dynamically generate narratives
|
||||
*/
|
||||
FhirContext ctx = getFhirContext();
|
||||
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
|
||||
|
||||
/*
|
||||
* Default to JSON and pretty printing
|
||||
*/
|
||||
setDefaultPrettyPrint(true);
|
||||
setDefaultResponseEncoding(EncodingEnum.JSON);
|
||||
|
||||
/*
|
||||
* -- New in HAPI FHIR 1.5 --
|
||||
* This configures the server to page search results to and from
|
||||
* the database, instead of only paging them to memory. This may mean
|
||||
* a performance hit when performing searches that return lots of results,
|
||||
* but makes the server much more scalable.
|
||||
*/
|
||||
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
|
||||
|
||||
/*
|
||||
* Load interceptors for the server from Spring (these are defined in FhirServerConfig.java)
|
||||
*/
|
||||
Collection<IServerInterceptor> interceptorBeans = myAppCtx.getBeansOfType(IServerInterceptor.class).values();
|
||||
for (IServerInterceptor interceptor : interceptorBeans) {
|
||||
this.registerInterceptor(interceptor);
|
||||
}
|
||||
|
||||
/*
|
||||
* If you are hosting this server at a specific DNS name, the server will try to
|
||||
* figure out the FHIR base URL based on what the web container tells it, but
|
||||
* this doesn't always work. If you are setting links in your search bundles that
|
||||
* just refer to "localhost", you might want to use a server address strategy:
|
||||
*/
|
||||
//setServerAddressStrategy(new HardcodedServerAddressStrategy("http://mydomain.com/fhir/baseDstu2"));
|
||||
|
||||
/*
|
||||
* If you are using DSTU3+, you may want to add a terminology uploader, which allows
|
||||
* uploading of external terminologies such as Snomed CT. Note that this uploader
|
||||
* does not have any security attached (any anonymous user may use it by default)
|
||||
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
|
||||
* with this feature.
|
||||
*/
|
||||
//if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
// registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
|
||||
//}
|
||||
}
|
||||
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
|
@ -13,7 +13,7 @@
|
|||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfigWSocket
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfigDstu2
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
|
@ -28,7 +28,7 @@
|
|||
</init-param>
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfig</param-value>
|
||||
<param-value>ca.uhn.fhir.jpa.demo.FhirTesterConfigDstu2</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
@ -103,6 +103,4 @@
|
|||
<filter-name>CORS Filter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
</web-app>
|
|
@ -1,108 +0,0 @@
|
|||
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||
|
||||
<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>
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfigDstu3WSocket
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- 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>ca.uhn.fhir.jpa.demo.FhirTesterConfig</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<servlet-class>ca.uhn.fhir.jpa.demo.JpaServerDemo</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>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<url-pattern>/baseDstu3/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
||||
|
||||
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
|
||||
<filter>
|
||||
<filter-name>CORS Filter</filter-name>
|
||||
<filter-class>org.ebaysf.web.cors.CORSFilter</filter-class>
|
||||
<init-param>
|
||||
<description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
|
||||
<param-name>cors.allowed.origins</param-name>
|
||||
<param-value>*</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description>
|
||||
<param-name>cors.allowed.methods</param-name>
|
||||
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A comma separated list of allowed headers when making a non simple CORS request.</description>
|
||||
<param-name>cors.allowed.headers</param-name>
|
||||
<param-value>X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
|
||||
<param-name>cors.exposed.headers</param-name>
|
||||
<param-value>Location,Content-Location</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A flag that suggests if CORS is supported with cookies</description>
|
||||
<param-name>cors.support.credentials</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A flag to control logging</description>
|
||||
<param-name>cors.logging.enabled</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>Indicates how long (in seconds) the results of a preflight request can be cached in a preflight result cache.</description>
|
||||
<param-name>cors.preflight.maxage</param-name>
|
||||
<param-value>300</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>CORS Filter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
</web-app>
|
|
@ -1,108 +0,0 @@
|
|||
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
|
||||
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
|
||||
|
||||
<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>
|
||||
ca.uhn.fhir.jpa.demo.FhirServerConfig
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- 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>ca.uhn.fhir.jpa.demo.FhirTesterConfig</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<servlet-class>ca.uhn.fhir.jpa.demo.JpaServerDemo</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>DSTU2</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<url-pattern>/baseDstu2/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
|
||||
|
||||
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
|
||||
<filter>
|
||||
<filter-name>CORS Filter</filter-name>
|
||||
<filter-class>org.ebaysf.web.cors.CORSFilter</filter-class>
|
||||
<init-param>
|
||||
<description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
|
||||
<param-name>cors.allowed.origins</param-name>
|
||||
<param-value>*</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description>
|
||||
<param-name>cors.allowed.methods</param-name>
|
||||
<param-value>GET,POST,PUT,DELETE,OPTIONS</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A comma separated list of allowed headers when making a non simple CORS request.</description>
|
||||
<param-name>cors.allowed.headers</param-name>
|
||||
<param-value>X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
|
||||
<param-name>cors.exposed.headers</param-name>
|
||||
<param-value>Location,Content-Location</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A flag that suggests if CORS is supported with cookies</description>
|
||||
<param-name>cors.support.credentials</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>A flag to control logging</description>
|
||||
<param-name>cors.logging.enabled</param-name>
|
||||
<param-value>true</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<description>Indicates how long (in seconds) the results of a preflight request can be cached in a preflight result cache.</description>
|
||||
<param-name>cors.preflight.maxage</param-name>
|
||||
<param-value>300</param-value>
|
||||
</init-param>
|
||||
</filter>
|
||||
<filter-mapping>
|
||||
<filter-name>CORS Filter</filter-name>
|
||||
<url-pattern>/*</url-pattern>
|
||||
</filter-mapping>
|
||||
|
||||
|
||||
</web-app>
|
Loading…
Reference in New Issue