Merge branch 'loinc_loader_update' of github.com:jamesagnew/hapi-fhir into loinc_loader_update

This commit is contained in:
jamesagnew 2018-04-15 17:43:16 -04:00
commit 13242d77ed
14 changed files with 195 additions and 36 deletions

View File

@ -209,7 +209,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
for (int i = 0; i < theRequest.getEntry().size(); i++) {
if (i % 100 == 0) {
ourLog.info("Processed {} non-GET entries out of {}", i, theRequest.getEntry().size());
ourLog.debug("Processed {} non-GET entries out of {}", i, theRequest.getEntry().size());
}
Entry nextReqEntry = theRequest.getEntry().get(i);

View File

@ -815,7 +815,7 @@ public class SearchBuilder implements ISearchBuilder {
continue;
}
predicate = join.<Object>get("myUri").as(String.class).in(toFind);
predicate = join.get("myUri").as(String.class).in(toFind);
} else if (param.getQualifier() == UriParamQualifierEnum.BELOW) {
predicate = myBuilder.like(join.get("myUri").as(String.class), createLeftMatchLikeExpression(value));
@ -953,8 +953,8 @@ public class SearchBuilder implements ISearchBuilder {
Predicate lb = null;
if (lowerBound != null) {
Predicate gt = theBuilder.greaterThanOrEqualTo(theFrom.<Date>get("myValueLow"), lowerBound);
Predicate lt = theBuilder.greaterThanOrEqualTo(theFrom.<Date>get("myValueHigh"), lowerBound);
Predicate gt = theBuilder.greaterThanOrEqualTo(theFrom.get("myValueLow"), lowerBound);
Predicate lt = theBuilder.greaterThanOrEqualTo(theFrom.get("myValueHigh"), lowerBound);
if (theRange.getLowerBound().getPrefix() == ParamPrefixEnum.STARTS_AFTER || theRange.getLowerBound().getPrefix() == ParamPrefixEnum.EQUAL) {
lb = gt;
} else {
@ -964,8 +964,8 @@ public class SearchBuilder implements ISearchBuilder {
Predicate ub = null;
if (upperBound != null) {
Predicate gt = theBuilder.lessThanOrEqualTo(theFrom.<Date>get("myValueLow"), upperBound);
Predicate lt = theBuilder.lessThanOrEqualTo(theFrom.<Date>get("myValueHigh"), upperBound);
Predicate gt = theBuilder.lessThanOrEqualTo(theFrom.get("myValueLow"), upperBound);
Predicate lt = theBuilder.lessThanOrEqualTo(theFrom.get("myValueHigh"), upperBound);
if (theRange.getUpperBound().getPrefix() == ParamPrefixEnum.ENDS_BEFORE || theRange.getUpperBound().getPrefix() == ParamPrefixEnum.EQUAL) {
ub = lt;
} else {
@ -2008,15 +2008,15 @@ public class SearchBuilder implements ISearchBuilder {
}
private static List<Predicate> createLastUpdatedPredicates(final DateRangeParam theLastUpdated, CriteriaBuilder builder, From<?, ResourceTable> from) {
List<Predicate> lastUpdatedPredicates = new ArrayList<Predicate>();
List<Predicate> lastUpdatedPredicates = new ArrayList<>();
if (theLastUpdated != null) {
if (theLastUpdated.getLowerBoundAsInstant() != null) {
ourLog.debug("LastUpdated lower bound: {}", new InstantDt(theLastUpdated.getLowerBoundAsInstant()));
Predicate predicateLower = builder.greaterThanOrEqualTo(from.<Date>get("myUpdated"), theLastUpdated.getLowerBoundAsInstant());
Predicate predicateLower = builder.greaterThanOrEqualTo(from.get("myUpdated"), theLastUpdated.getLowerBoundAsInstant());
lastUpdatedPredicates.add(predicateLower);
}
if (theLastUpdated.getUpperBoundAsInstant() != null) {
Predicate predicateUpper = builder.lessThanOrEqualTo(from.<Date>get("myUpdated"), theLastUpdated.getUpperBoundAsInstant());
Predicate predicateUpper = builder.lessThanOrEqualTo(from.get("myUpdated"), theLastUpdated.getUpperBoundAsInstant());
lastUpdatedPredicates.add(predicateUpper);
}
}
@ -2262,10 +2262,7 @@ public class SearchBuilder implements ISearchBuilder {
if (myNext == null) {
fetchNext();
}
if (myNext == NO_MORE) {
return false;
}
return true;
return myNext != NO_MORE;
}
@Override

View File

@ -318,7 +318,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
for (int i = 0; i < theEntries.size(); i++) {
if (i % 100 == 0) {
ourLog.info("Processed {} non-GET entries out of {}", i, theEntries.size());
ourLog.debug("Processed {} non-GET entries out of {}", i, theEntries.size());
}
BundleEntryComponent nextReqEntry = theEntries.get(i);

View File

@ -333,7 +333,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
for (int i = 0; i < theEntries.size(); i++) {
if (i % 100 == 0) {
ourLog.info("Processed {} non-GET entries out of {}", i, theEntries.size());
ourLog.debug("Processed {} non-GET entries out of {}", i, theEntries.size());
}
BundleEntryComponent nextReqEntry = theEntries.get(i);

View File

@ -168,6 +168,19 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
retVal.getEmailDetails().setSubjectTemplate(subjectTemplate);
}
if (retVal.getChannelType() == Subscription.SubscriptionChannelType.RESTHOOK) {
String stripVersionIds;
String deliverLatestVersion;
try {
stripVersionIds = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
deliverLatestVersion = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
} catch (FHIRException theE) {
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
}
retVal.getRestHookDetails().setStripVersionId(Boolean.parseBoolean(stripVersionIds));
retVal.getRestHookDetails().setDeliverLatestVersion(Boolean.parseBoolean(deliverLatestVersion));
}
} catch (FHIRException theE) {
throw new InternalErrorException(theE);
}
@ -201,6 +214,19 @@ public abstract class BaseSubscriptionInterceptor<S extends IBaseResource> exten
retVal.getEmailDetails().setSubjectTemplate(subjectTemplate);
}
if (retVal.getChannelType() == Subscription.SubscriptionChannelType.RESTHOOK) {
String stripVersionIds;
String deliverLatestVersion;
try {
stripVersionIds = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS);
deliverLatestVersion = subscription.getChannel().getExtensionString(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION);
} catch (FHIRException theE) {
throw new ConfigurationException("Failed to extract subscription extension(s): " + theE.getMessage(), theE);
}
retVal.getRestHookDetails().setStripVersionId(Boolean.parseBoolean(stripVersionIds));
retVal.getRestHookDetails().setDeliverLatestVersion(Boolean.parseBoolean(deliverLatestVersion));
}
List<org.hl7.fhir.r4.model.Extension> topicExts = subscription.getExtensionsByUrl("http://hl7.org/fhir/subscription/topics");
if (topicExts.size() > 0) {
IBaseReference ref = (IBaseReference) topicExts.get(0).getValueAsPrimitive();

View File

@ -67,6 +67,8 @@ public class CanonicalSubscription implements Serializable {
private CanonicalEventDefinition myTrigger;
@JsonProperty("emailDetails")
private EmailDetails myEmailDetails;
@JsonProperty("restHookDetails")
private RestHookDetails myRestHookDetails;
/**
* For now we're using the R4 TriggerDefinition, but this
@ -131,12 +133,10 @@ public class CanonicalSubscription implements Serializable {
return myHeaders;
}
public void setHeaders(List<? extends IPrimitiveType<String>> theHeader) {
public void setHeaders(String theHeaders) {
myHeaders = new ArrayList<>();
for (IPrimitiveType<String> next : theHeader) {
if (isNotBlank(next.getValueAsString())) {
myHeaders.add(next.getValueAsString());
}
if (isNotBlank(theHeaders)) {
myHeaders.add(theHeaders);
}
}
@ -160,6 +160,13 @@ public class CanonicalSubscription implements Serializable {
myPayloadString = thePayloadString;
}
public RestHookDetails getRestHookDetails() {
if (myRestHookDetails == null) {
myRestHookDetails = new RestHookDetails();
}
return myRestHookDetails;
}
public Subscription.SubscriptionStatus getStatus() {
return myStatus;
}
@ -191,10 +198,12 @@ public class CanonicalSubscription implements Serializable {
}
}
public void setHeaders(String theHeaders) {
public void setHeaders(List<? extends IPrimitiveType<String>> theHeader) {
myHeaders = new ArrayList<>();
if (isNotBlank(theHeaders)) {
myHeaders.add(theHeaders);
for (IPrimitiveType<String> next : theHeader) {
if (isNotBlank(next.getValueAsString())) {
myHeaders.add(next.getValueAsString());
}
}
}
@ -230,6 +239,32 @@ public class CanonicalSubscription implements Serializable {
}
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public static class RestHookDetails {
@JsonProperty("stripVersionId")
private boolean myStripVersionId;
@JsonProperty("deliverLatestVersion")
private boolean myDeliverLatestVersion;
public boolean isDeliverLatestVersion() {
return myDeliverLatestVersion;
}
public void setDeliverLatestVersion(boolean theDeliverLatestVersion) {
myDeliverLatestVersion = theDeliverLatestVersion;
}
public boolean isStripVersionId() {
return myStripVersionId;
}
public void setStripVersionId(boolean theStripVersionId) {
myStripVersionId = theStripVersionId;
}
}
@JsonInclude(JsonInclude.Include.NON_NULL)
@JsonAutoDetect(creatorVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, getterVisibility = JsonAutoDetect.Visibility.NONE, isGetterVisibility = JsonAutoDetect.Visibility.NONE, setterVisibility = JsonAutoDetect.Visibility.NONE)
public static class CanonicalEventDefinition {

View File

@ -28,8 +28,10 @@ import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.client.api.*;
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
import ca.uhn.fhir.rest.gclient.IClientExecutable;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Subscription;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@ -51,21 +53,26 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
}
protected void deliverPayload(ResourceDeliveryMessage theMsg, CanonicalSubscription theSubscription, EncodingEnum thePayloadType, IGenericClient theClient) {
IBaseResource payloadResource = theMsg.getPayload(getContext());
IBaseResource payloadResource = getAndMassagePayload(theMsg, theSubscription);
if (payloadResource == null) return;
doDelivery(theMsg, theSubscription, thePayloadType, theClient, payloadResource);
}
protected void doDelivery(ResourceDeliveryMessage theMsg, CanonicalSubscription theSubscription, EncodingEnum thePayloadType, IGenericClient theClient, IBaseResource thePayloadResource) {
IClientExecutable<?, ?> operation;
switch (theMsg.getOperationType()) {
case CREATE:
if (payloadResource == null || payloadResource.isEmpty()) {
if (thePayloadResource == null || thePayloadResource.isEmpty()) {
if (thePayloadType != null ) {
operation = theClient.create().resource(payloadResource);
operation = theClient.create().resource(thePayloadResource);
} else {
sendNotification(theMsg);
return;
}
} else {
if (thePayloadType != null ) {
operation = theClient.update().resource(payloadResource);
operation = theClient.update().resource(thePayloadResource);
} else {
sendNotification(theMsg);
return;
@ -73,16 +80,16 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
}
break;
case UPDATE:
if (payloadResource == null || payloadResource.isEmpty()) {
if (thePayloadResource == null || thePayloadResource.isEmpty()) {
if (thePayloadType != null ) {
operation = theClient.create().resource(payloadResource);
operation = theClient.create().resource(thePayloadResource);
} else {
sendNotification(theMsg);
return;
}
} else {
if (thePayloadType != null ) {
operation = theClient.update().resource(payloadResource);
operation = theClient.update().resource(thePayloadResource);
} else {
sendNotification(theMsg);
return;
@ -101,7 +108,7 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
operation.encoded(thePayloadType);
}
ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), payloadResource.getIdElement().toUnqualified().getValue(), theSubscription.getIdElement(getContext()).toUnqualifiedVersionless().getValue());
ourLog.info("Delivering {} rest-hook payload {} for {}", theMsg.getOperationType(), thePayloadResource.getIdElement().toUnqualified().getValue(), theSubscription.getIdElement(getContext()).toUnqualifiedVersionless().getValue());
try {
operation.execute();
@ -112,6 +119,27 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionDe
}
}
protected IBaseResource getAndMassagePayload(ResourceDeliveryMessage theMsg, CanonicalSubscription theSubscription) {
IBaseResource payloadResource = theMsg.getPayload(getContext());
if (theSubscription.getRestHookDetails().isDeliverLatestVersion()) {
IFhirResourceDao dao = getSubscriptionDao().getDao(payloadResource.getClass());
try {
payloadResource = dao.read(payloadResource.getIdElement().toVersionless());
} catch (ResourceGoneException e) {
ourLog.warn("Resource {} is deleted, not going to deliver for subscription {}", payloadResource.getIdElement(), theSubscription.getIdElement(getContext()));
return null;
}
}
IIdType resourceId = payloadResource.getIdElement();
if (theSubscription.getRestHookDetails().isStripVersionId()) {
resourceId = resourceId.toVersionless();
payloadResource.setId(resourceId);
}
return payloadResource;
}
@Override
public void handleMessage(ResourceDeliveryMessage theMessage) throws MessagingException {
CanonicalSubscription subscription = theMessage.getSubscription();

View File

@ -808,8 +808,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc
ourLog.info("Validating all codes in CodeSystem for storage (this can take some time for large sets)");
// Validate the code system
ArrayList<String> conceptsStack = new ArrayList<String>();
IdentityHashMap<TermConcept, Object> allConcepts = new IdentityHashMap<TermConcept, Object>();
ArrayList<String> conceptsStack = new ArrayList<>();
IdentityHashMap<TermConcept, Object> allConcepts = new IdentityHashMap<>();
int totalCodeCount = 0;
for (TermConcept next : theCodeSystemVersion.getConcepts()) {
totalCodeCount += validateConceptForStorage(next, theCodeSystemVersion, conceptsStack, allConcepts);

View File

@ -40,4 +40,33 @@ public class JpaConstants {
*/
public static final String EXT_SUBSCRIPTION_SUBJECT_TEMPLATE = "http://hapifhir.io/fhir/StructureDefinition/subscription-email-subject-template";
/**
* This extension URL indicates whether a REST HOOK delivery should
* include the version ID when delivering.
* <p>
* This extension should be of type <code>boolean</code> and should be
* placed on the <code>Subscription.channel</code> element.
* </p>
*/
public static final String EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS = "http://hapifhir.io/fhir/StructureDefinition/subscription-resthook-strip-version-ids";
/**
* This extension URL indicates whether a REST HOOK delivery should
* reload the resource and deliver the latest version always. This
* could be useful for example if a resource which triggers a
* subscription gets updated many times in short succession and there
* is no value in delivering the older versions.
* <p>
* Note that if the resource is now deleted, this may cause
* the delivery to be cancelled altogether.
* </p>
*
* <p>
* This extension should be of type <code>boolean</code> and should be
* placed on the <code>Subscription.channel</code> element.
* </p>
*/
public static final String EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION = "http://hapifhir.io/fhir/StructureDefinition/subscription-resthook-deliver-latest-version";
}

View File

@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.validation.ResultSeverityEnum;
import net.ttddyy.dsproxy.listener.ThreadQueryCountHolder;
import net.ttddyy.dsproxy.listener.logging.SLF4JLogLevel;
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
@ -104,7 +105,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
DataSource dataSource = ProxyDataSourceBuilder
.create(retVal)
// .logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
.logQueryBySlf4j(SLF4JLogLevel.INFO, "SQL")
.logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
.countQuery(new ThreadQueryCountHolder())
.build();

View File

@ -182,6 +182,15 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
return ids;
}
@Test
@Ignore
public void test() throws IOException {
HttpGet get = new HttpGet(ourServerBase + "/QuestionnaireResponse?_count=50&status=completed&questionnaire=ARIncenterAbsRecord&_lastUpdated=%3E"+UrlUtil.escapeUrlParam("=2018-01-01")+"&context.organization=O3435");
ourLog.info("*** MAKING QUERY");
ourHttpClient.execute(get);
System.exit(0);
}
@Test
public void testBundleCreate() throws Exception {
IGenericClient client = myClient;

View File

@ -2,8 +2,10 @@ package ca.uhn.fhir.jpa.subscription.r4;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
import ca.uhn.fhir.jpa.provider.r4.BaseResourceProviderR4Test;
import ca.uhn.fhir.jpa.subscription.RestHookTestDstu2Test;
import ca.uhn.fhir.jpa.util.JpaConstants;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
@ -172,7 +174,38 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test {
}
@Test
public void testRestHookSubscriptionApplicationJsonDisableVersionIdInDelivery() throws Exception {
String payload = "application/json";
String code = "1000000050";
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
Subscription subscription1 = createSubscription(criteria1, payload, ourListenerServerBase);
subscription1
.getChannel()
.addExtension(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_STRIP_VERSION_IDS, new BooleanType("true"));
subscription1
.getChannel()
.addExtension(JpaConstants.EXT_SUBSCRIPTION_RESTHOOK_DELIVER_LATEST_VERSION, new BooleanType("true"));
myClient.update().resource(subscription1).execute();
waitForQueueToDrain();
Observation observation1 = sendObservation(code, "SNOMED-CT");
// Should see 1 subscription notification
waitForQueueToDrain();
waitForSize(0, ourCreatedObservations);
waitForSize(1, ourUpdatedObservations);
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
assertEquals(observation1.getIdElement().getIdPart(), ourUpdatedObservations.get(0).getIdElement().getIdPart());
assertEquals(null, ourUpdatedObservations.get(0).getIdElement().getVersionIdPart());
}
@Test
public void testRestHookSubscriptionApplicationJson() throws Exception {
String payload = "application/json";
@ -191,6 +224,8 @@ public class RestHookTestR4Test extends BaseResourceProviderR4Test {
waitForSize(1, ourUpdatedObservations);
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
assertEquals("1", ourUpdatedObservations.get(0).getIdElement().getVersionIdPart());
Subscription subscriptionTemp = myClient.read(Subscription.class, subscription2.getId());
Assert.assertNotNull(subscriptionTemp);

View File

@ -205,7 +205,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
ValueSet outcome = myTermSvc.expandValueSet(vs);
codes = toCodesContains(outcome.getExpansion().getContains());
assertThat(codes, containsInAnyOrder("ParentA", "childAAA", "childAAB", "childAA", "childAB", "ParentB"));
assertThat(codes, containsInAnyOrder("ParentWithNoChildrenA", "ParentWithNoChildrenB", "ParentWithNoChildrenC", "ParentA", "childAAA", "childAAB", "childAA", "childAB", "ParentB"));
}
@Test

View File

@ -108,7 +108,6 @@ where res_id in (
drop table hfj_history_tag cascade constraints;
drop table hfj_forced_id cascade constraints;
drop table HFJ_SUBSCRIPTION_STATS cascade constraints;
drop table hfj_res_link cascade constraints;
drop table hfj_spidx_coords cascade constraints;
drop table hfj_spidx_date cascade constraints;