Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
04764ed07e
|
@ -24,6 +24,7 @@ import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -47,6 +48,7 @@ import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||||
import ca.uhn.fhir.rest.param.CollectionBinder;
|
import ca.uhn.fhir.rest.param.CollectionBinder;
|
||||||
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.param.ResourceParameter;
|
import ca.uhn.fhir.rest.param.ResourceParameter;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
@ -66,6 +68,7 @@ public class OperationParameter implements IParameter {
|
||||||
private Class<?> myParameterType;
|
private Class<?> myParameterType;
|
||||||
private String myParamType;
|
private String myParamType;
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
|
private boolean myAllowGet;
|
||||||
|
|
||||||
public OperationParameter(FhirContext theCtx, String theOperationName, OperationParam theOperationParam) {
|
public OperationParameter(FhirContext theCtx, String theOperationName, OperationParam theOperationParam) {
|
||||||
this(theCtx, theOperationName, theOperationParam.name(), theOperationParam.min(), theOperationParam.max());
|
this(theCtx, theOperationName, theOperationParam.name(), theOperationParam.min(), theOperationParam.max());
|
||||||
|
@ -107,6 +110,8 @@ public class OperationParameter implements IParameter {
|
||||||
myMax = 1;
|
myMax = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myAllowGet = IPrimitiveType.class.isAssignableFrom(myParameterType);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The parameter can be of type string for validation methods - This is a bit
|
* The parameter can be of type string for validation methods - This is a bit
|
||||||
* weird. See ValidateDstu2Test. We should probably clean this up..
|
* weird. See ValidateDstu2Test. We should probably clean this up..
|
||||||
|
@ -114,6 +119,10 @@ public class OperationParameter implements IParameter {
|
||||||
if (!myParameterType.equals(IBase.class) && !myParameterType.equals(String.class)) {
|
if (!myParameterType.equals(IBase.class) && !myParameterType.equals(String.class)) {
|
||||||
if (IBaseResource.class.isAssignableFrom(myParameterType) && myParameterType.isInterface()) {
|
if (IBaseResource.class.isAssignableFrom(myParameterType) && myParameterType.isInterface()) {
|
||||||
myParamType = "Resource";
|
myParamType = "Resource";
|
||||||
|
} else if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
|
||||||
|
myParamType = "date";
|
||||||
|
myMax = 2;
|
||||||
|
myAllowGet = true;
|
||||||
} else if (!IBase.class.isAssignableFrom(myParameterType) || myParameterType.isInterface() || Modifier.isAbstract(myParameterType.getModifiers())) {
|
} else if (!IBase.class.isAssignableFrom(myParameterType) || myParameterType.isInterface() || Modifier.isAbstract(myParameterType.getModifiers())) {
|
||||||
throw new ConfigurationException("Invalid type for @OperationParam: " + myParameterType.getName());
|
throw new ConfigurationException("Invalid type for @OperationParam: " + myParameterType.getName());
|
||||||
} else if (myParameterType.equals(ValidationModeEnum.class)) {
|
} else if (myParameterType.equals(ValidationModeEnum.class)) {
|
||||||
|
@ -153,13 +162,25 @@ public class OperationParameter implements IParameter {
|
||||||
if (theRequest.getRequestType() == RequestTypeEnum.GET) {
|
if (theRequest.getRequestType() == RequestTypeEnum.GET) {
|
||||||
String[] paramValues = theRequest.getParameters().get(myName);
|
String[] paramValues = theRequest.getParameters().get(myName);
|
||||||
if (paramValues != null && paramValues.length > 0) {
|
if (paramValues != null && paramValues.length > 0) {
|
||||||
if (IPrimitiveType.class.isAssignableFrom(myParameterType)) {
|
if (myAllowGet) {
|
||||||
for (String nextValue : paramValues) {
|
|
||||||
FhirContext ctx = theRequest.getServer().getFhirContext();
|
if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
|
||||||
RuntimePrimitiveDatatypeDefinition def = (RuntimePrimitiveDatatypeDefinition) ctx.getElementDefinition((Class<? extends IBase>) myParameterType);
|
List<QualifiedParamList> parameters = new ArrayList<QualifiedParamList>();
|
||||||
IPrimitiveType<?> instance = def.newInstance();
|
parameters.add(QualifiedParamList.singleton(paramValues[0]));
|
||||||
instance.setValueAsString(nextValue);
|
if (paramValues.length > 1) {
|
||||||
matchingParamValues.add(instance);
|
parameters.add(QualifiedParamList.singleton(paramValues[1]));
|
||||||
|
}
|
||||||
|
DateRangeParam dateRangeParam = new DateRangeParam();
|
||||||
|
dateRangeParam.setValuesAsQueryTokens(parameters);
|
||||||
|
matchingParamValues.add(dateRangeParam);
|
||||||
|
} else {
|
||||||
|
for (String nextValue : paramValues) {
|
||||||
|
FhirContext ctx = theRequest.getServer().getFhirContext();
|
||||||
|
RuntimePrimitiveDatatypeDefinition def = (RuntimePrimitiveDatatypeDefinition) ctx.getElementDefinition((Class<? extends IBase>) myParameterType);
|
||||||
|
IPrimitiveType<?> instance = def.newInstance();
|
||||||
|
instance.setValueAsString(nextValue);
|
||||||
|
matchingParamValues.add(instance);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
HapiLocalizer localizer = theRequest.getServer().getFhirContext().getLocalizer();
|
HapiLocalizer localizer = theRequest.getServer().getFhirContext().getLocalizer();
|
||||||
|
|
|
@ -11,7 +11,14 @@ a browser.
|
||||||
<!--*/-->
|
<!--*/-->
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<div class="hapiHeaderText" th:if="${not resource.nameElement.empty}" th:narrative="${resource.name}"></div>
|
<th:block th:switch="${fhirVersion}">
|
||||||
|
<th:block th:case="'DSTU1'">
|
||||||
|
<div class="hapiHeaderText" th:if="${not resource.nameElement.empty}" th:narrative="${resource.name}"></div>
|
||||||
|
</th:block>
|
||||||
|
<th:block th:case="*">
|
||||||
|
<div class="hapiHeaderText" th:if="${not resource.code.empty}" th:narrative="${resource.code}"></div>
|
||||||
|
</th:block>
|
||||||
|
</th:block>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!--/*-->
|
<!--/*-->
|
||||||
|
|
|
@ -1615,7 +1615,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
/**
|
/**
|
||||||
* THIS SHOULD RETURN HASHSET and not jsut Set because we add to it later (so it can't be Collections.emptySet())
|
* THIS SHOULD RETURN HASHSET and not jsut Set because we add to it later (so it can't be Collections.emptySet())
|
||||||
*/
|
*/
|
||||||
private HashSet<Long> loadReverseIncludes(List<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode) {
|
private HashSet<Long> loadReverseIncludes(Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode) {
|
||||||
if (theMatches.size() == 0) {
|
if (theMatches.size() == 0) {
|
||||||
return new HashSet<Long>();
|
return new HashSet<Long>();
|
||||||
}
|
}
|
||||||
|
@ -2023,6 +2023,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Load _include and _revinclude before filter and sort in everything mode
|
||||||
|
if (theParams.isEverythingMode() == true) {
|
||||||
|
if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
|
||||||
|
loadPids.addAll(loadReverseIncludes(loadPids, theParams.getRevIncludes(), true));
|
||||||
|
loadPids.addAll(loadReverseIncludes(loadPids, theParams.getIncludes(), false));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Handle _lastUpdated
|
// Handle _lastUpdated
|
||||||
DateRangeParam lu = theParams.getLastUpdated();
|
DateRangeParam lu = theParams.getLastUpdated();
|
||||||
if (lu != null && (lu.getLowerBoundAsInstant() != null || lu.getUpperBoundAsInstant() != null)) {
|
if (lu != null && (lu.getLowerBoundAsInstant() != null || lu.getUpperBoundAsInstant() != null)) {
|
||||||
|
@ -2054,52 +2062,15 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle sorting if any was provided
|
// Handle sorting if any was provided
|
||||||
final List<Long> pids;
|
final List<Long> pids = processSort(theParams, loadPids);
|
||||||
if (theParams.getSort() != null && isNotBlank(theParams.getSort().getParamName())) {
|
|
||||||
List<Order> orders = new ArrayList<Order>();
|
|
||||||
List<Predicate> predicates = new ArrayList<Predicate>();
|
|
||||||
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
|
||||||
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
|
||||||
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
|
||||||
predicates.add(from.get("myId").in(loadPids));
|
|
||||||
createSort(builder, from, theParams.getSort(), orders, predicates);
|
|
||||||
if (orders.size() > 0) {
|
|
||||||
Set<Long> originalPids = loadPids;
|
|
||||||
loadPids = new LinkedHashSet<Long>();
|
|
||||||
cq.multiselect(from.get("myId").as(Long.class));
|
|
||||||
cq.where(predicates.toArray(new Predicate[0]));
|
|
||||||
cq.orderBy(orders);
|
|
||||||
|
|
||||||
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
|
||||||
|
|
||||||
for (Tuple next : query.getResultList()) {
|
|
||||||
loadPids.add(next.get(0, Long.class));
|
|
||||||
}
|
|
||||||
|
|
||||||
ourLog.debug("Sort PID order is now: {}", loadPids);
|
|
||||||
|
|
||||||
pids = new ArrayList<Long>(loadPids);
|
|
||||||
|
|
||||||
// Any ressources which weren't matched by the sort get added to the bottom
|
|
||||||
for (Long next : originalPids) {
|
|
||||||
if (loadPids.contains(next) == false) {
|
|
||||||
pids.add(next);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
pids = new ArrayList<Long>(loadPids);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
pids = new ArrayList<Long>(loadPids);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load _revinclude resources
|
// Load _revinclude resources
|
||||||
final Set<Long> revIncludedPids;
|
final Set<Long> revIncludedPids;
|
||||||
if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
|
if (theParams.isEverythingMode() == false) {
|
||||||
revIncludedPids = loadReverseIncludes(pids, theParams.getRevIncludes(), true);
|
if (theParams.getRevIncludes() != null && theParams.getRevIncludes().isEmpty() == false) {
|
||||||
if (theParams.isEverythingMode()) {
|
revIncludedPids = loadReverseIncludes(pids, theParams.getRevIncludes(), true);
|
||||||
revIncludedPids.addAll(loadReverseIncludes(pids, theParams.getIncludes(), false));
|
} else {
|
||||||
|
revIncludedPids = new HashSet<Long>();
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
revIncludedPids = new HashSet<Long>();
|
revIncludedPids = new HashSet<Long>();
|
||||||
|
@ -2155,6 +2126,49 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private List<Long> processSort(final SearchParameterMap theParams, Set<Long> loadPids) {
|
||||||
|
final List<Long> pids;
|
||||||
|
if (theParams.getSort() != null && isNotBlank(theParams.getSort().getParamName())) {
|
||||||
|
List<Order> orders = new ArrayList<Order>();
|
||||||
|
List<Predicate> predicates = new ArrayList<Predicate>();
|
||||||
|
CriteriaBuilder builder = myEntityManager.getCriteriaBuilder();
|
||||||
|
CriteriaQuery<Tuple> cq = builder.createTupleQuery();
|
||||||
|
Root<ResourceTable> from = cq.from(ResourceTable.class);
|
||||||
|
predicates.add(from.get("myId").in(loadPids));
|
||||||
|
createSort(builder, from, theParams.getSort(), orders, predicates);
|
||||||
|
if (orders.size() > 0) {
|
||||||
|
Set<Long> originalPids = loadPids;
|
||||||
|
loadPids = new LinkedHashSet<Long>();
|
||||||
|
cq.multiselect(from.get("myId").as(Long.class));
|
||||||
|
cq.where(predicates.toArray(new Predicate[0]));
|
||||||
|
cq.orderBy(orders);
|
||||||
|
|
||||||
|
TypedQuery<Tuple> query = myEntityManager.createQuery(cq);
|
||||||
|
|
||||||
|
for (Tuple next : query.getResultList()) {
|
||||||
|
loadPids.add(next.get(0, Long.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
ourLog.debug("Sort PID order is now: {}", loadPids);
|
||||||
|
|
||||||
|
pids = new ArrayList<Long>(loadPids);
|
||||||
|
|
||||||
|
// Any ressources which weren't matched by the sort get added to the bottom
|
||||||
|
for (Long next : originalPids) {
|
||||||
|
if (loadPids.contains(next) == false) {
|
||||||
|
pids.add(next);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
pids = new ArrayList<Long>(loadPids);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
pids = new ArrayList<Long>(loadPids);
|
||||||
|
}
|
||||||
|
return pids;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBundleProvider search(String theParameterName, IQueryParameterType theValue) {
|
public IBundleProvider search(String theParameterName, IQueryParameterType theValue) {
|
||||||
return search(Collections.singletonMap(theParameterName, theValue));
|
return search(Collections.singletonMap(theParameterName, theValue));
|
||||||
|
|
|
@ -8,13 +8,15 @@ import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.UnsignedIntDt;
|
import ca.uhn.fhir.model.primitive.UnsignedIntDt;
|
||||||
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
|
|
||||||
public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>implements IFhirResourceDaoPatient<Patient> {
|
public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>implements IFhirResourceDaoPatient<Patient> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBundleProvider everything(HttpServletRequest theServletRequest, IdDt theId, UnsignedIntDt theCount) {
|
public IBundleProvider everything(HttpServletRequest theServletRequest, IdDt theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
|
||||||
SearchParameterMap paramMap = new SearchParameterMap();
|
SearchParameterMap paramMap = new SearchParameterMap();
|
||||||
if (theCount != null) {
|
if (theCount != null) {
|
||||||
paramMap.setCount(theCount.getValue());
|
paramMap.setCount(theCount.getValue());
|
||||||
|
@ -23,6 +25,8 @@ public class FhirResourceDaoPatientDstu2 extends FhirResourceDaoDstu2<Patient>im
|
||||||
paramMap.setRevIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
|
paramMap.setRevIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
|
||||||
paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
|
paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
|
||||||
paramMap.setEverythingMode(true);
|
paramMap.setEverythingMode(true);
|
||||||
|
paramMap.setSort(theSort);
|
||||||
|
paramMap.setLastUpdated(theLastUpdated);
|
||||||
paramMap.add("_id", new StringParam(theId.getIdPart()));
|
paramMap.add("_id", new StringParam(theId.getIdPart()));
|
||||||
ca.uhn.fhir.rest.server.IBundleProvider retVal = search(paramMap);
|
ca.uhn.fhir.rest.server.IBundleProvider retVal = search(paramMap);
|
||||||
return retVal;
|
return retVal;
|
||||||
|
|
|
@ -26,10 +26,12 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.UnsignedIntDt;
|
import ca.uhn.fhir.model.primitive.UnsignedIntDt;
|
||||||
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
import ca.uhn.fhir.rest.server.IBundleProvider;
|
import ca.uhn.fhir.rest.server.IBundleProvider;
|
||||||
|
|
||||||
public interface IFhirResourceDaoPatient<T extends IBaseResource> extends IFhirResourceDao<T> {
|
public interface IFhirResourceDaoPatient<T extends IBaseResource> extends IFhirResourceDao<T> {
|
||||||
|
|
||||||
IBundleProvider everything(HttpServletRequest theServletRequest, IdDt theId, UnsignedIntDt theCount);
|
IBundleProvider everything(HttpServletRequest theServletRequest, IdDt theId, UnsignedIntDt theCount, DateRangeParam theLastUpdate, SortSpec theSort);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -51,12 +51,12 @@ public class JpaValidationSupportDstu2 implements IValidationSupport {
|
||||||
private FhirContext myDstu2Ctx;
|
private FhirContext myDstu2Ctx;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(ConceptSetComponent theInclude) {
|
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet fetchCodeSystem(String theSystem) {
|
public ValueSet fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,20 +85,19 @@ public class JpaValidationSupportDstu2 implements IValidationSupport {
|
||||||
/*
|
/*
|
||||||
* Validator wants RI structures and not HAPI ones, so convert
|
* Validator wants RI structures and not HAPI ones, so convert
|
||||||
*
|
*
|
||||||
* TODO: we really need a more efficient way of converting.. Or maybe this will
|
* TODO: we really need a more efficient way of converting.. Or maybe this will just go away when we move to RI structures
|
||||||
* just go away when we move to RI structures
|
|
||||||
*/
|
*/
|
||||||
String encoded = myDstu2Ctx.newJsonParser().encodeResourceToString(res);
|
String encoded = myDstu2Ctx.newJsonParser().encodeResourceToString(res);
|
||||||
return myRiCtx.newJsonParser().parseResource(theClass, encoded);
|
return myRiCtx.newJsonParser().parseResource(theClass, encoded);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(String theSystem) {
|
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeValidationResult validateCode(String theCodeSystem, String theCode, String theDisplay) {
|
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,10 @@ import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Operation;
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
|
import ca.uhn.fhir.rest.annotation.Sort;
|
||||||
|
import ca.uhn.fhir.rest.api.SortSpec;
|
||||||
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
|
import ca.uhn.fhir.rest.server.Constants;
|
||||||
|
|
||||||
public class BaseJpaResourceProviderPatientDstu2 extends JpaResourceProviderDstu2<Patient> {
|
public class BaseJpaResourceProviderPatientDstu2 extends JpaResourceProviderDstu2<Patient> {
|
||||||
|
|
||||||
|
@ -18,12 +22,21 @@ public class BaseJpaResourceProviderPatientDstu2 extends JpaResourceProviderDstu
|
||||||
ca.uhn.fhir.model.primitive.IdDt theId,
|
ca.uhn.fhir.model.primitive.IdDt theId,
|
||||||
|
|
||||||
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
|
||||||
@OperationParam(name = "_count")
|
@OperationParam(name = Constants.PARAM_COUNT)
|
||||||
ca.uhn.fhir.model.primitive.UnsignedIntDt theCount) {
|
ca.uhn.fhir.model.primitive.UnsignedIntDt theCount,
|
||||||
|
|
||||||
|
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
|
||||||
|
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
|
||||||
|
DateRangeParam theLastUpdated,
|
||||||
|
|
||||||
|
// @OperationParam(name = Constants.PARAM_SORT, min=0, max=1)
|
||||||
|
@Sort
|
||||||
|
SortSpec theSortSpec
|
||||||
|
) {
|
||||||
|
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
return ((IFhirResourceDaoPatient<Patient>)getDao()).everything(theServletRequest, theId, theCount);
|
return ((IFhirResourceDaoPatient<Patient>)getDao()).everything(theServletRequest, theId, theCount, theLastUpdated, theSortSpec);
|
||||||
} finally {
|
} finally {
|
||||||
endRequest(theServletRequest);
|
endRequest(theServletRequest);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<context:annotation-config />
|
<context:annotation-config />
|
||||||
|
|
||||||
<websocket:handlers>
|
<websocket:handlers>
|
||||||
<websocket:mapping path="/baseDstu2/websocket" handler="mySubscriptionWebsocketHandler" />
|
<websocket:mapping path="/websocket/dstu2" handler="mySubscriptionWebsocketHandler" />
|
||||||
</websocket:handlers>
|
</websocket:handlers>
|
||||||
|
|
||||||
<!--
|
<!--
|
||||||
|
|
|
@ -602,6 +602,96 @@ public class ResourceProviderDstu2Test extends BaseResourceProviderDstu2Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEverythingWithLastUpdatedAndSort() throws Exception {
|
||||||
|
String methodName = "testEverythingWithLastUpdatedAndSort";
|
||||||
|
|
||||||
|
long time0 = System.currentTimeMillis();
|
||||||
|
Thread.sleep(10);
|
||||||
|
|
||||||
|
Organization org = new Organization();
|
||||||
|
org.setName(methodName);
|
||||||
|
IIdType oId = ourClient.create().resource(org).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
long time1 = System.currentTimeMillis();
|
||||||
|
Thread.sleep(10);
|
||||||
|
|
||||||
|
Patient p = new Patient();
|
||||||
|
p.addName().addFamily(methodName);
|
||||||
|
p.getManagingOrganization().setReference(oId);
|
||||||
|
IIdType pId = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
long time2 = System.currentTimeMillis();
|
||||||
|
Thread.sleep(10);
|
||||||
|
|
||||||
|
Condition c = new Condition();
|
||||||
|
c.getCode().setText(methodName);
|
||||||
|
c.getPatient().setReference(pId);
|
||||||
|
IIdType cId = ourClient.create().resource(c).execute().getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Thread.sleep(10);
|
||||||
|
long time3 = System.currentTimeMillis();
|
||||||
|
|
||||||
|
// %3E=> %3C=<
|
||||||
|
|
||||||
|
HttpGet get = new HttpGet(ourServerBase + "/Patient/" + pId.getIdPart() + "/$everything?_lastUpdated=%3E" + new InstantDt(new Date(time1)).getValueAsString());
|
||||||
|
CloseableHttpResponse response = ourHttpClient.execute(get);
|
||||||
|
try {
|
||||||
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
|
String output = IOUtils.toString(response.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||||
|
ourLog.info(output);
|
||||||
|
List<IdDt> ids = toIdListUnqualifiedVersionless(myFhirCtx.newXmlParser().parseBundle(output));
|
||||||
|
ourLog.info(ids.toString());
|
||||||
|
assertThat(ids, containsInAnyOrder(pId, cId));
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
get = new HttpGet(ourServerBase + "/Patient/" + pId.getIdPart() + "/$everything?_lastUpdated=%3E" + new InstantDt(new Date(time2)).getValueAsString() + "&_lastUpdated=%3C" + new InstantDt(new Date(time3)).getValueAsString());
|
||||||
|
response = ourHttpClient.execute(get);
|
||||||
|
try {
|
||||||
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
|
String output = IOUtils.toString(response.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||||
|
ourLog.info(output);
|
||||||
|
List<IdDt> ids = toIdListUnqualifiedVersionless(myFhirCtx.newXmlParser().parseBundle(output));
|
||||||
|
ourLog.info(ids.toString());
|
||||||
|
assertThat(ids, containsInAnyOrder(cId));
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
get = new HttpGet(ourServerBase + "/Patient/" + pId.getIdPart() + "/$everything?_lastUpdated=%3E" + new InstantDt(new Date(time1)).getValueAsString() + "&_sort=_lastUpdated");
|
||||||
|
response = ourHttpClient.execute(get);
|
||||||
|
try {
|
||||||
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
|
String output = IOUtils.toString(response.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||||
|
ourLog.info(output);
|
||||||
|
List<IdDt> ids = toIdListUnqualifiedVersionless(myFhirCtx.newXmlParser().parseBundle(output));
|
||||||
|
ourLog.info(ids.toString());
|
||||||
|
assertThat(ids, contains(pId, cId));
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
get = new HttpGet(ourServerBase + "/Patient/" + pId.getIdPart() + "/$everything?_sort:desc=_lastUpdated");
|
||||||
|
response = ourHttpClient.execute(get);
|
||||||
|
try {
|
||||||
|
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||||
|
String output = IOUtils.toString(response.getEntity().getContent());
|
||||||
|
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||||
|
ourLog.info(output);
|
||||||
|
List<IdDt> ids = toIdListUnqualifiedVersionless(myFhirCtx.newXmlParser().parseBundle(output));
|
||||||
|
ourLog.info(ids.toString());
|
||||||
|
assertThat(ids, contains(cId, pId, oId));
|
||||||
|
} finally {
|
||||||
|
response.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See #148
|
* See #148
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -324,7 +324,7 @@ public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {
|
||||||
SimpleEchoSocket socket = new SimpleEchoSocket(subsId);
|
SimpleEchoSocket socket = new SimpleEchoSocket(subsId);
|
||||||
try {
|
try {
|
||||||
client.start();
|
client.start();
|
||||||
URI echoUri = new URI("ws://localhost:" + ourPort + "/baseDstu2/websocket");
|
URI echoUri = new URI("ws://localhost:" + ourPort + "/websocket/dstu2");
|
||||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||||
client.connect(socket, echoUri, request);
|
client.connect(socket, echoUri, request);
|
||||||
ourLog.info("Connecting to : {}", echoUri);
|
ourLog.info("Connecting to : {}", echoUri);
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
package ca.uhn.fhirtest;
|
package ca.uhn.fhirtest;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
|
||||||
import org.apache.derby.drda.NetworkServerControl;
|
import org.apache.derby.drda.NetworkServerControl;
|
||||||
import org.springframework.beans.factory.DisposableBean;
|
import org.springframework.beans.factory.DisposableBean;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
import org.springframework.beans.factory.InitializingBean;
|
||||||
|
@ -22,7 +26,30 @@ public class DerbyNetworkServer implements InitializingBean, DisposableBean {
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
server = new NetworkServerControl();
|
server = new NetworkServerControl();
|
||||||
server.start (null);
|
Writer w = new Writer() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(char[] theCbuf, int theOff, int theLen) throws IOException {
|
||||||
|
ourLog.info("[DERBY] " + new String(theCbuf, theOff, theLen));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void flush() throws IOException {
|
||||||
|
// nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
// nothing
|
||||||
|
}};
|
||||||
|
server.start (new PrintWriter(w));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void main(String[] args) throws Exception {
|
||||||
|
DerbyNetworkServer s = new DerbyNetworkServer();
|
||||||
|
s.afterPropertiesSet();
|
||||||
|
s.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@ import javax.servlet.ServletException;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||||
import org.springframework.web.context.ContextLoaderListener;
|
import org.springframework.web.context.ContextLoaderListener;
|
||||||
import org.springframework.web.context.WebApplicationContext;
|
import org.springframework.web.context.WebApplicationContext;
|
||||||
|
@ -35,7 +36,7 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestRestfulServer.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestRestfulServer.class);
|
||||||
|
|
||||||
private ClassPathXmlApplicationContext myAppCtx;
|
private ApplicationContext myAppCtx;
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
@Override
|
@Override
|
||||||
|
@ -44,6 +45,7 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
|
|
||||||
// Get the spring context from the web container (it's declared in web.xml)
|
// Get the spring context from the web container (it's declared in web.xml)
|
||||||
WebApplicationContext parentAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
WebApplicationContext parentAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
|
||||||
|
myAppCtx = (parentAppCtx);
|
||||||
|
|
||||||
// These two parmeters are also declared in web.xml
|
// These two parmeters are also declared in web.xml
|
||||||
String implDesc = getInitParameter("ImplementationDescription");
|
String implDesc = getInitParameter("ImplementationDescription");
|
||||||
|
@ -64,9 +66,6 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
String baseUrlProperty;
|
String baseUrlProperty;
|
||||||
switch (fhirVersionParam.trim().toUpperCase()) {
|
switch (fhirVersionParam.trim().toUpperCase()) {
|
||||||
case "DSTU1": {
|
case "DSTU1": {
|
||||||
myAppCtx = new ClassPathXmlApplicationContext(new String[] {
|
|
||||||
"hapi-fhir-server-database-config-dstu1.xml",
|
|
||||||
"hapi-fhir-server-resourceproviders-dstu1.xml"}, parentAppCtx);
|
|
||||||
setFhirContext(FhirContext.forDstu1());
|
setFhirContext(FhirContext.forDstu1());
|
||||||
beans = myAppCtx.getBean("myResourceProvidersDstu1", List.class);
|
beans = myAppCtx.getBean("myResourceProvidersDstu1", List.class);
|
||||||
systemProviderDstu1 = myAppCtx.getBean("mySystemProviderDstu1", JpaSystemProviderDstu1.class);
|
systemProviderDstu1 = myAppCtx.getBean("mySystemProviderDstu1", JpaSystemProviderDstu1.class);
|
||||||
|
@ -79,11 +78,6 @@ public class TestRestfulServer extends RestfulServer {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "DSTU2": {
|
case "DSTU2": {
|
||||||
myAppCtx = new ClassPathXmlApplicationContext(new String[] {
|
|
||||||
"hapi-fhir-server-database-config-dstu2.xml",
|
|
||||||
"hapi-fhir-server-resourceproviders-dstu2.xml",
|
|
||||||
"fhir-spring-subscription-config-dstu2.xml"
|
|
||||||
}, parentAppCtx);
|
|
||||||
setFhirContext(FhirContext.forDstu2());
|
setFhirContext(FhirContext.forDstu2());
|
||||||
beans = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
|
beans = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
|
||||||
systemProviderDstu2 = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
|
systemProviderDstu2 = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
|
||||||
|
|
|
@ -12,6 +12,11 @@
|
||||||
/WEB-INF/hapi-fhir-server-config.xml
|
/WEB-INF/hapi-fhir-server-config.xml
|
||||||
/WEB-INF/hapi-fhir-tester-application-context.xml
|
/WEB-INF/hapi-fhir-tester-application-context.xml
|
||||||
/WEB-INF/hapi-fhir-tester-config.xml
|
/WEB-INF/hapi-fhir-tester-config.xml
|
||||||
|
classpath:/hapi-fhir-server-database-config-dstu1.xml
|
||||||
|
classpath:/hapi-fhir-server-database-config-dstu2.xml
|
||||||
|
classpath:hapi-fhir-server-resourceproviders-dstu1.xml
|
||||||
|
classpath:hapi-fhir-server-resourceproviders-dstu2.xml
|
||||||
|
classpath:fhir-spring-subscription-config-dstu2.xml
|
||||||
</param-value>
|
</param-value>
|
||||||
</context-param>
|
</context-param>
|
||||||
|
|
||||||
|
@ -25,6 +30,7 @@
|
||||||
<param-value>
|
<param-value>
|
||||||
/WEB-INF/hapi-fhir-tester-application-context.xml
|
/WEB-INF/hapi-fhir-tester-application-context.xml
|
||||||
/WEB-INF/hapi-fhir-tester-config.xml
|
/WEB-INF/hapi-fhir-tester-config.xml
|
||||||
|
classpath:fhir-spring-subscription-config-dstu2.xml
|
||||||
</param-value>
|
</param-value>
|
||||||
</init-param>
|
</init-param>
|
||||||
<load-on-startup>2</load-on-startup>
|
<load-on-startup>2</load-on-startup>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package ca.uhn.fhir.narrative;
|
package ca.uhn.fhir.narrative;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
@ -53,7 +54,7 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
|
||||||
Patient value = new Patient();
|
Patient value = new Patient();
|
||||||
|
|
||||||
value.addIdentifier().setSystem("urn:names").setValue("123456");
|
value.addIdentifier().setSystem("urn:names").setValue("123456");
|
||||||
value.addName().addFamily("blow").addGiven("joe").addGiven((String)null).addGiven("john");
|
value.addName().addFamily("blow").addGiven("joe").addGiven((String) null).addGiven("john");
|
||||||
value.getAddressFirstRep().addLine("123 Fake Street").addLine("Unit 1");
|
value.getAddressFirstRep().addLine("123 Fake Street").addLine("Unit 1");
|
||||||
value.getAddressFirstRep().setCity("Toronto").setState("ON").setCountry("Canada");
|
value.getAddressFirstRep().setCity("Toronto").setState("ON").setCountry("Canada");
|
||||||
|
|
||||||
|
@ -67,12 +68,12 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
|
||||||
|
|
||||||
String title = myGen.generateTitle(value);
|
String title = myGen.generateTitle(value);
|
||||||
assertEquals("joe john BLOW (123456)", title);
|
assertEquals("joe john BLOW (123456)", title);
|
||||||
// ourLog.info(title);
|
// ourLog.info(title);
|
||||||
|
|
||||||
value.getIdentifierFirstRep().setValue("FOO MRN 123");
|
value.getIdentifierFirstRep().setValue("FOO MRN 123");
|
||||||
title = myGen.generateTitle(value);
|
title = myGen.generateTitle(value);
|
||||||
assertEquals("joe john BLOW (FOO MRN 123)", title);
|
assertEquals("joe john BLOW (FOO MRN 123)", title);
|
||||||
// ourLog.info(title);
|
// ourLog.info(title);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +81,7 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
|
||||||
public void testGenerateEncounter() throws DataFormatException {
|
public void testGenerateEncounter() throws DataFormatException {
|
||||||
Encounter enc = new Encounter();
|
Encounter enc = new Encounter();
|
||||||
|
|
||||||
enc.addIdentifier().setSystem("urn:visits").setValue( "1234567");
|
enc.addIdentifier().setSystem("urn:visits").setValue("1234567");
|
||||||
enc.setClassElement(EncounterClassEnum.AMBULATORY);
|
enc.setClassElement(EncounterClassEnum.AMBULATORY);
|
||||||
enc.setPeriod(new PeriodDt().setStart(new DateTimeDt("2001-01-02T11:11:00")));
|
enc.setPeriod(new PeriodDt().setStart(new DateTimeDt("2001-01-02T11:11:00")));
|
||||||
enc.setType(ca.uhn.fhir.model.dstu2.valueset.EncounterTypeEnum.ANNUAL_DIABETES_MELLITUS_SCREENING);
|
enc.setType(ca.uhn.fhir.model.dstu2.valueset.EncounterTypeEnum.ANNUAL_DIABETES_MELLITUS_SCREENING);
|
||||||
|
@ -92,7 +93,6 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateDiagnosticReport() throws DataFormatException {
|
public void testGenerateDiagnosticReport() throws DataFormatException {
|
||||||
DiagnosticReport value = new DiagnosticReport();
|
DiagnosticReport value = new DiagnosticReport();
|
||||||
|
@ -127,9 +127,9 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
|
||||||
|
|
||||||
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, parse);
|
OperationOutcome oo = ourCtx.newXmlParser().parseResource(OperationOutcome.class, parse);
|
||||||
|
|
||||||
// String output = gen.generateTitle(oo);
|
// String output = gen.generateTitle(oo);
|
||||||
// ourLog.info(output);
|
// ourLog.info(output);
|
||||||
// assertEquals("Operation Outcome (2 issues)", output);
|
// assertEquals("Operation Outcome (2 issues)", output);
|
||||||
|
|
||||||
NarrativeDt narrative = new NarrativeDt();
|
NarrativeDt narrative = new NarrativeDt();
|
||||||
myGen.generateNarrative(null, oo, narrative);
|
myGen.generateNarrative(null, oo, narrative);
|
||||||
|
@ -137,11 +137,11 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
|
||||||
|
|
||||||
ourLog.info(output);
|
ourLog.info(output);
|
||||||
|
|
||||||
// oo = new OperationOutcome();
|
// oo = new OperationOutcome();
|
||||||
// oo.addIssue().setSeverity(IssueSeverityEnum.FATAL).setDetails("AA");
|
// oo.addIssue().setSeverity(IssueSeverityEnum.FATAL).setDetails("AA");
|
||||||
// output = gen.generateTitle(oo);
|
// output = gen.generateTitle(oo);
|
||||||
// ourLog.info(output);
|
// ourLog.info(output);
|
||||||
// assertEquals("Operation Outcome (fatal)", output);
|
// assertEquals("Operation Outcome (fatal)", output);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -195,25 +195,41 @@ public class DefaultThymeleafNarrativeGeneratorTestDstu2 {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGenerateMedicationPrescription(){
|
public void testGenerateMedicationPrescription() {
|
||||||
MedicationOrder mp = new MedicationOrder();
|
MedicationOrder mp = new MedicationOrder();
|
||||||
mp.setId("12345");
|
mp.setId("12345");
|
||||||
Medication med = new Medication();
|
Medication med = new Medication();
|
||||||
med.getCode().setText("ciproflaxin");
|
med.getCode().setText("ciproflaxin");
|
||||||
ResourceReferenceDt medRef = new ResourceReferenceDt(med);
|
ResourceReferenceDt medRef = new ResourceReferenceDt(med);
|
||||||
mp.setMedication(medRef );
|
mp.setMedication(medRef);
|
||||||
mp.setStatus(MedicationOrderStatusEnum.ACTIVE);
|
mp.setStatus(MedicationOrderStatusEnum.ACTIVE);
|
||||||
mp.setDateWritten(new DateTimeDt("2014-09-01"));
|
mp.setDateWritten(new DateTimeDt("2014-09-01"));
|
||||||
|
|
||||||
NarrativeDt narrative = new NarrativeDt();
|
NarrativeDt narrative = new NarrativeDt();
|
||||||
myGen.generateNarrative(mp, narrative);
|
myGen.generateNarrative(mp, narrative);
|
||||||
|
|
||||||
assertTrue("Expected medication name of ciprofloaxin within narrative: " + narrative.getDiv().toString(), narrative.getDiv().toString().indexOf("ciprofloaxin")>-1);
|
assertTrue("Expected medication name of ciprofloaxin within narrative: " + narrative.getDiv().toString(), narrative.getDiv().toString().indexOf("ciprofloaxin") > -1);
|
||||||
assertTrue("Expected string status of ACTIVE within narrative: " + narrative.getDiv().toString(), narrative.getDiv().toString().indexOf("ACTIVE")>-1);
|
assertTrue("Expected string status of ACTIVE within narrative: " + narrative.getDiv().toString(), narrative.getDiv().toString().indexOf("ACTIVE") > -1);
|
||||||
|
|
||||||
String title = myGen.generateTitle(mp);
|
String title = myGen.generateTitle(mp);
|
||||||
assertEquals("ciprofloaxin", title);
|
assertEquals("ciprofloaxin", title);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGenerateMedication() {
|
||||||
|
Medication med = new Medication();
|
||||||
|
med.getCode().setText("ciproflaxin");
|
||||||
|
|
||||||
|
NarrativeDt narrative = new NarrativeDt();
|
||||||
|
myGen.generateNarrative(med, narrative);
|
||||||
|
|
||||||
|
String string = narrative.getDiv().toString();
|
||||||
|
assertThat(string, containsString("ciproflaxin"));
|
||||||
|
|
||||||
|
String title = myGen.generateTitle(med);
|
||||||
|
assertEquals("ciproflaxin", title);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -92,63 +92,6 @@ public class XmlParserDstu2Test {
|
||||||
private static final FhirContext ourCtx = FhirContext.forDstu2();
|
private static final FhirContext ourCtx = FhirContext.forDstu2();
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserDstu2Test.class);
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testParseBundleWithResourceId() {
|
|
||||||
//@formatter:off
|
|
||||||
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">"
|
|
||||||
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"3\"/><lastUpdated value=\"2015-09-11T23:35:43.273-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
|
|
||||||
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"2\"/><lastUpdated value=\"2015-09-11T23:35:42.849-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
|
|
||||||
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"1\"/><lastUpdated value=\"2015-09-11T23:35:42.295-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
|
|
||||||
+ "</Bundle>\n";
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, input);
|
|
||||||
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/3", bundle.getEntry().get(0).getResource().getId().getValue());
|
|
||||||
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/2", bundle.getEntry().get(1).getResource().getId().getValue());
|
|
||||||
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/1", bundle.getEntry().get(2).getResource().getId().getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {
|
|
||||||
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.setId("phitcc_pat_normal");
|
|
||||||
patient.addName().addGiven("Patty").setUse(NameUseEnum.NICKNAME);
|
|
||||||
patient.addTelecom().setSystem(ContactPointSystemEnum.EMAIL).setValue("patpain@ehealthinnovation.org");
|
|
||||||
patient.setGender(AdministrativeGenderEnum.FEMALE);
|
|
||||||
patient.setBirthDate(new DateDt("2001-10-13"));
|
|
||||||
|
|
||||||
DateTimeDt obsEffectiveTime = new DateTimeDt("2015-04-11T12:22:01-04:00");
|
|
||||||
|
|
||||||
Observation obsParent = new Observation();
|
|
||||||
obsParent.setId("phitcc_obs_bp_parent");
|
|
||||||
obsParent.getSubject().setResource(patient);
|
|
||||||
obsParent.setStatus(ObservationStatusEnum.FINAL);
|
|
||||||
obsParent.setEffective(obsEffectiveTime);
|
|
||||||
|
|
||||||
Observation obsSystolic = new Observation();
|
|
||||||
obsSystolic.setId("phitcc_obs_bp_dia");
|
|
||||||
obsSystolic.getSubject().setResource(patient);
|
|
||||||
obsSystolic.setEffective(obsEffectiveTime);
|
|
||||||
obsParent.addRelated().setType(ObservationRelationshipTypeEnum.HAS_MEMBER).setTarget(new ResourceReferenceDt(obsSystolic));
|
|
||||||
|
|
||||||
Observation obsDiastolic = new Observation();
|
|
||||||
obsDiastolic.setId("phitcc_obs_bp_dia");
|
|
||||||
obsDiastolic.getSubject().setResource(patient);
|
|
||||||
obsDiastolic.setEffective(obsEffectiveTime);
|
|
||||||
obsParent.addRelated().setType(ObservationRelationshipTypeEnum.HAS_MEMBER).setTarget(new ResourceReferenceDt(obsDiastolic));
|
|
||||||
|
|
||||||
String str = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(obsParent);
|
|
||||||
ourLog.info(str);
|
|
||||||
|
|
||||||
assertThat(str, containsString("<reference value=\"Patient/phitcc_pat_normal\"/>"));
|
|
||||||
assertThat(str, containsString("<reference value=\"Observation/phitcc_obs_bp_dia\"/>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testBundleWithBinary() {
|
public void testBundleWithBinary() {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
@ -231,86 +174,6 @@ public class XmlParserDstu2Test {
|
||||||
assertTrue(parsed.getEntries().get(0).getResource().getId().isEmpty());
|
assertTrue(parsed.getEntries().get(0).getResource().getId().isEmpty());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* See #216 - Profiled datatypes should use their unprofiled parent type as the choice[x] name
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testEncodeAndParseProfiledDatatypeChoice() throws Exception {
|
|
||||||
IParser xmlParser = ourCtx.newXmlParser();
|
|
||||||
|
|
||||||
String input = IOUtils.toString(XmlParser.class.getResourceAsStream("/medicationstatement_invalidelement.xml"));
|
|
||||||
MedicationStatement ms = xmlParser.parseResource(MedicationStatement.class, input);
|
|
||||||
SimpleQuantityDt q = (SimpleQuantityDt) ms.getDosage().get(0).getQuantity();
|
|
||||||
assertEquals("1", q.getValueElement().getValueAsString());
|
|
||||||
|
|
||||||
String output = xmlParser.encodeResourceToString(ms);
|
|
||||||
assertThat(output, containsString("<quantityQuantity><value value=\"1\"/></quantityQuantity>"));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See #216
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testEncodeAndParseIdentifierDstu2() {
|
|
||||||
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);
|
|
||||||
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.addIdentifier().setSystem("SYS").setValue("VAL").setType(IdentifierTypeCodesEnum.MR);
|
|
||||||
|
|
||||||
String out = xmlParser.encodeResourceToString(patient);
|
|
||||||
ourLog.info(out);
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
assertThat(out, stringContainsInOrder("<identifier>",
|
|
||||||
"<type>",
|
|
||||||
"<coding>",
|
|
||||||
"<system value=\"http://hl7.org/fhir/v2/0203\"/>",
|
|
||||||
"<code value=\"MR\"/>",
|
|
||||||
"</coding>",
|
|
||||||
"</type>",
|
|
||||||
"<system value=\"SYS\"/>",
|
|
||||||
"<value value=\"VAL\"/>",
|
|
||||||
"</identifier>"));
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
patient = ourCtx.newXmlParser().parseResource(Patient.class, out);
|
|
||||||
assertThat(patient.getIdentifier().get(0).getType().getValueAsEnum(), contains(IdentifierTypeCodesEnum.MR));
|
|
||||||
assertEquals("http://hl7.org/fhir/v2/0203", patient.getIdentifier().get(0).getType().getCoding().get(0).getSystem());
|
|
||||||
assertEquals("MR", patient.getIdentifier().get(0).getType().getCoding().get(0).getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* See #216
|
|
||||||
*/
|
|
||||||
@Test
|
|
||||||
public void testParseMalformedIdentifierDstu2() {
|
|
||||||
|
|
||||||
// This was changed from 0.5 to 1.0.0
|
|
||||||
|
|
||||||
//@formatter:off
|
|
||||||
String out = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
|
||||||
" <identifier>\n" +
|
|
||||||
" <type value=\"MRN\"/>\n" +
|
|
||||||
" <system value=\"SYS\"/>\n" +
|
|
||||||
" <value value=\"VAL\"/>\n" +
|
|
||||||
" </identifier>\n" +
|
|
||||||
"</Patient>";
|
|
||||||
//@formatter:on
|
|
||||||
|
|
||||||
IParserErrorHandler errorHandler = mock(IParserErrorHandler.class);
|
|
||||||
|
|
||||||
IParser p = ourCtx.newXmlParser();
|
|
||||||
p.setParserErrorHandler(errorHandler);
|
|
||||||
|
|
||||||
Patient patient = p.parseResource(Patient.class, out);
|
|
||||||
assertThat(patient.getIdentifier().get(0).getType().getValueAsEnum(), IsEmptyCollection.empty());
|
|
||||||
|
|
||||||
ArgumentCaptor<String> capt = ArgumentCaptor.forClass(String.class);
|
|
||||||
verify(errorHandler, times(1)).unknownAttribute(any(IParseLocation.class), capt.capture());
|
|
||||||
|
|
||||||
assertEquals("value", capt.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeAndParseContained() {
|
public void testEncodeAndParseContained() {
|
||||||
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);
|
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||||
|
@ -448,9 +311,11 @@ public class XmlParserDstu2Test {
|
||||||
String enc = ourCtx.newXmlParser().encodeResourceToString(patient);
|
String enc = ourCtx.newXmlParser().encodeResourceToString(patient);
|
||||||
assertThat(enc, containsString("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://example.com/extensions#someext\"><valueDateTime value=\"2011-01-02T11:13:15\"/></extension>"));
|
assertThat(enc, containsString("<Patient xmlns=\"http://hl7.org/fhir\"><extension url=\"http://example.com/extensions#someext\"><valueDateTime value=\"2011-01-02T11:13:15\"/></extension>"));
|
||||||
assertThat(enc, containsString("<modifierExtension url=\"http://example.com/extensions#modext\"><valueDate value=\"1995-01-02\"/></modifierExtension>"));
|
assertThat(enc, containsString("<modifierExtension url=\"http://example.com/extensions#modext\"><valueDate value=\"1995-01-02\"/></modifierExtension>"));
|
||||||
assertThat(enc, containsString("<extension url=\"http://example.com#parent\"><extension url=\"http://example.com#child\"><valueString value=\"value1\"/></extension><extension url=\"http://example.com#child\"><valueString value=\"value2\"/></extension></extension>"));
|
assertThat(enc, containsString(
|
||||||
|
"<extension url=\"http://example.com#parent\"><extension url=\"http://example.com#child\"><valueString value=\"value1\"/></extension><extension url=\"http://example.com#child\"><valueString value=\"value2\"/></extension></extension>"));
|
||||||
assertThat(enc, containsString("<given value=\"Joe\"><extension url=\"http://examples.com#givenext\"><valueString value=\"given\"/></extension></given>"));
|
assertThat(enc, containsString("<given value=\"Joe\"><extension url=\"http://examples.com#givenext\"><valueString value=\"given\"/></extension></given>"));
|
||||||
assertThat(enc, containsString("<given value=\"Shmoe\"><extension url=\"http://examples.com#givenext_parent\"><extension url=\"http://examples.com#givenext_child\"><valueString value=\"CHILD\"/></extension></extension></given>"));
|
assertThat(enc, containsString(
|
||||||
|
"<given value=\"Shmoe\"><extension url=\"http://examples.com#givenext_parent\"><extension url=\"http://examples.com#givenext_child\"><valueString value=\"CHILD\"/></extension></extension></given>"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Now parse this back
|
* Now parse this back
|
||||||
|
@ -490,6 +355,38 @@ public class XmlParserDstu2Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #216
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEncodeAndParseIdentifierDstu2() {
|
||||||
|
IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true);
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setSystem("SYS").setValue("VAL").setType(IdentifierTypeCodesEnum.MR);
|
||||||
|
|
||||||
|
String out = xmlParser.encodeResourceToString(patient);
|
||||||
|
ourLog.info(out);
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
assertThat(out, stringContainsInOrder("<identifier>",
|
||||||
|
"<type>",
|
||||||
|
"<coding>",
|
||||||
|
"<system value=\"http://hl7.org/fhir/v2/0203\"/>",
|
||||||
|
"<code value=\"MR\"/>",
|
||||||
|
"</coding>",
|
||||||
|
"</type>",
|
||||||
|
"<system value=\"SYS\"/>",
|
||||||
|
"<value value=\"VAL\"/>",
|
||||||
|
"</identifier>"));
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
patient = ourCtx.newXmlParser().parseResource(Patient.class, out);
|
||||||
|
assertThat(patient.getIdentifier().get(0).getType().getValueAsEnum(), contains(IdentifierTypeCodesEnum.MR));
|
||||||
|
assertEquals("http://hl7.org/fhir/v2/0203", patient.getIdentifier().get(0).getType().getCoding().get(0).getSystem());
|
||||||
|
assertEquals("MR", patient.getIdentifier().get(0).getType().getCoding().get(0).getCode());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeAndParseMetaProfileAndTags() {
|
public void testEncodeAndParseMetaProfileAndTags() {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
@ -595,6 +492,38 @@ public class XmlParserDstu2Test {
|
||||||
assertEquals(new Tag("scheme2", "term2", "label2"), tagList.get(1));
|
assertEquals(new Tag("scheme2", "term2", "label2"), tagList.get(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Test for #233
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEncodeAndParseProfiledDatatype() {
|
||||||
|
MedicationOrder mo = new MedicationOrder();
|
||||||
|
mo.addDosageInstruction().getTiming().getRepeat().setBounds(new DurationDt().setCode("code"));
|
||||||
|
String out = ourCtx.newXmlParser().encodeResourceToString(mo);
|
||||||
|
ourLog.info(out);
|
||||||
|
assertThat(out, containsString("</boundsQuantity>"));
|
||||||
|
|
||||||
|
mo = ourCtx.newXmlParser().parseResource(MedicationOrder.class, out);
|
||||||
|
DurationDt duration = (DurationDt) mo.getDosageInstruction().get(0).getTiming().getRepeat().getBounds();
|
||||||
|
assertEquals("code", duration.getCode());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #216 - Profiled datatypes should use their unprofiled parent type as the choice[x] name
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testEncodeAndParseProfiledDatatypeChoice() throws Exception {
|
||||||
|
IParser xmlParser = ourCtx.newXmlParser();
|
||||||
|
|
||||||
|
String input = IOUtils.toString(XmlParser.class.getResourceAsStream("/medicationstatement_invalidelement.xml"));
|
||||||
|
MedicationStatement ms = xmlParser.parseResource(MedicationStatement.class, input);
|
||||||
|
SimpleQuantityDt q = (SimpleQuantityDt) ms.getDosage().get(0).getQuantity();
|
||||||
|
assertEquals("1", q.getValueElement().getValueAsString());
|
||||||
|
|
||||||
|
String output = xmlParser.encodeResourceToString(ms);
|
||||||
|
assertThat(output, containsString("<quantityQuantity><value value=\"1\"/></quantityQuantity>"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeAndParseSecurityLabels() {
|
public void testEncodeAndParseSecurityLabels() {
|
||||||
Patient p = new Patient();
|
Patient p = new Patient();
|
||||||
|
@ -791,8 +720,10 @@ public class XmlParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
// @formatter:on
|
// @formatter:on
|
||||||
assertThat(encoded, stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"123\"/>", "<code>", "<coding>", "<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>",
|
assertThat(encoded,
|
||||||
"</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#123\"/>", "<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
|
stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"123\"/>", "<code>", "<coding>",
|
||||||
|
"<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>", "</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#123\"/>",
|
||||||
|
"<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -824,12 +755,13 @@ public class XmlParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
assertThat(encoded, stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"1\"/>", "<code>", "<coding>", "<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>",
|
assertThat(encoded,
|
||||||
"</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#1\"/>", "<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
|
stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"1\"/>", "<code>", "<coding>",
|
||||||
|
"<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>", "</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#1\"/>",
|
||||||
|
"<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* See #113
|
* See #113
|
||||||
*/
|
*/
|
||||||
|
@ -861,8 +793,10 @@ public class XmlParserDstu2Test {
|
||||||
ourLog.info(encoded);
|
ourLog.info(encoded);
|
||||||
|
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
assertThat(encoded, stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"123\"/>", "<code>", "<coding>", "<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>",
|
assertThat(encoded,
|
||||||
"</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#123\"/>", "<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
|
stringContainsInOrder("<MedicationOrder xmlns=\"http://hl7.org/fhir\">", "<contained>", "<Medication xmlns=\"http://hl7.org/fhir\">", "<id value=\"123\"/>", "<code>", "<coding>",
|
||||||
|
"<system value=\"urn:sys\"/>", "<code value=\"code1\"/>", "</coding>", "</code>", "</Medication>", "</contained>", "<medicationReference>", "<reference value=\"#123\"/>",
|
||||||
|
"<display value=\"MedRef\"/>", "</medicationReference>", "</MedicationOrder>"));
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -894,7 +828,6 @@ public class XmlParserDstu2Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #158
|
* #158
|
||||||
*/
|
*/
|
||||||
|
@ -911,6 +844,7 @@ public class XmlParserDstu2Test {
|
||||||
assertThat(encoded, not(containsString("tag")));
|
assertThat(encoded, not(containsString("tag")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* #158
|
* #158
|
||||||
*/
|
*/
|
||||||
|
@ -929,7 +863,6 @@ public class XmlParserDstu2Test {
|
||||||
assertThat(encoded, not(containsString("Label")));
|
assertThat(encoded, not(containsString("Label")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeExtensionWithResourceContent() {
|
public void testEncodeExtensionWithResourceContent() {
|
||||||
IParser parser = ourCtx.newXmlParser();
|
IParser parser = ourCtx.newXmlParser();
|
||||||
|
@ -951,6 +884,7 @@ public class XmlParserDstu2Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeNarrativeSuppressed() {
|
public void testEncodeNarrativeSuppressed() {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
|
@ -1011,6 +945,43 @@ public class XmlParserDstu2Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeReferenceUsingUnqualifiedResourceWorksCorrectly() {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.setId("phitcc_pat_normal");
|
||||||
|
patient.addName().addGiven("Patty").setUse(NameUseEnum.NICKNAME);
|
||||||
|
patient.addTelecom().setSystem(ContactPointSystemEnum.EMAIL).setValue("patpain@ehealthinnovation.org");
|
||||||
|
patient.setGender(AdministrativeGenderEnum.FEMALE);
|
||||||
|
patient.setBirthDate(new DateDt("2001-10-13"));
|
||||||
|
|
||||||
|
DateTimeDt obsEffectiveTime = new DateTimeDt("2015-04-11T12:22:01-04:00");
|
||||||
|
|
||||||
|
Observation obsParent = new Observation();
|
||||||
|
obsParent.setId("phitcc_obs_bp_parent");
|
||||||
|
obsParent.getSubject().setResource(patient);
|
||||||
|
obsParent.setStatus(ObservationStatusEnum.FINAL);
|
||||||
|
obsParent.setEffective(obsEffectiveTime);
|
||||||
|
|
||||||
|
Observation obsSystolic = new Observation();
|
||||||
|
obsSystolic.setId("phitcc_obs_bp_dia");
|
||||||
|
obsSystolic.getSubject().setResource(patient);
|
||||||
|
obsSystolic.setEffective(obsEffectiveTime);
|
||||||
|
obsParent.addRelated().setType(ObservationRelationshipTypeEnum.HAS_MEMBER).setTarget(new ResourceReferenceDt(obsSystolic));
|
||||||
|
|
||||||
|
Observation obsDiastolic = new Observation();
|
||||||
|
obsDiastolic.setId("phitcc_obs_bp_dia");
|
||||||
|
obsDiastolic.getSubject().setResource(patient);
|
||||||
|
obsDiastolic.setEffective(obsEffectiveTime);
|
||||||
|
obsParent.addRelated().setType(ObservationRelationshipTypeEnum.HAS_MEMBER).setTarget(new ResourceReferenceDt(obsDiastolic));
|
||||||
|
|
||||||
|
String str = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(obsParent);
|
||||||
|
ourLog.info(str);
|
||||||
|
|
||||||
|
assertThat(str, containsString("<reference value=\"Patient/phitcc_pat_normal\"/>"));
|
||||||
|
assertThat(str, containsString("<reference value=\"Observation/phitcc_obs_bp_dia\"/>"));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testEncodeSummary() {
|
public void testEncodeSummary() {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
|
@ -1052,6 +1023,57 @@ public class XmlParserDstu2Test {
|
||||||
assertThat(encoded, not(containsString("maritalStatus")));
|
assertThat(encoded, not(containsString("maritalStatus")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEncodeWithEncodeElements() throws Exception {
|
||||||
|
String content = IOUtils.toString(XmlParserDstu2Test.class.getResourceAsStream("/bundle-example.xml"));
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addName().addFamily("FAMILY");
|
||||||
|
patient.addAddress().addLine("LINE1");
|
||||||
|
|
||||||
|
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
||||||
|
bundle.setTotal(100);
|
||||||
|
bundle.addEntry().setResource(patient);
|
||||||
|
|
||||||
|
{
|
||||||
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name", "Bundle.entry")));
|
||||||
|
p.setPrettyPrint(true);
|
||||||
|
String out = p.encodeResourceToString(bundle);
|
||||||
|
ourLog.info(out);
|
||||||
|
assertThat(out, not(containsString("total")));
|
||||||
|
assertThat(out, (containsString("Patient")));
|
||||||
|
assertThat(out, (containsString("name")));
|
||||||
|
assertThat(out, not(containsString("address")));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
||||||
|
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||||
|
p.setPrettyPrint(true);
|
||||||
|
String out = p.encodeResourceToString(bundle);
|
||||||
|
ourLog.info(out);
|
||||||
|
assertThat(out, (containsString("total")));
|
||||||
|
assertThat(out, (containsString("Patient")));
|
||||||
|
assertThat(out, (containsString("name")));
|
||||||
|
assertThat(out, not(containsString("address")));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
|
||||||
|
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
||||||
|
p.setPrettyPrint(true);
|
||||||
|
String out = p.encodeResourceToString(bundle);
|
||||||
|
ourLog.info(out);
|
||||||
|
assertThat(out, (containsString("total")));
|
||||||
|
assertThat(out, (containsString("Patient")));
|
||||||
|
assertThat(out, (containsString("name")));
|
||||||
|
assertThat(out, (containsString("address")));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMoreExtensions() throws Exception {
|
public void testMoreExtensions() throws Exception {
|
||||||
|
|
||||||
|
@ -1117,57 +1139,6 @@ public class XmlParserDstu2Test {
|
||||||
assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
|
assertThat(ourCtx.newXmlParser().setOmitResourceId(true).encodeResourceToString(p), not(containsString("123")));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testEncodeWithEncodeElements() throws Exception {
|
|
||||||
String content = IOUtils.toString(XmlParserDstu2Test.class.getResourceAsStream("/bundle-example.xml"));
|
|
||||||
|
|
||||||
Patient patient = new Patient();
|
|
||||||
patient.addName().addFamily("FAMILY");
|
|
||||||
patient.addAddress().addLine("LINE1");
|
|
||||||
|
|
||||||
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
|
||||||
bundle.setTotal(100);
|
|
||||||
bundle.addEntry().setResource(patient);
|
|
||||||
|
|
||||||
{
|
|
||||||
IParser p = ourCtx.newXmlParser();
|
|
||||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name", "Bundle.entry")));
|
|
||||||
p.setPrettyPrint(true);
|
|
||||||
String out = p.encodeResourceToString(bundle);
|
|
||||||
ourLog.info(out);
|
|
||||||
assertThat(out, not(containsString("total")));
|
|
||||||
assertThat(out, (containsString("Patient")));
|
|
||||||
assertThat(out, (containsString("name")));
|
|
||||||
assertThat(out, not(containsString("address")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
IParser p = ourCtx.newXmlParser();
|
|
||||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient.name")));
|
|
||||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
|
||||||
p.setPrettyPrint(true);
|
|
||||||
String out = p.encodeResourceToString(bundle);
|
|
||||||
ourLog.info(out);
|
|
||||||
assertThat(out, (containsString("total")));
|
|
||||||
assertThat(out, (containsString("Patient")));
|
|
||||||
assertThat(out, (containsString("name")));
|
|
||||||
assertThat(out, not(containsString("address")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
IParser p = ourCtx.newXmlParser();
|
|
||||||
p.setEncodeElements(new HashSet<String>(Arrays.asList("Patient")));
|
|
||||||
p.setEncodeElementsAppliesToResourceTypes(new HashSet<String>(Arrays.asList("Patient")));
|
|
||||||
p.setPrettyPrint(true);
|
|
||||||
String out = p.encodeResourceToString(bundle);
|
|
||||||
ourLog.info(out);
|
|
||||||
assertThat(out, (containsString("total")));
|
|
||||||
assertThat(out, (containsString("Patient")));
|
|
||||||
assertThat(out, (containsString("name")));
|
|
||||||
assertThat(out, (containsString("address")));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseAndEncodeBundle() throws Exception {
|
public void testParseAndEncodeBundle() throws Exception {
|
||||||
String content = IOUtils.toString(XmlParserDstu2Test.class.getResourceAsStream("/bundle-example.xml"));
|
String content = IOUtils.toString(XmlParserDstu2Test.class.getResourceAsStream("/bundle-example.xml"));
|
||||||
|
@ -1240,6 +1211,7 @@ public class XmlParserDstu2Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseAndEncodeExtensionOnResourceReference() {
|
public void testParseAndEncodeExtensionOnResourceReference() {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
@ -1642,6 +1614,22 @@ public class XmlParserDstu2Test {
|
||||||
assertEquals("Observation", link.getUrl());
|
assertEquals("Observation", link.getUrl());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testParseBundleWithResourceId() {
|
||||||
|
//@formatter:off
|
||||||
|
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">"
|
||||||
|
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"3\"/><lastUpdated value=\"2015-09-11T23:35:43.273-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
|
||||||
|
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"2\"/><lastUpdated value=\"2015-09-11T23:35:42.849-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
|
||||||
|
+ "<entry><fullUrl value=\"http://localhost:58402/fhir/context/Patient/1\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><id value=\"1\"/><meta><versionId value=\"1\"/><lastUpdated value=\"2015-09-11T23:35:42.295-04:00\"/></meta><name><family value=\"testHistoryWithDeletedResource\"/></name></Patient></resource></entry>"
|
||||||
|
+ "</Bundle>\n";
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, input);
|
||||||
|
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/3", bundle.getEntry().get(0).getResource().getId().getValue());
|
||||||
|
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/2", bundle.getEntry().get(1).getResource().getId().getValue());
|
||||||
|
assertEquals("http://localhost:58402/fhir/context/Patient/1/_history/1", bundle.getEntry().get(2).getResource().getId().getValue());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* see #144 and #146
|
* see #144 and #146
|
||||||
*/
|
*/
|
||||||
|
@ -1710,6 +1698,38 @@ public class XmlParserDstu2Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* See #216
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void testParseMalformedIdentifierDstu2() {
|
||||||
|
|
||||||
|
// This was changed from 0.5 to 1.0.0
|
||||||
|
|
||||||
|
//@formatter:off
|
||||||
|
String out = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
|
||||||
|
" <identifier>\n" +
|
||||||
|
" <type value=\"MRN\"/>\n" +
|
||||||
|
" <system value=\"SYS\"/>\n" +
|
||||||
|
" <value value=\"VAL\"/>\n" +
|
||||||
|
" </identifier>\n" +
|
||||||
|
"</Patient>";
|
||||||
|
//@formatter:on
|
||||||
|
|
||||||
|
IParserErrorHandler errorHandler = mock(IParserErrorHandler.class);
|
||||||
|
|
||||||
|
IParser p = ourCtx.newXmlParser();
|
||||||
|
p.setParserErrorHandler(errorHandler);
|
||||||
|
|
||||||
|
Patient patient = p.parseResource(Patient.class, out);
|
||||||
|
assertThat(patient.getIdentifier().get(0).getType().getValueAsEnum(), IsEmptyCollection.empty());
|
||||||
|
|
||||||
|
ArgumentCaptor<String> capt = ArgumentCaptor.forClass(String.class);
|
||||||
|
verify(errorHandler, times(1)).unknownAttribute(any(IParseLocation.class), capt.capture());
|
||||||
|
|
||||||
|
assertEquals("value", capt.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testParseMetadata() throws Exception {
|
public void testParseMetadata() throws Exception {
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package ca.uhn.fhir.validation;
|
package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.InputStreamReader;
|
import java.io.InputStreamReader;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
|
@ -20,67 +22,102 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
|
||||||
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;
|
||||||
@Override
|
|
||||||
public boolean isCodeSystemSupported(String theSystem) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@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, FhirInstanceValidator.getHl7OrgDstu2Ctx(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) {
|
|
||||||
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/valuesets.xml");
|
|
||||||
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>();
|
|
||||||
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
myDefaultValueSets = defaultValueSets;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (T) defaultValueSets.get(theUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeValidationResult validateCode(String theCodeSystem, String theCode, String theDisplay) {
|
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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, FhirInstanceValidator.getHl7OrgDstu2Ctx(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) {
|
||||||
|
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream("/org/hl7/fhir/instance/model/valueset/valuesets.xml");
|
||||||
|
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>();
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
|
||||||
|
myDefaultValueSets = defaultValueSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
return (T) defaultValueSets.get(theUri);
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||||
return new CodeValidationResult(IssueSeverity.INFORMATION, "Unknown code: " + theCodeSystem + " / " + theCode);
|
return new CodeValidationResult(IssueSeverity.INFORMATION, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet fetchCodeSystem(String theSystem) {
|
public ValueSet fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||||
return null;
|
Map<String, ValueSet> codeSystems = myCodeSystems;
|
||||||
|
if (codeSystems == null) {
|
||||||
|
codeSystems = new HashMap<String, ValueSet>();
|
||||||
|
|
||||||
|
loadCodeSystems(theContext, codeSystems, "/org/hl7/fhir/instance/model/valueset/valuesets.xml");
|
||||||
|
loadCodeSystems(theContext, codeSystems, "/org/hl7/fhir/instance/model/valueset/v2-tables.xml");
|
||||||
|
loadCodeSystems(theContext, codeSystems, "/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml");
|
||||||
|
|
||||||
|
myCodeSystems = codeSystems;
|
||||||
|
}
|
||||||
|
|
||||||
|
return codeSystems.get(theSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadCodeSystems(FhirContext theContext, Map<String, ValueSet> codeSystems, String file) {
|
||||||
|
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(file);
|
||||||
|
if (valuesetText != 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
FhirContext ctx = FhirInstanceValidator.getHl7OrgDstu2Ctx(theContext);
|
||||||
|
Bundle bundle = ctx.newXmlParser().parseResource(Bundle.class, reader);
|
||||||
|
for (BundleEntryComponent next : bundle.getEntry()) {
|
||||||
|
ValueSet nextValueSet = (ValueSet) next.getResource();
|
||||||
|
String system = nextValueSet.getCodeSystem().getSystem();
|
||||||
|
if (isNotBlank(system)) {
|
||||||
|
codeSystems.put(system, nextValueSet);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(ConceptSetComponent theInclude) {
|
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -269,7 +269,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandVS(ConceptSetComponent theInc) {
|
public ValueSetExpansionComponent expandVS(ConceptSetComponent theInc) {
|
||||||
return myValidationSupport.expandValueSet(theInc);
|
return myValidationSupport.expandValueSet(myCtx, theInc);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -282,7 +282,7 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
if (myValidationSupport == null) {
|
if (myValidationSupport == null) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return myValidationSupport.fetchCodeSystem(theSystem);
|
return myValidationSupport.fetchCodeSystem(myCtx, theSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -335,13 +335,13 @@ public class FhirInstanceValidator extends BaseValidatorBridge implements IValid
|
||||||
if (myValidationSupport == null) {
|
if (myValidationSupport == null) {
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
return myValidationSupport.isCodeSystemSupported(theSystem);
|
return myValidationSupport.isCodeSystemSupported(myCtx, theSystem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValidationResult validateCode(String theSystem, String theCode, String theDisplay) {
|
public ValidationResult validateCode(String theSystem, String theCode, String theDisplay) {
|
||||||
CodeValidationResult result = myValidationSupport.validateCode(theSystem, theCode, theDisplay);
|
CodeValidationResult result = myValidationSupport.validateCode(myCtx, theSystem, theCode, theDisplay);
|
||||||
if (result == null) {
|
if (result == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,7 +18,7 @@ public interface IValidationSupport {
|
||||||
* The portion to include
|
* The portion to include
|
||||||
* @return The expansion
|
* @return The expansion
|
||||||
*/
|
*/
|
||||||
ValueSetExpansionComponent expandValueSet(ConceptSetComponent theInclude);
|
ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch a code system by ID
|
* Fetch a code system by ID
|
||||||
|
@ -27,7 +27,7 @@ public interface IValidationSupport {
|
||||||
* The code system
|
* The code system
|
||||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||||
*/
|
*/
|
||||||
ValueSet fetchCodeSystem(String theSystem);
|
ValueSet fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||||
|
@ -53,7 +53,7 @@ public interface IValidationSupport {
|
||||||
* @return Returns <code>true</code> if codes in the given code system can be
|
* @return Returns <code>true</code> if codes in the given code system can be
|
||||||
* validated
|
* validated
|
||||||
*/
|
*/
|
||||||
boolean isCodeSystemSupported(String theSystem);
|
boolean isCodeSystemSupported(FhirContext theContext, String theSystem);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Validates that the given code exists and if possible returns a display
|
* Validates that the given code exists and if possible returns a display
|
||||||
|
@ -68,7 +68,7 @@ public interface IValidationSupport {
|
||||||
* The display name, if it should also be validated
|
* The display name, if it should also be validated
|
||||||
* @return Returns a validation result object
|
* @return Returns a validation result object
|
||||||
*/
|
*/
|
||||||
CodeValidationResult validateCode(String theCodeSystem, String theCode, String theDisplay);
|
CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
|
||||||
|
|
||||||
public class CodeValidationResult {
|
public class CodeValidationResult {
|
||||||
private ConceptDefinitionComponent definition;
|
private ConceptDefinitionComponent definition;
|
||||||
|
|
|
@ -24,19 +24,19 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent expandValueSet(ConceptSetComponent theInclude) {
|
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
if (next.isCodeSystemSupported(theInclude.getSystem())) {
|
if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) {
|
||||||
return next.expandValueSet(theInclude);
|
return next.expandValueSet(theCtx, theInclude);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return myChain.get(0).expandValueSet(theInclude);
|
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ValueSet fetchCodeSystem(String theSystem) {
|
public ValueSet fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
ValueSet retVal = next.fetchCodeSystem(theSystem);
|
ValueSet retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||||
if (retVal != null) {
|
if (retVal != null) {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
@ -56,9 +56,9 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isCodeSystemSupported(String theSystem) {
|
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
if (next.isCodeSystemSupported(theSystem)) {
|
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,13 +66,13 @@ public class ValidationSupportChain implements IValidationSupport {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CodeValidationResult validateCode(String theCodeSystem, String theCode, String theDisplay) {
|
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||||
for (IValidationSupport next : myChain) {
|
for (IValidationSupport next : myChain) {
|
||||||
if (next.isCodeSystemSupported(theCodeSystem)) {
|
if (next.isCodeSystemSupported(theCtx, theCodeSystem)) {
|
||||||
return next.validateCode(theCodeSystem, theCode, theDisplay);
|
return next.validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return myChain.get(0).validateCode(theCodeSystem, theCode, theDisplay);
|
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,9 @@ package ca.uhn.fhir.validation;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.greaterThan;
|
import static org.hamcrest.Matchers.greaterThan;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.fail;
|
||||||
import static org.mockito.Matchers.any;
|
import static org.mockito.Matchers.any;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
@ -16,6 +18,7 @@ import org.apache.commons.io.IOUtils;
|
||||||
import org.hl7.fhir.instance.model.CodeType;
|
import org.hl7.fhir.instance.model.CodeType;
|
||||||
import org.hl7.fhir.instance.model.Observation;
|
import org.hl7.fhir.instance.model.Observation;
|
||||||
import org.hl7.fhir.instance.model.Observation.ObservationStatus;
|
import org.hl7.fhir.instance.model.Observation.ObservationStatus;
|
||||||
|
import org.hl7.fhir.instance.model.Patient;
|
||||||
import org.hl7.fhir.instance.model.StringType;
|
import org.hl7.fhir.instance.model.StringType;
|
||||||
import org.hl7.fhir.instance.model.ValueSet;
|
import org.hl7.fhir.instance.model.ValueSet;
|
||||||
import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent;
|
import org.hl7.fhir.instance.model.ValueSet.ConceptDefinitionComponent;
|
||||||
|
@ -61,19 +64,19 @@ public class FhirInstanceValidatorTest {
|
||||||
myValidConcepts = new ArrayList<String>();
|
myValidConcepts = new ArrayList<String>();
|
||||||
|
|
||||||
myMockSupport = mock(IValidationSupport.class);
|
myMockSupport = mock(IValidationSupport.class);
|
||||||
when(myMockSupport.expandValueSet(any(ConceptSetComponent.class))).thenAnswer(new Answer<ValueSetExpansionComponent>() {
|
when(myMockSupport.expandValueSet(any(FhirContext.class), any(ConceptSetComponent.class))).thenAnswer(new Answer<ValueSetExpansionComponent>() {
|
||||||
@Override
|
@Override
|
||||||
public ValueSetExpansionComponent answer(InvocationOnMock theInvocation) throws Throwable {
|
public ValueSetExpansionComponent answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
ConceptSetComponent arg = (ConceptSetComponent)theInvocation.getArguments()[0];
|
ConceptSetComponent arg = (ConceptSetComponent)theInvocation.getArguments()[0];
|
||||||
ValueSetExpansionComponent retVal = mySupportedCodeSystemsForExpansion.get(arg.getSystem());
|
ValueSetExpansionComponent retVal = mySupportedCodeSystemsForExpansion.get(arg.getSystem());
|
||||||
if (retVal == null) {
|
if (retVal == null) {
|
||||||
retVal = myDefaultValidationSupport.expandValueSet(arg);
|
retVal = myDefaultValidationSupport.expandValueSet(any(FhirContext.class), arg);
|
||||||
}
|
}
|
||||||
ourLog.info("expandValueSet({}) : {}", new Object[] { theInvocation.getArguments()[0], retVal });
|
ourLog.info("expandValueSet({}) : {}", new Object[] { theInvocation.getArguments()[0], retVal });
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
when(myMockSupport.isCodeSystemSupported(any(String.class))).thenAnswer(new Answer<Boolean>() {
|
when(myMockSupport.isCodeSystemSupported(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean answer(InvocationOnMock theInvocation) throws Throwable {
|
public Boolean answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
boolean retVal = mySupportedCodeSystemsForExpansion.containsKey(theInvocation.getArguments()[0]);
|
boolean retVal = mySupportedCodeSystemsForExpansion.containsKey(theInvocation.getArguments()[0]);
|
||||||
|
@ -93,28 +96,29 @@ public class FhirInstanceValidatorTest {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
when(myMockSupport.validateCode(any(String.class), any(String.class), any(String.class)))
|
when(myMockSupport.validateCode(any(FhirContext.class), any(String.class), any(String.class), any(String.class)))
|
||||||
.thenAnswer(new Answer<CodeValidationResult>() {
|
.thenAnswer(new Answer<CodeValidationResult>() {
|
||||||
@Override
|
@Override
|
||||||
public CodeValidationResult answer(InvocationOnMock theInvocation) throws Throwable {
|
public CodeValidationResult answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
String system = (String) theInvocation.getArguments()[0];
|
FhirContext ctx = (FhirContext) theInvocation.getArguments()[0];
|
||||||
String code = (String) theInvocation.getArguments()[1];
|
String system = (String) theInvocation.getArguments()[1];
|
||||||
|
String code = (String) theInvocation.getArguments()[2];
|
||||||
CodeValidationResult retVal;
|
CodeValidationResult retVal;
|
||||||
if (myValidConcepts.contains(system + "___" + code)) {
|
if (myValidConcepts.contains(system + "___" + code)) {
|
||||||
retVal = new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(code)));
|
retVal = new CodeValidationResult(new ConceptDefinitionComponent(new CodeType(code)));
|
||||||
} else {
|
} else {
|
||||||
retVal = myDefaultValidationSupport.validateCode(system, code, (String) theInvocation.getArguments()[2]);
|
retVal = myDefaultValidationSupport.validateCode(ctx, system, code, (String) theInvocation.getArguments()[2]);
|
||||||
}
|
}
|
||||||
ourLog.info("validateCode({}, {}, {}) : {}",
|
ourLog.info("validateCode({}, {}, {}) : {}",
|
||||||
new Object[] { system, code, (String) theInvocation.getArguments()[2], retVal });
|
new Object[] { system, code, (String) theInvocation.getArguments()[2], retVal });
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
when(myMockSupport.fetchCodeSystem(any(String.class))).thenAnswer(new Answer<ValueSet>() {
|
when(myMockSupport.fetchCodeSystem(any(FhirContext.class), any(String.class))).thenAnswer(new Answer<ValueSet>() {
|
||||||
@Override
|
@Override
|
||||||
public ValueSet answer(InvocationOnMock theInvocation) throws Throwable {
|
public ValueSet answer(InvocationOnMock theInvocation) throws Throwable {
|
||||||
ValueSet retVal = myDefaultValidationSupport.fetchCodeSystem((String) theInvocation.getArguments()[0]);
|
ValueSet retVal = myDefaultValidationSupport.fetchCodeSystem((FhirContext) theInvocation.getArguments()[0],(String) theInvocation.getArguments()[1]);
|
||||||
ourLog.info("fetchCodeSystem({}) : {}", new Object[] { (String) theInvocation.getArguments()[0], retVal });
|
ourLog.info("fetchCodeSystem({}) : {}", new Object[] { (String) theInvocation.getArguments()[1], retVal });
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -306,6 +310,29 @@ public class FhirInstanceValidatorTest {
|
||||||
output.getMessages().get(0).getMessage());
|
output.getMessages().get(0).getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateResourceWithValuesetExpansion() {
|
||||||
|
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setSystem("http://system").setValue("12345").getType().addCoding().setSystem("foo").setCode("bar");
|
||||||
|
|
||||||
|
ValidationResult output = myVal.validateWithResult(patient);
|
||||||
|
List<SingleValidationMessage> all = logResultsAndReturnAll(output);
|
||||||
|
assertEquals(1, all.size());
|
||||||
|
assertEquals("/f:Patient/f:identifier/f:type", all.get(0).getLocationString());
|
||||||
|
assertEquals("None of the codes are in the expected value set http://hl7.org/fhir/ValueSet/identifier-type (http://hl7.org/fhir/ValueSet/identifier-type)", all.get(0).getMessage());
|
||||||
|
assertEquals(ResultSeverityEnum.WARNING, all.get(0).getSeverity());
|
||||||
|
|
||||||
|
patient = new Patient();
|
||||||
|
patient.addIdentifier().setSystem("http://system").setValue("12345").getType().addCoding().setSystem("http://hl7.org/fhir/v2/0203").setCode("MR");
|
||||||
|
|
||||||
|
output = myVal.validateWithResult(patient);
|
||||||
|
all = logResultsAndReturnAll(output);
|
||||||
|
assertEquals(0, all.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateResourceWithExampleBindingCodeValidationFailing() {
|
public void testValidateResourceWithExampleBindingCodeValidationFailing() {
|
||||||
Observation input = new Observation();
|
Observation input = new Observation();
|
||||||
|
@ -353,7 +380,11 @@ public class FhirInstanceValidatorTest {
|
||||||
|
|
||||||
ValidationResult output = myVal.validateWithResult(input);
|
ValidationResult output = myVal.validateWithResult(input);
|
||||||
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
List<SingleValidationMessage> errors = logResultsAndReturnNonInformationalOnes(output);
|
||||||
assertEquals(errors.toString(), 0, errors.size());
|
assertEquals(errors.toString(), 1, errors.size());
|
||||||
|
assertEquals("Unable to validate code \"1234\" in code system \"http://loinc.org\"", errors.get(0).getMessage());
|
||||||
|
assertEquals(ResultSeverityEnum.WARNING, errors.get(0).getSeverity());
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -84,6 +84,17 @@
|
||||||
a more appropriate 400/404 in the JPA server (vread on invalid version,
|
a more appropriate 400/404 in the JPA server (vread on invalid version,
|
||||||
delete with no ID, etc.)
|
delete with no ID, etc.)
|
||||||
</action>
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
Fix narrative generation for DSTU2 Medication resource
|
||||||
|
</action>
|
||||||
|
<action type="fix">
|
||||||
|
Profile validator now works for valuesets which use
|
||||||
|
v2 tables
|
||||||
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
JPA server Patient/[id]/$everything operation now supports
|
||||||
|
_lastUpdated filtering and _sort'ing of results.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="1.2" date="2015-09-18">
|
<release version="1.2" date="2015-09-18">
|
||||||
<action type="add">
|
<action type="add">
|
||||||
|
|
Loading…
Reference in New Issue