Split out delivery and processing channel for subscriptions
This commit is contained in:
parent
7764484f44
commit
e3a28e2ff5
|
@ -59,6 +59,7 @@ public abstract class BaseSubscriptionInterceptor extends ServerOperationInterce
|
||||||
static final String SUBSCRIPTION_HEADER = "Subscription.channel.header";
|
static final String SUBSCRIPTION_HEADER = "Subscription.channel.header";
|
||||||
private static final Integer MAX_SUBSCRIPTION_RESULTS = 1000;
|
private static final Integer MAX_SUBSCRIPTION_RESULTS = 1000;
|
||||||
private SubscribableChannel myProcessingChannel;
|
private SubscribableChannel myProcessingChannel;
|
||||||
|
private SubscribableChannel myDeliveryChannel;
|
||||||
private ExecutorService myExecutor;
|
private ExecutorService myExecutor;
|
||||||
private boolean myAutoActivateSubscriptions = true;
|
private boolean myAutoActivateSubscriptions = true;
|
||||||
private int myExecutorThreadCount = 1;
|
private int myExecutorThreadCount = 1;
|
||||||
|
@ -70,6 +71,14 @@ public abstract class BaseSubscriptionInterceptor extends ServerOperationInterce
|
||||||
|
|
||||||
public abstract Subscription.SubscriptionChannelType getChannelType();
|
public abstract Subscription.SubscriptionChannelType getChannelType();
|
||||||
|
|
||||||
|
public SubscribableChannel getDeliveryChannel() {
|
||||||
|
return myDeliveryChannel;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setDeliveryChannel(SubscribableChannel theDeliveryChannel) {
|
||||||
|
myDeliveryChannel = theDeliveryChannel;
|
||||||
|
}
|
||||||
|
|
||||||
public BlockingQueue<Runnable> getExecutorQueueForUnitTests() {
|
public BlockingQueue<Runnable> getExecutorQueueForUnitTests() {
|
||||||
return myExecutorQueue;
|
return myExecutorQueue;
|
||||||
}
|
}
|
||||||
|
@ -144,19 +153,22 @@ public abstract class BaseSubscriptionInterceptor extends ServerOperationInterce
|
||||||
rejectedExecutionHandler);
|
rejectedExecutionHandler);
|
||||||
|
|
||||||
|
|
||||||
if (myProcessingChannel == null) {
|
if (getProcessingChannel() == null) {
|
||||||
myProcessingChannel = new ExecutorSubscribableChannel(myExecutor);
|
setProcessingChannel(new ExecutorSubscribableChannel(myExecutor));
|
||||||
|
}
|
||||||
|
if (getDeliveryChannel() == null) {
|
||||||
|
setDeliveryChannel(new ExecutorSubscribableChannel(myExecutor));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myAutoActivateSubscriptions) {
|
if (myAutoActivateSubscriptions) {
|
||||||
if (mySubscriptionActivatingSubscriber == null) {
|
if (mySubscriptionActivatingSubscriber == null) {
|
||||||
mySubscriptionActivatingSubscriber = new SubscriptionActivatingSubscriber(getSubscriptionDao(), myIdToSubscription, getChannelType(), myProcessingChannel);
|
mySubscriptionActivatingSubscriber = new SubscriptionActivatingSubscriber(getSubscriptionDao(), myIdToSubscription, getChannelType(), this);
|
||||||
}
|
}
|
||||||
getProcessingChannel().subscribe(mySubscriptionActivatingSubscriber);
|
getProcessingChannel().subscribe(mySubscriptionActivatingSubscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mySubscriptionCheckingSubscriber == null) {
|
if (mySubscriptionCheckingSubscriber == null) {
|
||||||
mySubscriptionCheckingSubscriber = new SubscriptionCheckingSubscriber(getSubscriptionDao(), myIdToSubscription, getChannelType(), myProcessingChannel);
|
mySubscriptionCheckingSubscriber = new SubscriptionCheckingSubscriber(getSubscriptionDao(), myIdToSubscription, getChannelType(), this);
|
||||||
}
|
}
|
||||||
getProcessingChannel().subscribe(mySubscriptionCheckingSubscriber);
|
getProcessingChannel().subscribe(mySubscriptionCheckingSubscriber);
|
||||||
|
|
||||||
|
|
|
@ -26,14 +26,14 @@ public abstract class BaseSubscriptionRestHookInterceptor extends BaseSubscripti
|
||||||
@Override
|
@Override
|
||||||
protected void registerDeliverySubscriber() {
|
protected void registerDeliverySubscriber() {
|
||||||
if (mySubscriptionDeliverySubscriber == null) {
|
if (mySubscriptionDeliverySubscriber == null) {
|
||||||
mySubscriptionDeliverySubscriber = new SubscriptionDeliveringRestHookSubscriber(getSubscriptionDao(), getIdToSubscription(), getChannelType(), getProcessingChannel());
|
mySubscriptionDeliverySubscriber = new SubscriptionDeliveringRestHookSubscriber(getSubscriptionDao(), getIdToSubscription(), getChannelType(), this);
|
||||||
}
|
}
|
||||||
getProcessingChannel().subscribe(mySubscriptionDeliverySubscriber);
|
getDeliveryChannel().subscribe(mySubscriptionDeliverySubscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void unregisterDeliverySubscriber() {
|
protected void unregisterDeliverySubscriber() {
|
||||||
getProcessingChannel().unsubscribe(mySubscriptionDeliverySubscriber);
|
getDeliveryChannel().unsubscribe(mySubscriptionDeliverySubscriber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.Subscription;
|
import org.hl7.fhir.r4.model.Subscription;
|
||||||
import org.springframework.messaging.MessageHandler;
|
import org.springframework.messaging.MessageHandler;
|
||||||
import org.springframework.messaging.SubscribableChannel;
|
|
||||||
|
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
@ -35,16 +34,16 @@ public abstract class BaseSubscriptionSubscriber implements MessageHandler {
|
||||||
private final IFhirResourceDao mySubscriptionDao;
|
private final IFhirResourceDao mySubscriptionDao;
|
||||||
private final ConcurrentHashMap<String, IBaseResource> myIdToSubscription;
|
private final ConcurrentHashMap<String, IBaseResource> myIdToSubscription;
|
||||||
private final Subscription.SubscriptionChannelType myChannelType;
|
private final Subscription.SubscriptionChannelType myChannelType;
|
||||||
private final SubscribableChannel myProcessingChannel;
|
private final BaseSubscriptionInterceptor mySubscriptionInterceptor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public BaseSubscriptionSubscriber(IFhirResourceDao<? extends IBaseResource> theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, SubscribableChannel theProcessingChannel) {
|
public BaseSubscriptionSubscriber(IFhirResourceDao<? extends IBaseResource> theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor) {
|
||||||
mySubscriptionDao = theSubscriptionDao;
|
mySubscriptionDao = theSubscriptionDao;
|
||||||
myIdToSubscription = theIdToSubscription;
|
myIdToSubscription = theIdToSubscription;
|
||||||
myChannelType = theChannelType;
|
myChannelType = theChannelType;
|
||||||
myProcessingChannel = theProcessingChannel;
|
mySubscriptionInterceptor = theSubscriptionInterceptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Subscription.SubscriptionChannelType getChannelType() {
|
public Subscription.SubscriptionChannelType getChannelType() {
|
||||||
|
@ -59,14 +58,14 @@ public abstract class BaseSubscriptionSubscriber implements MessageHandler {
|
||||||
return myIdToSubscription;
|
return myIdToSubscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SubscribableChannel getProcessingChannel() {
|
|
||||||
return myProcessingChannel;
|
|
||||||
}
|
|
||||||
|
|
||||||
public IFhirResourceDao getSubscriptionDao() {
|
public IFhirResourceDao getSubscriptionDao() {
|
||||||
return mySubscriptionDao;
|
return mySubscriptionDao;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public BaseSubscriptionInterceptor getSubscriptionInterceptor() {
|
||||||
|
return mySubscriptionInterceptor;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Does this subscription type (e.g. rest hook, websocket, etc) apply to this interceptor?
|
* Does this subscription type (e.g. rest hook, websocket, etc) apply to this interceptor?
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -44,14 +44,14 @@ public abstract class BaseSubscriptionWebsocketInterceptor extends BaseSubscript
|
||||||
@Override
|
@Override
|
||||||
protected void registerDeliverySubscriber() {
|
protected void registerDeliverySubscriber() {
|
||||||
if (mySubscriptionDeliverySubscriber == null) {
|
if (mySubscriptionDeliverySubscriber == null) {
|
||||||
mySubscriptionDeliverySubscriber = new SubscriptionDeliveringWebsocketSubscriber(getSubscriptionDao(), getIdToSubscription(), getChannelType(), getProcessingChannel(), myTxManager, mySubscriptionFlaggedResourceDataDao, mySubscriptionTableDao, myResourceTableDao);
|
mySubscriptionDeliverySubscriber = new SubscriptionDeliveringWebsocketSubscriber(getSubscriptionDao(), getIdToSubscription(), getChannelType(), this, myTxManager, mySubscriptionFlaggedResourceDataDao, mySubscriptionTableDao, myResourceTableDao);
|
||||||
}
|
}
|
||||||
getProcessingChannel().subscribe(mySubscriptionDeliverySubscriber);
|
getDeliveryChannel().subscribe(mySubscriptionDeliverySubscriber);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void unregisterDeliverySubscriber() {
|
protected void unregisterDeliverySubscriber() {
|
||||||
getProcessingChannel().unsubscribe(mySubscriptionDeliverySubscriber);
|
getDeliveryChannel().unsubscribe(mySubscriptionDeliverySubscriber);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,8 +41,8 @@ public class SubscriptionActivatingSubscriber extends BaseSubscriptionSubscriber
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public SubscriptionActivatingSubscriber(IFhirResourceDao<? extends IBaseResource> theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, SubscribableChannel theProcessingChannel) {
|
public SubscriptionActivatingSubscriber(IFhirResourceDao<? extends IBaseResource> theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor) {
|
||||||
super(theSubscriptionDao, theIdToSubscription, theChannelType, theProcessingChannel);
|
super(theSubscriptionDao, theIdToSubscription, theChannelType, theSubscriptionInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void activateAndRegisterSubscriptionIfRequired(ResourceModifiedMessage theMsg) {
|
private void activateAndRegisterSubscriptionIfRequired(ResourceModifiedMessage theMsg) {
|
||||||
|
|
|
@ -45,8 +45,8 @@ import java.util.concurrent.ConcurrentHashMap;
|
||||||
public class SubscriptionCheckingSubscriber extends BaseSubscriptionSubscriber {
|
public class SubscriptionCheckingSubscriber extends BaseSubscriptionSubscriber {
|
||||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionCheckingSubscriber.class);
|
private Logger ourLog = LoggerFactory.getLogger(SubscriptionCheckingSubscriber.class);
|
||||||
|
|
||||||
public SubscriptionCheckingSubscriber(IFhirResourceDao theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, SubscribableChannel theProcessingChannel) {
|
public SubscriptionCheckingSubscriber(IFhirResourceDao theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType,BaseSubscriptionInterceptor theSubscriptionInterceptor) {
|
||||||
super(theSubscriptionDao, theIdToSubscription, theChannelType, theProcessingChannel);
|
super(theSubscriptionDao, theIdToSubscription, theChannelType, theSubscriptionInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -112,7 +112,7 @@ public class SubscriptionCheckingSubscriber extends BaseSubscriptionSubscriber {
|
||||||
deliveryMsg.setOperationType(msg.getOperationType());
|
deliveryMsg.setOperationType(msg.getOperationType());
|
||||||
deliveryMsg.setPayloadId(msg.getId());
|
deliveryMsg.setPayloadId(msg.getId());
|
||||||
|
|
||||||
getProcessingChannel().send(new GenericMessage<>(deliveryMsg));
|
getSubscriptionInterceptor().getDeliveryChannel().send(new GenericMessage<>(deliveryMsg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -44,8 +44,8 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionSubscriber {
|
public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionSubscriber {
|
||||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionDeliveringRestHookSubscriber.class);
|
private Logger ourLog = LoggerFactory.getLogger(SubscriptionDeliveringRestHookSubscriber.class);
|
||||||
|
|
||||||
public SubscriptionDeliveringRestHookSubscriber(IFhirResourceDao theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, SubscribableChannel theProcessingChannel) {
|
public SubscriptionDeliveringRestHookSubscriber(IFhirResourceDao theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor) {
|
||||||
super(theSubscriptionDao, theIdToSubscription, theChannelType, theProcessingChannel);
|
super(theSubscriptionDao, theIdToSubscription, theChannelType, theSubscriptionInterceptor);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -58,8 +58,8 @@ public class SubscriptionDeliveringWebsocketSubscriber extends BaseSubscriptionS
|
||||||
private final IResourceTableDao myResourceTableDao;
|
private final IResourceTableDao myResourceTableDao;
|
||||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionDeliveringWebsocketSubscriber.class);
|
private Logger ourLog = LoggerFactory.getLogger(SubscriptionDeliveringWebsocketSubscriber.class);
|
||||||
|
|
||||||
public SubscriptionDeliveringWebsocketSubscriber(IFhirResourceDao theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, SubscribableChannel theProcessingChannel, PlatformTransactionManager theTxManager, ISubscriptionFlaggedResourceDataDao theSubscriptionFlaggedResourceDataDao, ISubscriptionTableDao theSubscriptionTableDao, IResourceTableDao theResourceTableDao) {
|
public SubscriptionDeliveringWebsocketSubscriber(IFhirResourceDao theSubscriptionDao, ConcurrentHashMap<String, IBaseResource> theIdToSubscription, Subscription.SubscriptionChannelType theChannelType, BaseSubscriptionInterceptor theSubscriptionInterceptor, PlatformTransactionManager theTxManager, ISubscriptionFlaggedResourceDataDao theSubscriptionFlaggedResourceDataDao, ISubscriptionTableDao theSubscriptionTableDao, IResourceTableDao theResourceTableDao) {
|
||||||
super(theSubscriptionDao, theIdToSubscription, theChannelType, theProcessingChannel);
|
super(theSubscriptionDao, theIdToSubscription, theChannelType, theSubscriptionInterceptor);
|
||||||
|
|
||||||
myTxManager = theTxManager;
|
myTxManager = theTxManager;
|
||||||
mySubscriptionFlaggedResourceDao = theSubscriptionFlaggedResourceDataDao;
|
mySubscriptionFlaggedResourceDao = theSubscriptionFlaggedResourceDataDao;
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<Bundle xmlns="http://hl7.org/fhir">
|
<Bundle xmlns="http://hl7.org/fhir">
|
||||||
<id value="v2-valuesets"/>
|
<id value="v2-valuesets"/>
|
||||||
<meta>
|
<meta>
|
||||||
<lastUpdated value="2015-11-11T10:54:01.813-05:00"/>
|
<lastUpdated value="2015-10-24T07:41:03.495+11:00"/>
|
||||||
</meta>
|
</meta>
|
||||||
<type value="collection"/>
|
<type value="collection"/>
|
||||||
<entry>
|
<entry>
|
||||||
|
@ -34461,7 +34461,7 @@
|
||||||
<display value="MMR"/>
|
<display value="MMR"/>
|
||||||
<designation>
|
<designation>
|
||||||
<language value="nl"/>
|
<language value="nl"/>
|
||||||
<value value="BMR - bof, mazelen, rodehond"/>
|
<value value="BMR - mazelen, bof, rodehond"/>
|
||||||
</designation>
|
</designation>
|
||||||
</concept>
|
</concept>
|
||||||
<concept>
|
<concept>
|
||||||
|
@ -34901,7 +34901,7 @@
|
||||||
<display value="DTaP"/>
|
<display value="DTaP"/>
|
||||||
<designation>
|
<designation>
|
||||||
<language value="nl"/>
|
<language value="nl"/>
|
||||||
<value value="DaKT -difterie-acellulaire kinkhoest-tetanus"/>
|
<value value="DaKT"/>
|
||||||
</designation>
|
</designation>
|
||||||
</concept>
|
</concept>
|
||||||
<concept>
|
<concept>
|
||||||
|
@ -35396,7 +35396,7 @@
|
||||||
<display value="leprosy"/>
|
<display value="leprosy"/>
|
||||||
<designation>
|
<designation>
|
||||||
<language value="nl"/>
|
<language value="nl"/>
|
||||||
<value value="lepra"/>
|
<value value="leprosy"/>
|
||||||
</designation>
|
</designation>
|
||||||
</concept>
|
</concept>
|
||||||
<concept>
|
<concept>
|
||||||
|
@ -35715,7 +35715,7 @@
|
||||||
<display value="MMRV"/>
|
<display value="MMRV"/>
|
||||||
<designation>
|
<designation>
|
||||||
<language value="nl"/>
|
<language value="nl"/>
|
||||||
<value value="BMRV - bof, mazelen, rodehond en varicella"/>
|
<value value="BMRV - mazelen, bof, rodehond en varicella"/>
|
||||||
</designation>
|
</designation>
|
||||||
</concept>
|
</concept>
|
||||||
<concept>
|
<concept>
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -1,15 +1,10 @@
|
||||||
package org.hl7.fhir.instance.hapi.validation;
|
package org.hl7.fhir.instance.hapi.validation;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.Bundle;
|
import org.hl7.fhir.instance.model.Bundle;
|
||||||
import org.hl7.fhir.instance.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.instance.model.Bundle.BundleEntryComponent;
|
||||||
|
import org.hl7.fhir.instance.model.CodeType;
|
||||||
import org.hl7.fhir.instance.model.IdType;
|
import org.hl7.fhir.instance.model.IdType;
|
||||||
import org.hl7.fhir.instance.model.ValueSet;
|
import org.hl7.fhir.instance.model.ValueSet;
|
||||||
import org.hl7.fhir.instance.model.ValueSet.ConceptSetComponent;
|
import org.hl7.fhir.instance.model.ValueSet.ConceptSetComponent;
|
||||||
|
@ -17,123 +12,138 @@ import org.hl7.fhir.instance.model.ValueSet.ValueSetExpansionComponent;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import java.io.InputStream;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import java.io.InputStreamReader;
|
||||||
|
import java.io.UnsupportedEncodingException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||||
|
|
||||||
private Map<String, ValueSet> myDefaultValueSets;
|
private Map<String, ValueSet> myDefaultValueSets;
|
||||||
private Map<String, ValueSet> myCodeSystems;
|
private Map<String, ValueSet> myCodeSystems;
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
* Constructor
|
||||||
return false;
|
*/
|
||||||
}
|
public DefaultProfileValidationSupport() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* Constructor
|
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||||
*/
|
return null;
|
||||||
public DefaultProfileValidationSupport() {
|
}
|
||||||
super();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void flush() {
|
@Override
|
||||||
myDefaultValueSets = null;
|
public ValueSet fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||||
myCodeSystems = null;
|
synchronized (this) {
|
||||||
}
|
Map<String, ValueSet> valueSets = myCodeSystems;
|
||||||
|
if (valueSets == null) {
|
||||||
|
valueSets = new HashMap<String, ValueSet>();
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/valuesets.xml");
|
||||||
@Override
|
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v2-tables.xml");
|
||||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml");
|
||||||
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
|
||||||
return (T) FhirInstanceValidator.loadProfileOrReturnNull(null, theContext, theUri.substring("http://hl7.org/fhir/StructureDefinition/".length()));
|
|
||||||
}
|
|
||||||
if (theUri.startsWith("http://hl7.org/fhir/ValueSet/")) {
|
|
||||||
Map<String, ValueSet> defaultValueSets = myDefaultValueSets;
|
|
||||||
if (defaultValueSets == null) {
|
|
||||||
String path = theContext.getVersion().getPathToSchemaDefinitions().replace("/schema", "/valueset") + "/valuesets.xml";
|
|
||||||
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(path);
|
|
||||||
if (valuesetText == null) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
InputStreamReader reader;
|
|
||||||
try {
|
|
||||||
reader = new InputStreamReader(valuesetText, "UTF-8");
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
// Shouldn't happen!
|
|
||||||
throw new InternalErrorException("UTF-8 encoding not supported on this platform", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
defaultValueSets = new HashMap<String, ValueSet>();
|
myCodeSystems = valueSets;
|
||||||
|
}
|
||||||
|
|
||||||
FhirContext ctx = FhirInstanceValidator.getHl7OrgDstu2Ctx(theContext);
|
return valueSets.get(theSystem);
|
||||||
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, reader);
|
}
|
||||||
for (BundleEntryComponent next : bundle.getEntry()) {
|
}
|
||||||
IdType nextId = new IdType(next.getFullUrl());
|
|
||||||
if (nextId.isEmpty() || !nextId.getValue().startsWith("http://hl7.org/fhir/ValueSet/")) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
defaultValueSets.put(nextId.toVersionless().getValue(), (ValueSet) next.getResource());
|
|
||||||
}
|
|
||||||
|
|
||||||
myDefaultValueSets = defaultValueSets;
|
@SuppressWarnings("unchecked")
|
||||||
}
|
@Override
|
||||||
|
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||||
|
if (theUri.startsWith("http://hl7.org/fhir/StructureDefinition/")) {
|
||||||
|
return (T) FhirInstanceValidator.loadProfileOrReturnNull(null, theContext, theUri.substring("http://hl7.org/fhir/StructureDefinition/".length()));
|
||||||
|
}
|
||||||
|
if (theUri.startsWith("http://hl7.org/fhir/ValueSet/")) {
|
||||||
|
Map<String, ValueSet> defaultValueSets = myDefaultValueSets;
|
||||||
|
if (defaultValueSets == null) {
|
||||||
|
String path = theContext.getVersion().getPathToSchemaDefinitions().replace("/schema", "/valueset") + "/valuesets.xml";
|
||||||
|
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(path);
|
||||||
|
if (valuesetText == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
InputStreamReader reader;
|
||||||
|
try {
|
||||||
|
reader = new InputStreamReader(valuesetText, "UTF-8");
|
||||||
|
} catch (UnsupportedEncodingException e) {
|
||||||
|
// Shouldn't happen!
|
||||||
|
throw new InternalErrorException("UTF-8 encoding not supported on this platform", e);
|
||||||
|
}
|
||||||
|
|
||||||
return (T) defaultValueSets.get(theUri);
|
defaultValueSets = new HashMap<String, ValueSet>();
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
FhirContext ctx = FhirInstanceValidator.getHl7OrgDstu2Ctx(theContext);
|
||||||
}
|
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, reader);
|
||||||
|
for (BundleEntryComponent next : bundle.getEntry()) {
|
||||||
|
IdType nextId = new IdType(next.getFullUrl());
|
||||||
|
if (nextId.isEmpty() || !nextId.getValue().startsWith("http://hl7.org/fhir/ValueSet/")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
defaultValueSets.put(nextId.toVersionless().getValue(), (ValueSet) next.getResource());
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
myDefaultValueSets = defaultValueSets;
|
||||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
}
|
||||||
return new CodeValidationResult(IssueSeverity.INFORMATION, "Unknown code: " + theCodeSystem + " / " + theCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
return (T) defaultValueSets.get(theUri);
|
||||||
public ValueSet fetchCodeSystem(FhirContext theContext, String theSystem) {
|
}
|
||||||
synchronized (this) {
|
|
||||||
Map<String, ValueSet> valueSets = myCodeSystems;
|
|
||||||
if (valueSets == null) {
|
|
||||||
valueSets = new HashMap<String, ValueSet>();
|
|
||||||
|
|
||||||
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/valuesets.xml");
|
return null;
|
||||||
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v2-tables.xml");
|
}
|
||||||
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml");
|
|
||||||
|
|
||||||
myCodeSystems = valueSets;
|
public void flush() {
|
||||||
}
|
myDefaultValueSets = null;
|
||||||
|
myCodeSystems = null;
|
||||||
|
}
|
||||||
|
|
||||||
return valueSets.get(theSystem);
|
@Override
|
||||||
}
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
}
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
private void loadCodeSystems(FhirContext theContext, Map<String, ValueSet> codeSystems, String file) {
|
private void loadCodeSystems(FhirContext theContext, Map<String, ValueSet> codeSystems, String file) {
|
||||||
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(file);
|
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(file);
|
||||||
if (valuesetText != null) {
|
if (valuesetText != null) {
|
||||||
InputStreamReader reader;
|
InputStreamReader reader;
|
||||||
try {
|
try {
|
||||||
reader = new InputStreamReader(valuesetText, "UTF-8");
|
reader = new InputStreamReader(valuesetText, "UTF-8");
|
||||||
} catch (UnsupportedEncodingException e) {
|
} catch (UnsupportedEncodingException e) {
|
||||||
// Shouldn't happen!
|
// Shouldn't happen!
|
||||||
throw new InternalErrorException("UTF-8 encoding not supported on this platform", e);
|
throw new InternalErrorException("UTF-8 encoding not supported on this platform", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
FhirContext ctx = FhirInstanceValidator.getHl7OrgDstu2Ctx(theContext);
|
FhirContext ctx = FhirInstanceValidator.getHl7OrgDstu2Ctx(theContext);
|
||||||
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, reader);
|
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, reader);
|
||||||
for (BundleEntryComponent next : bundle.getEntry()) {
|
for (BundleEntryComponent next : bundle.getEntry()) {
|
||||||
ValueSet nextValueSet = (ValueSet) next.getResource();
|
ValueSet nextValueSet = (ValueSet) next.getResource();
|
||||||
String system = nextValueSet.getCodeSystem().getSystem();
|
String system = nextValueSet.getCodeSystem().getSystem();
|
||||||
if (isNotBlank(system)) {
|
if (isNotBlank(system)) {
|
||||||
codeSystems.put(system, nextValueSet);
|
codeSystems.put(system, nextValueSet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||||
return null;
|
ValueSet vs = fetchCodeSystem(theContext, theCodeSystem);
|
||||||
}
|
if (vs != null) {
|
||||||
|
for (ValueSet.ConceptDefinitionComponent nextConcept : vs.getCodeSystem().getConcept()) {
|
||||||
|
if (nextConcept.getCode().equals(theCode)){
|
||||||
|
ValueSet.ConceptDefinitionComponent component = new ValueSet.ConceptDefinitionComponent(new CodeType(theCode));
|
||||||
|
return new CodeValidationResult(component);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,6 @@
|
||||||
package org.hl7.fhir.instance.hapi.validation;
|
package org.hl7.fhir.instance.hapi.validation;
|
||||||
|
|
||||||
import java.util.List;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.instance.formats.IParser;
|
import org.hl7.fhir.instance.formats.IParser;
|
||||||
import org.hl7.fhir.instance.formats.ParserType;
|
import org.hl7.fhir.instance.formats.ParserType;
|
||||||
|
@ -15,10 +13,14 @@ import org.hl7.fhir.instance.model.ValueSet.ValueSetExpansionComponent;
|
||||||
import org.hl7.fhir.instance.terminologies.ValueSetExpander;
|
import org.hl7.fhir.instance.terminologies.ValueSetExpander;
|
||||||
import org.hl7.fhir.instance.terminologies.ValueSetExpanderFactory;
|
import org.hl7.fhir.instance.terminologies.ValueSetExpanderFactory;
|
||||||
import org.hl7.fhir.instance.terminologies.ValueSetExpanderSimple;
|
import org.hl7.fhir.instance.terminologies.ValueSetExpanderSimple;
|
||||||
import org.hl7.fhir.instance.utils.*;
|
import org.hl7.fhir.instance.utils.INarrativeGenerator;
|
||||||
|
import org.hl7.fhir.instance.utils.IResourceValidator;
|
||||||
|
import org.hl7.fhir.instance.utils.IWorkerContext;
|
||||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public final class HapiWorkerContext implements IWorkerContext, ValueSetExpanderFactory, ValueSetExpander {
|
public final class HapiWorkerContext implements IWorkerContext, ValueSetExpanderFactory, ValueSetExpander {
|
||||||
private final FhirContext myCtx;
|
private final FhirContext myCtx;
|
||||||
|
@ -174,21 +176,6 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validateCode(String theSystem, String theCode, String theDisplay, ValueSet theVs) {
|
public ValidationResult validateCode(String theSystem, String theCode, String theDisplay, ValueSet theVs) {
|
||||||
|
|
||||||
/*
|
|
||||||
* For some reason the built-in valueset is empty
|
|
||||||
*/
|
|
||||||
if (theVs.getIdElement().getValue().equals("http://hl7.org/fhir/ValueSet/defined-types")) {
|
|
||||||
// try {
|
|
||||||
// myCtx.getResourceDefinition(theCode);
|
|
||||||
// return new ValidationResult(new ConceptDefinitionComponent(new CodeType(theCode)));
|
|
||||||
// } catch (DataFormatException e){
|
|
||||||
// if (myCtx.getElementDefinition(theCode) != null) {
|
|
||||||
// return new ValidationResult(new ConceptDefinitionComponent(new CodeType(theCode)));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return new ValidationResult(new ConceptDefinitionComponent(new CodeType(theCode)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theSystem == null || StringUtils.equals(theSystem, theVs.getCodeSystem().getSystem())) {
|
if (theSystem == null || StringUtils.equals(theSystem, theVs.getCodeSystem().getSystem())) {
|
||||||
for (ConceptDefinitionComponent next : theVs.getCodeSystem().getConcept()) {
|
for (ConceptDefinitionComponent next : theVs.getCodeSystem().getConcept()) {
|
||||||
ValidationResult retVal = validateCodeSystem(theCode, next);
|
ValidationResult retVal = validateCodeSystem(theCode, next);
|
||||||
|
@ -199,7 +186,13 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
||||||
}
|
}
|
||||||
|
|
||||||
for (ConceptSetComponent nextComposeConceptSet : theVs.getCompose().getInclude()) {
|
for (ConceptSetComponent nextComposeConceptSet : theVs.getCompose().getInclude()) {
|
||||||
if (StringUtils.equals(theSystem, nextComposeConceptSet.getSystem())) {
|
|
||||||
|
String nextSystem = theSystem;
|
||||||
|
if (nextSystem == null && isNotBlank(nextComposeConceptSet.getSystem())) {
|
||||||
|
nextSystem = nextComposeConceptSet.getSystem();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.equals(nextSystem, nextComposeConceptSet.getSystem())) {
|
||||||
for (ConceptReferenceComponent nextComposeCode : nextComposeConceptSet.getConcept()) {
|
for (ConceptReferenceComponent nextComposeCode : nextComposeConceptSet.getConcept()) {
|
||||||
ConceptDefinitionComponent conceptDef = new ConceptDefinitionComponent();
|
ConceptDefinitionComponent conceptDef = new ConceptDefinitionComponent();
|
||||||
conceptDef.setCode(nextComposeCode.getCode());
|
conceptDef.setCode(nextComposeCode.getCode());
|
||||||
|
@ -209,8 +202,16 @@ public final class HapiWorkerContext implements IWorkerContext, ValueSetExpander
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nextComposeConceptSet.getConcept().isEmpty()){
|
||||||
|
ValidationResult result = validateCode(nextSystem, theCode, null);
|
||||||
|
if (result.isOk()){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return new ValidationResult(IssueSeverity.ERROR, "Unknown code[" + theCode + "] in system[" + theSystem + "]");
|
return new ValidationResult(IssueSeverity.ERROR, "Unknown code[" + theCode + "] in system[" + theSystem + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,17 +13,28 @@ public class HapiWorkerContextTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIdTypes(){
|
public void testIdTypes(){
|
||||||
|
|
||||||
HapiWorkerContext hwc = new HapiWorkerContext(FhirContext.forDstu2(), new DefaultProfileValidationSupport());
|
DefaultProfileValidationSupport validationSupport = new DefaultProfileValidationSupport();
|
||||||
ValueSet vs = new ValueSet();
|
FhirContext ctx = FhirContext.forDstu2();
|
||||||
vs.setId("http://hl7.org/fhir/ValueSet/defined-types");
|
HapiWorkerContext hwc = new HapiWorkerContext(ctx, validationSupport);
|
||||||
|
|
||||||
|
ValueSet vs = validationSupport.fetchResource(ctx, ValueSet.class, "http://hl7.org/fhir/ValueSet/defined-types");
|
||||||
IWorkerContext.ValidationResult outcome;
|
IWorkerContext.ValidationResult outcome;
|
||||||
|
|
||||||
|
outcome = hwc.validateCode("http://hl7.org/fhir/resource-types", "Patient", null);
|
||||||
|
assertTrue(outcome.isOk());
|
||||||
|
|
||||||
|
outcome = hwc.validateCode("http://hl7.org/fhir/resource-types", "Patient", null, vs);
|
||||||
|
assertTrue(outcome.isOk());
|
||||||
|
|
||||||
outcome = hwc.validateCode(null, "Patient", null, vs);
|
outcome = hwc.validateCode(null, "Patient", null, vs);
|
||||||
assertTrue(outcome.isOk());
|
assertTrue(outcome.isOk());
|
||||||
|
|
||||||
outcome = hwc.validateCode(null, "id", null, vs);
|
outcome = hwc.validateCode(null, "id", null, vs);
|
||||||
assertTrue(outcome.isOk());
|
assertTrue(outcome.isOk());
|
||||||
|
|
||||||
|
outcome = hwc.validateCode(null, "foo", null, vs);
|
||||||
|
assertFalse(outcome.isOk());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -151,10 +151,14 @@ public class ResourceMinimizerMojo extends AbstractMojo {
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void main(String[] args) throws Exception {
|
public static void main(String[] args) throws Exception {
|
||||||
FhirContext ctxDstu2 = FhirContext.forDstu2();
|
FhirContext ctxDstu2;
|
||||||
FhirContext ctxDstu2_1 = FhirContext.forDstu2_1();
|
FhirContext ctxDstu2_1;
|
||||||
FhirContext ctxDstu3 = FhirContext.forDstu3();
|
FhirContext ctxDstu3;
|
||||||
FhirContext ctxR4 = FhirContext.forR4();
|
FhirContext ctxR4;
|
||||||
|
ctxDstu2 = FhirContext.forDstu2();
|
||||||
|
ctxDstu2_1 = FhirContext.forDstu2_1();
|
||||||
|
ctxDstu3 = FhirContext.forDstu3();
|
||||||
|
ctxR4 = FhirContext.forR4();
|
||||||
|
|
||||||
LoggerContext loggerContext = ((ch.qos.logback.classic.Logger) ourLog).getLoggerContext();
|
LoggerContext loggerContext = ((ch.qos.logback.classic.Logger) ourLog).getLoggerContext();
|
||||||
URL mainURL = ConfigurationWatchListUtil.getMainWatchURL(loggerContext);
|
URL mainURL = ConfigurationWatchListUtil.getMainWatchURL(loggerContext);
|
||||||
|
|
|
@ -319,6 +319,10 @@
|
||||||
<action type="add">
|
<action type="add">
|
||||||
REST Hook subscriptions now honour the Subscription.channel.header field
|
REST Hook subscriptions now honour the Subscription.channel.header field
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
DSTU2 validator has been enhanced to do a better job handling
|
||||||
|
ValueSets with expansions pointing to other ValueSets
|
||||||
|
</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