Merge branch 'master' into hapi3_refactor
This commit is contained in:
commit
fbe2f98a02
|
@ -334,6 +334,16 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
nextId = nextValue.getReferenceElement();
|
nextId = nextValue.getReferenceElement();
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This can only really happen if the DAO is being called
|
||||||
|
* programatically with a Bundle (not through the FHIR REST API)
|
||||||
|
* but Smile does this
|
||||||
|
*/
|
||||||
|
if (nextId.isEmpty() && nextValue.getResource() != null) {
|
||||||
|
nextId = nextValue.getResource().getIdElement();
|
||||||
|
}
|
||||||
|
|
||||||
if (nextId.isEmpty() || nextId.getValue().startsWith("#")) {
|
if (nextId.isEmpty() || nextId.getValue().startsWith("#")) {
|
||||||
// This is a blank or contained resource reference
|
// This is a blank or contained resource reference
|
||||||
continue;
|
continue;
|
||||||
|
@ -2046,7 +2056,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
||||||
return paramMap;
|
return paramMap;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected static List<NameValuePair> translateMatchUrl(String theMatchUrl) {
|
public static List<NameValuePair> translateMatchUrl(String theMatchUrl) {
|
||||||
List<NameValuePair> parameters;
|
List<NameValuePair> parameters;
|
||||||
String matchUrl = theMatchUrl;
|
String matchUrl = theMatchUrl;
|
||||||
int questionMarkIndex = matchUrl.indexOf('?');
|
int questionMarkIndex = matchUrl.indexOf('?');
|
||||||
|
|
|
@ -273,19 +273,24 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
||||||
|
|
||||||
// Notify interceptors
|
// Notify interceptors
|
||||||
IdDt idToDelete = entity.getIdDt();
|
IdDt idToDelete = entity.getIdDt();
|
||||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, idToDelete.getResourceType(), idToDelete);
|
if (theRequestDetails != null) {
|
||||||
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
|
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, idToDelete.getResourceType(), idToDelete);
|
||||||
|
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
|
||||||
|
}
|
||||||
|
|
||||||
// Perform delete
|
// Perform delete
|
||||||
Date updateTime = new Date();
|
Date updateTime = new Date();
|
||||||
updateEntity(null, entity, updateTime, updateTime);
|
updateEntity(null, entity, updateTime, updateTime);
|
||||||
|
|
||||||
// Notify JPA interceptors
|
// Notify JPA interceptors
|
||||||
T resourceToDelete = toResource(myResourceType, entity, false);
|
T resourceToDelete = toResource(myResourceType, entity, false);
|
||||||
theRequestDetails.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
if (theRequestDetails != null) {
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
theRequestDetails.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
||||||
if (next instanceof IJpaServerInterceptor) {
|
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequestDetails, idToDelete.getResourceType(), idToDelete);
|
||||||
((IJpaServerInterceptor) next).resourceDeleted(requestDetails, entity);
|
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||||
|
if (next instanceof IJpaServerInterceptor) {
|
||||||
|
((IJpaServerInterceptor) next).resourceDeleted(requestDetails, entity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||||
|
|
|
@ -247,7 +247,6 @@ public class FulltextSearchSvcImpl extends BaseHapiFhirDao<IBaseResource> implem
|
||||||
|
|
||||||
QueryBuilder qb = em.getSearchFactory().buildQueryBuilder().forEntity(ResourceTable.class).get();
|
QueryBuilder qb = em.getSearchFactory().buildQueryBuilder().forEntity(ResourceTable.class).get();
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
Query textQuery = qb
|
Query textQuery = qb
|
||||||
.phrase()
|
.phrase()
|
||||||
.withSlop(2)
|
.withSlop(2)
|
||||||
|
@ -261,7 +260,6 @@ public class FulltextSearchSvcImpl extends BaseHapiFhirDao<IBaseResource> implem
|
||||||
.must(qb.keyword().onField("myResourceLinks.myTargetResourcePid").matching(pid).createQuery())
|
.must(qb.keyword().onField("myResourceLinks.myTargetResourcePid").matching(pid).createQuery())
|
||||||
.must(textQuery)
|
.must(textQuery)
|
||||||
.createQuery();
|
.createQuery();
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
FullTextQuery ftq = em.createFullTextQuery(query, ResourceTable.class);
|
FullTextQuery ftq = em.createFullTextQuery(query, ResourceTable.class);
|
||||||
ftq.setProjection("myContentText");
|
ftq.setProjection("myContentText");
|
||||||
|
@ -289,14 +287,6 @@ public class FulltextSearchSvcImpl extends BaseHapiFhirDao<IBaseResource> implem
|
||||||
formatter.setAnalyzer("myContentTextEdgeNGram");
|
formatter.setAnalyzer("myContentTextEdgeNGram");
|
||||||
highlighter.getBestFragments(analyzer.tokenStream("myContentTextEdgeNGram", nextValue), nextValue, 10);
|
highlighter.getBestFragments(analyzer.tokenStream("myContentTextEdgeNGram", nextValue), nextValue, 10);
|
||||||
|
|
||||||
// formatter.setAnalyzer("myContentText");
|
|
||||||
// highlighter.getBestFragments(analyzer.tokenStream("myContentText", nextValue), nextValue, 10);
|
|
||||||
// formatter.setAnalyzer("myContentTextNGram");
|
|
||||||
// highlighter.getBestFragments(analyzer.tokenStream("myContentTextNGram", nextValue), nextValue, 10);
|
|
||||||
// formatter.setAnalyzer("myContentTextEdgeNGram");
|
|
||||||
// highlighter.getBestFragments(analyzer.tokenStream("myContentTextEdgeNGram", nextValue), nextValue, 10);
|
|
||||||
// formatter.setAnalyzer("myContentTextPhonetic");
|
|
||||||
// highlighter.getBestFragments(analyzer.tokenStream("myContentTextPhonetic", nextValue), nextValue, 10);
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
throw new InternalErrorException(e);
|
throw new InternalErrorException(e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,12 @@ import javax.annotation.PostConstruct;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
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.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpPut;
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
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.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
@ -63,6 +66,7 @@ import ca.uhn.fhir.rest.server.interceptor.*;
|
||||||
|
|
||||||
public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterceptorAdapter {
|
public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterceptorAdapter {
|
||||||
|
|
||||||
|
private static final Integer MAX_SUBSCRIPTION_RESULTS = 10000;
|
||||||
private static volatile ExecutorService executor;
|
private static volatile ExecutorService executor;
|
||||||
private final static int MAX_THREADS = 1;
|
private final static int MAX_THREADS = 1;
|
||||||
|
|
||||||
|
@ -71,13 +75,13 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myFhirContext;
|
private FhirContext myFhirContext;
|
||||||
|
|
||||||
private boolean myNotifyOnDelete = false;
|
|
||||||
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("mySubscriptionDaoDstu2")
|
@Qualifier("mySubscriptionDaoDstu2")
|
||||||
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
||||||
|
|
||||||
|
private boolean myNotifyOnDelete = false;
|
||||||
|
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check subscriptions and send notifications or payload
|
* Check subscriptions and send notifications or payload
|
||||||
*
|
*
|
||||||
|
@ -205,6 +209,7 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
||||||
req.setSubRequest(true);
|
req.setSubRequest(true);
|
||||||
|
|
||||||
IFhirResourceDao<? extends IBaseResource> responseDao = mySubscriptionDao.getDao(responseResourceDef.getImplementingClass());
|
IFhirResourceDao<? extends IBaseResource> responseDao = mySubscriptionDao.getDao(responseResourceDef.getImplementingClass());
|
||||||
|
responseCriteriaUrl.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||||
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
|
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
|
||||||
return responseResults;
|
return responseResults;
|
||||||
}
|
}
|
||||||
|
@ -265,7 +270,12 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
||||||
RequestDetails req = new ServletSubRequestDetails();
|
RequestDetails req = new ServletSubRequestDetails();
|
||||||
req.setSubRequest(true);
|
req.setSubRequest(true);
|
||||||
|
|
||||||
|
map.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||||
IBundleProvider subscriptionBundleList = mySubscriptionDao.search(map, req);
|
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());
|
List<IBaseResource> resourceList = subscriptionBundleList.getResources(0, subscriptionBundleList.size());
|
||||||
|
|
||||||
for (IBaseResource resource : resourceList) {
|
for (IBaseResource resource : resourceList) {
|
||||||
|
@ -398,4 +408,58 @@ public class RestHookSubscriptionDstu2Interceptor extends ServerOperationInterce
|
||||||
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
|
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
|
||||||
mySubscriptionDao = 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.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
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.HttpPost;
|
||||||
import org.apache.http.client.methods.HttpPut;
|
import org.apache.http.client.methods.HttpPut;
|
||||||
import org.apache.http.client.methods.HttpUriRequest;
|
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.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
import org.hl7.fhir.dstu3.model.Subscription;
|
import org.hl7.fhir.dstu3.model.Subscription;
|
||||||
|
@ -61,6 +64,7 @@ import ca.uhn.fhir.rest.server.interceptor.*;
|
||||||
|
|
||||||
public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterceptorAdapter {
|
public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterceptorAdapter {
|
||||||
|
|
||||||
|
private static final Integer MAX_SUBSCRIPTION_RESULTS = 10000;
|
||||||
private static volatile ExecutorService executor;
|
private static volatile ExecutorService executor;
|
||||||
private final static int MAX_THREADS = 1;
|
private final static int MAX_THREADS = 1;
|
||||||
|
|
||||||
|
@ -68,21 +72,12 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myFhirContext;
|
private FhirContext myFhirContext;
|
||||||
|
|
||||||
public void setFhirContext(FhirContext theFhirContext) {
|
|
||||||
myFhirContext = theFhirContext;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSubscriptionDao(IFhirResourceDao<Subscription> theSubscriptionDao) {
|
|
||||||
mySubscriptionDao = theSubscriptionDao;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("mySubscriptionDaoDstu3")
|
@Qualifier("mySubscriptionDaoDstu3")
|
||||||
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
private IFhirResourceDao<Subscription> mySubscriptionDao;
|
||||||
|
|
||||||
private boolean notifyOnDelete = false;
|
private boolean notifyOnDelete = false;
|
||||||
|
|
||||||
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
private final List<Subscription> myRestHookSubscriptions = new ArrayList<Subscription>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -205,6 +200,7 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
||||||
req.setSubRequest(true);
|
req.setSubRequest(true);
|
||||||
|
|
||||||
IFhirResourceDao<? extends IBaseResource> responseDao = mySubscriptionDao.getDao(responseResourceDef.getImplementingClass());
|
IFhirResourceDao<? extends IBaseResource> responseDao = mySubscriptionDao.getDao(responseResourceDef.getImplementingClass());
|
||||||
|
responseCriteriaUrl.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||||
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
|
IBundleProvider responseResults = responseDao.search(responseCriteriaUrl, req);
|
||||||
return responseResults;
|
return responseResults;
|
||||||
}
|
}
|
||||||
|
@ -254,7 +250,6 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read the existing subscriptions from the database
|
* Read the existing subscriptions from the database
|
||||||
*/
|
*/
|
||||||
|
@ -266,7 +261,12 @@ public class RestHookSubscriptionDstu3Interceptor extends ServerOperationInterce
|
||||||
RequestDetails req = new ServletSubRequestDetails();
|
RequestDetails req = new ServletSubRequestDetails();
|
||||||
req.setSubRequest(true);
|
req.setSubRequest(true);
|
||||||
|
|
||||||
|
map.setCount(MAX_SUBSCRIPTION_RESULTS);
|
||||||
IBundleProvider subscriptionBundleList = mySubscriptionDao.search(map, req);
|
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());
|
List<IBaseResource> resourceList = subscriptionBundleList.getResources(0, subscriptionBundleList.size());
|
||||||
|
|
||||||
for (IBaseResource resource : resourceList) {
|
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) {
|
public void setNotifyOnDelete(boolean notifyOnDelete) {
|
||||||
this.notifyOnDelete = 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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -542,6 +542,60 @@ public class FhirSystemDaoDstu3Test extends BaseJpaDstu3SystemTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionWithReferenceUuid() {
|
||||||
|
Bundle request = new Bundle();
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setActive(true);
|
||||||
|
p.setId(IdType.newRandomUuid());
|
||||||
|
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl(p.getId());
|
||||||
|
|
||||||
|
Observation o = new Observation();
|
||||||
|
o.getCode().setText("Some Observation");
|
||||||
|
o.getSubject().setReference(p.getId());
|
||||||
|
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
|
||||||
|
|
||||||
|
Bundle resp = mySystemDao.transaction(mySrd, request);
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||||
|
|
||||||
|
String patientId = new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualifiedVersionless().getValue();
|
||||||
|
assertThat(patientId, startsWith("Patient/"));
|
||||||
|
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.setLoadSynchronous(true);
|
||||||
|
params.add("subject", new ReferenceParam(patientId));
|
||||||
|
IBundleProvider found = myObservationDao.search(params);
|
||||||
|
assertEquals(1, found.size().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testTransactionWithReferenceResource() {
|
||||||
|
Bundle request = new Bundle();
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.setActive(true);
|
||||||
|
p.setId(IdType.newRandomUuid());
|
||||||
|
request.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl(p.getId());
|
||||||
|
|
||||||
|
Observation o = new Observation();
|
||||||
|
o.getCode().setText("Some Observation");
|
||||||
|
o.getSubject().setResource(p);
|
||||||
|
request.addEntry().setResource(o).getRequest().setMethod(HTTPVerb.POST);
|
||||||
|
|
||||||
|
Bundle resp = mySystemDao.transaction(mySrd, request);
|
||||||
|
ourLog.info(myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp));
|
||||||
|
|
||||||
|
String patientId = new IdType(resp.getEntry().get(0).getResponse().getLocation()).toUnqualifiedVersionless().getValue();
|
||||||
|
assertThat(patientId, startsWith("Patient/"));
|
||||||
|
|
||||||
|
SearchParameterMap params = new SearchParameterMap();
|
||||||
|
params.setLoadSynchronous(true);
|
||||||
|
params.add("subject", new ReferenceParam(patientId));
|
||||||
|
IBundleProvider found = myObservationDao.search(params);
|
||||||
|
assertEquals(1, found.size().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionCreateInlineMatchUrlWithOneMatch() {
|
public void testTransactionCreateInlineMatchUrlWithOneMatch() {
|
||||||
String methodName = "testTransactionCreateInlineMatchUrlWithOneMatch";
|
String methodName = "testTransactionCreateInlineMatchUrlWithOneMatch";
|
||||||
|
|
|
@ -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"
|
<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>
|
||||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||||
|
@ -13,7 +13,7 @@
|
||||||
<context-param>
|
<context-param>
|
||||||
<param-name>contextConfigLocation</param-name>
|
<param-name>contextConfigLocation</param-name>
|
||||||
<param-value>
|
<param-value>
|
||||||
ca.uhn.fhir.jpa.demo.FhirServerConfigWSocket
|
ca.uhn.fhir.jpa.demo.FhirServerConfigDstu2
|
||||||
</param-value>
|
</param-value>
|
||||||
</context-param>
|
</context-param>
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@
|
||||||
</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.demo.FhirTesterConfigDstu2</param-value>
|
||||||
</init-param>
|
</init-param>
|
||||||
<load-on-startup>2</load-on-startup>
|
<load-on-startup>2</load-on-startup>
|
||||||
</servlet>
|
</servlet>
|
||||||
|
@ -103,6 +103,4 @@
|
||||||
<filter-name>CORS Filter</filter-name>
|
<filter-name>CORS Filter</filter-name>
|
||||||
<url-pattern>/*</url-pattern>
|
<url-pattern>/*</url-pattern>
|
||||||
</filter-mapping>
|
</filter-mapping>
|
||||||
|
|
||||||
|
|
||||||
</web-app>
|
</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>
|
|
|
@ -66,6 +66,16 @@
|
||||||
Prevent duplicates in $everything query response in JPA server. Thanks to @vlad-ignatov
|
Prevent duplicates in $everything query response in JPA server. Thanks to @vlad-ignatov
|
||||||
for reporting!
|
for reporting!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
Fix issue in calling JPA server transactions programmatically where resources
|
||||||
|
are linked by object reference and not by ID where indexes were not correctly
|
||||||
|
generated. This should not affect most users.
|
||||||
|
</action>
|
||||||
|
<action type="fix" issue="678">
|
||||||
|
FIx issue in SubscriptionInterceptor that caused interceptor to only
|
||||||
|
actually notify listeners of the first 10 subscriptions. Thanks to Jeff Chung
|
||||||
|
for the pull request!
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="2.5" date="2017-06-08">
|
<release version="2.5" date="2017-06-08">
|
||||||
<action type="fix">
|
<action type="fix">
|
||||||
|
|
Loading…
Reference in New Issue