This commit is contained in:
Kai Liu 2018-03-28 17:38:09 -04:00
commit ae010a4309
81 changed files with 20970 additions and 424 deletions

View File

@ -224,13 +224,17 @@
</pluginManagement>
<plugins>
<!-- Tell Maven which Java source version you want to use -->
<!--
The CQF-Ruler project has some OWASP dependency security failures which we don't want
to cause the whole build to fail. TODO: investigate these
-->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
<failBuildOnCVSS>99</failBuildOnCVSS>
<failOnError>false</failOnError>
</configuration>
</plugin>

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-base</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<url>http://jamesagnew.github.io/hapi-fhir/</url>
@ -150,6 +150,21 @@
</executions>
</plugin>
-->
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
<!--required when using servers-->
ca.uhn.fhir.rest.api.server;resolution:=optional,
ca.uhn.fhir.model.api;resolution:=optional,
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
<resources>
<resource>

View File

@ -20,9 +20,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

View File

@ -9,7 +9,7 @@
</parent>
<artifactId>hapi-fhir-client</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR - Client Framework</name>
@ -69,6 +69,18 @@
<argLine>@{argLine} -Dfile.encoding=UTF-8 -Xmx712m</argLine>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-converter</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<dependencies>
<dependency>
@ -134,5 +134,21 @@
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Import-Package>
ca.uhn.fhir.rest.server*;resolution:=optional,
javax.servlet.http;resolution:=optional,
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -60,6 +60,9 @@ public class DaoConfig {
* update setter javadoc if default changes
*/
private boolean myAllowExternalReferences = false;
/**
* update setter javadoc if default changes
*/
private boolean myAllowContainsSearches = true;
/**
@ -137,6 +140,7 @@ public class DaoConfig {
myTreatReferencesAsLogical.add(theTreatReferencesAsLogical);
}
/**
* Specifies the highest number that a client is permitted to use in a
* <code>Cache-Control: nostore, max-results=NNN</code>
@ -376,9 +380,9 @@ public class DaoConfig {
* of higher importance than raw write performance
* </p>
* <p>
* Note that this setting also has an impact on sorting (i.e. using the
* <code>_sort</code> parameter on searches): If the server is configured
* to not index missing field.
* Note that this setting also has an impact on sorting (i.e. using the
* <code>_sort</code> parameter on searches): If the server is configured
* to not index missing field.
* </p>
*/
public void setIndexMissingFields(IndexEnabledEnum theIndexMissingFields) {
@ -650,6 +654,26 @@ public class DaoConfig {
return this;
}
/**
* If enabled, the server will support the use of :contains searches,
* which are helpful but can have adverse effects on performance.
*
* Default is <code>true</code>
*/
public boolean isAllowContainsSearches() {
return myAllowContainsSearches;
}
/**
* If enabled, the server will support the use of :contains searches,
* which are helpful but can have adverse effects on performance.
*
* Default is <code>true</code>
*/
public void setAllowContainsSearches(boolean theAllowContainsSearches) {
this.myAllowContainsSearches = theAllowContainsSearches;
}
/**
* If set to <code>true</code> (default is <code>false</code>) the server will allow
* resources to have references to external servers. For example if this server is
@ -1099,16 +1123,6 @@ public class DaoConfig {
}
public boolean allowContainsSearches() {
return myAllowContainsSearches;
}
public void setAllowContainsSearches(boolean myAllowContainsSearches) {
this.myAllowContainsSearches = myAllowContainsSearches;
}
public enum IndexEnabledEnum {
ENABLED,
DISABLED

View File

@ -20,29 +20,32 @@ package ca.uhn.fhir.jpa.dao;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.param.DateRangeParam;
import org.hl7.fhir.instance.model.api.IBaseResource;
import javax.persistence.EntityManager;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import javax.persistence.EntityManager;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.rest.param.DateRangeParam;
public interface ISearchBuilder {
Iterator<Long> createQuery(SearchParameterMap theParams, String theSearchUuid);
void setType(Class<? extends IBaseResource> theResourceType, String theResourceName);
void loadResourcesByPid(Collection<Long> theIncludePids, List<IBaseResource> theResourceListToPopulate, Set<Long> theRevIncludedPids, boolean theForHistoryOperation, EntityManager theEntityManager,
FhirContext theContext, IDao theDao);
FhirContext theContext, IDao theDao);
Set<Long> loadReverseIncludes(IDao theCallingDao, FhirContext theContext, EntityManager theEntityManager, Collection<Long> theMatches, Set<Include> theRevIncludes, boolean theReverseMode,
DateRangeParam theLastUpdated);
DateRangeParam theLastUpdated);
/**
* How many results may be fetched at once
*/
void setFetchSize(int theFetchSize);
void setType(Class<? extends IBaseResource> theResourceType, String theResourceName);
}

View File

@ -28,8 +28,6 @@ import ca.uhn.fhir.jpa.search.JpaRuntimeSearchParam;
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
import ca.uhn.fhir.jpa.term.VersionIndependentConcept;
import ca.uhn.fhir.jpa.util.BaseIterator;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.model.api.*;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseIdentifierDt;
@ -45,7 +43,9 @@ import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.util.StopWatch;
import ca.uhn.fhir.util.UrlUtil;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
@ -59,6 +59,9 @@ import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.tuple.Pair;
import org.hibernate.ScrollMode;
import org.hibernate.ScrollableResults;
import org.hibernate.engine.spi.EntityKey;
import org.hibernate.engine.spi.PersistenceContext;
import org.hibernate.internal.SessionImpl;
import org.hibernate.query.Query;
import org.hl7.fhir.dstu3.model.BaseResource;
import org.hl7.fhir.instance.model.api.IAnyResource;
@ -104,6 +107,7 @@ public class SearchBuilder implements ISearchBuilder {
private ISearchParamRegistry mySearchParamRegistry;
private String mySearchUuid;
private IHapiTerminologySvc myTerminologySvc;
private int myFetchSize;
/**
* Constructor
@ -1091,10 +1095,10 @@ public class SearchBuilder implements ISearchBuilder {
} else if (theParameter instanceof StringParam) {
StringParam id = (StringParam) theParameter;
rawSearchTerm = id.getValue();
if ((id.isContains()) &&
(!myCallingDao.getConfig().allowContainsSearches()))
{
throw new MethodNotAllowedException(":contains modifier is disabled on this server");
if (id.isContains()) {
if (!myCallingDao.getConfig().isAllowContainsSearches()) {
throw new MethodNotAllowedException(":contains modifier is disabled on this server");
}
}
} else if (theParameter instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> id = (IPrimitiveDatatype<?>) theParameter;
@ -1109,18 +1113,11 @@ public class SearchBuilder implements ISearchBuilder {
}
String likeExpression = BaseHapiFhirDao.normalizeString(rawSearchTerm);
if (myCallingDao.getConfig().allowContainsSearches()) {
if (theParameter instanceof StringParam) {
if (((StringParam) theParameter).isContains()) {
likeExpression = createLeftAndRightMatchLikeExpression(likeExpression);
} else {
likeExpression = createLeftMatchLikeExpression(likeExpression);
}
} else {
likeExpression = createLeftMatchLikeExpression(likeExpression);
}
}
else {
if (theParameter instanceof StringParam &&
((StringParam) theParameter).isContains() &&
myCallingDao.getConfig().isAllowContainsSearches()) {
likeExpression = createLeftAndRightMatchLikeExpression(likeExpression);
} else {
likeExpression = createLeftMatchLikeExpression(likeExpression);
}
@ -1933,6 +1930,11 @@ public class SearchBuilder implements ISearchBuilder {
}
}
@Override
public void setFetchSize(int theFetchSize) {
myFetchSize = theFetchSize;
}
@Override
public void setType(Class<? extends IBaseResource> theResourceType, String theResourceName) {
myResourceType = theResourceType;
@ -2020,14 +2022,14 @@ public class SearchBuilder implements ISearchBuilder {
return lastUpdatedPredicates;
}
private static String createLeftMatchLikeExpression(String likeExpression) {
return likeExpression.replace("%", "[%]") + "%";
}
private static String createLeftAndRightMatchLikeExpression(String likeExpression) {
return "%" + likeExpression.replace("%", "[%]") + "%";
}
private static String createLeftMatchLikeExpression(String likeExpression) {
return likeExpression.replace("%", "[%]") + "%";
}
private static Predicate createResourceLinkPathPredicate(IDao theCallingDao, FhirContext theContext, String theParamName, From<?, ? extends ResourceLink> theFrom,
String theResourceType) {
RuntimeResourceDefinition resourceDef = theContext.getResourceDefinition(theResourceType);
@ -2188,6 +2190,7 @@ public class SearchBuilder implements ISearchBuilder {
final TypedQuery<Long> query = createQuery(mySort, maximumResults);
Query<Long> hibernateQuery = (Query<Long>) query;
hibernateQuery.setFetchSize(myFetchSize);
ScrollableResults scroll = hibernateQuery.scroll(ScrollMode.FORWARD_ONLY);
myResultsIterator = new ScrollableResultsIterator(scroll);

View File

@ -206,6 +206,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
Class<? extends IBaseResource> resourceTypeClass = myContext.getResourceDefinition(theResourceType).getImplementingClass();
final ISearchBuilder sb = theCallingDao.newSearchBuilder();
sb.setType(resourceTypeClass, theResourceType);
sb.setFetchSize(mySyncSize);
final Integer loadSynchronousUpTo;
if (theCacheControlDirective != null && theCacheControlDirective.isNoStore()) {
@ -233,7 +234,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
public SimpleBundleProvider doInTransaction(TransactionStatus theStatus) {
// Load the results synchronously
final List<Long> pids = new ArrayList<Long>();
final List<Long> pids = new ArrayList<>();
Iterator<Long> resultIter = sb.createQuery(theParams, searchUuid);
while (resultIter.hasNext()) {
@ -458,8 +459,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
private final SearchParameterMap myParams;
private final String myResourceType;
private final Search mySearch;
private final ArrayList<Long> mySyncedPids = new ArrayList<Long>();
private final ArrayList<Long> myUnsyncedPids = new ArrayList<Long>();
private final ArrayList<Long> mySyncedPids = new ArrayList<>();
private final ArrayList<Long> myUnsyncedPids = new ArrayList<>();
private boolean myAbortRequested;
private int myCountSaved = 0;
private String mySearchUuid;
@ -503,7 +504,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
* It is called automatically by the thread pool.
*/
@Override
public Void call() throws Exception {
public Void call() {
StopWatch sw = new StopWatch();
try {
@ -631,10 +632,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc {
boolean keepWaiting;
do {
synchronized (mySyncedPids) {
keepWaiting = false;
if (mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING) {
keepWaiting = true;
}
keepWaiting = mySyncedPids.size() < theToIndex && mySearch.getStatus() == SearchStatusEnum.LOADING;
}
if (keepWaiting) {
ourLog.info("Waiting, as we only have {} results", mySyncedPids.size());

View File

@ -11,6 +11,7 @@ import ca.uhn.fhir.rest.api.Constants;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
import ca.uhn.fhir.util.TestUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
@ -54,6 +55,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
public void afterResetSearchSize() {
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
}
@Before
@ -1404,43 +1406,6 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
}
}
/**
* See #819
*/
@Test
public void testSearchTokenWithNotModifier() {
String male, female;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().setFamily("Tester").addGiven("Joe");
patient.setGender(AdministrativeGender.MALE);
male = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester").addGiven("Jane");
patient.setGender(AdministrativeGender.FEMALE);
female = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
}
List<String> patients;
SearchParameterMap params;
params = new SearchParameterMap();
params.add(Patient.SP_GENDER, new TokenParam(null, "male"));
params.setLoadSynchronous(true);
patients = toUnqualifiedVersionlessIdValues(myPatientDao.search(params));
assertThat(patients, contains(male));
params = new SearchParameterMap();
params.add(Patient.SP_GENDER, new TokenParam(null, "male").setModifier(TokenParamModifier.NOT));
params.setLoadSynchronous(true);
patients = toUnqualifiedVersionlessIdValues(myPatientDao.search(params));
assertThat(patients, contains(female));
}
@Test
public void testSearchNumberParam() {
ImmunizationRecommendation e1 = new ImmunizationRecommendation();
@ -2122,6 +2087,43 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
}
}
/**
* See #819
*/
@Test
public void testSearchTokenWithNotModifier() {
String male, female;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().setFamily("Tester").addGiven("Joe");
patient.setGender(AdministrativeGender.MALE);
male = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
}
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().setFamily("Tester").addGiven("Jane");
patient.setGender(AdministrativeGender.FEMALE);
female = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless().getValue();
}
List<String> patients;
SearchParameterMap params;
params = new SearchParameterMap();
params.add(Patient.SP_GENDER, new TokenParam(null, "male"));
params.setLoadSynchronous(true);
patients = toUnqualifiedVersionlessIdValues(myPatientDao.search(params));
assertThat(patients, contains(male));
params = new SearchParameterMap();
params.add(Patient.SP_GENDER, new TokenParam(null, "male").setModifier(TokenParamModifier.NOT));
params.setLoadSynchronous(true);
patients = toUnqualifiedVersionlessIdValues(myPatientDao.search(params));
assertThat(patients, contains(female));
}
@Test
public void testSearchTokenWrongParam() {
Patient p1 = new Patient();
@ -2257,6 +2259,67 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
}
@Test
public void testSearchWithContains() {
Patient pt1 = new Patient();
pt1.addName().setFamily("ABCDEFGHIJK");
String pt1id = myPatientDao.create(pt1).getId().toUnqualifiedVersionless().getValue();
Patient pt2 = new Patient();
pt2.addName().setFamily("FGHIJK");
String pt2id = myPatientDao.create(pt2).getId().toUnqualifiedVersionless().getValue();
Patient pt3 = new Patient();
pt3.addName().setFamily("ZZZZZ");
myPatientDao.create(pt3).getId().toUnqualifiedVersionless().getValue();
List<String> ids;
SearchParameterMap map;
IBundleProvider results;
// Contains = true
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(true));
map.setLoadSynchronous(true);
results = myPatientDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, containsInAnyOrder(pt1id, pt2id));
// Contains = false
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(false));
map.setLoadSynchronous(true);
results = myPatientDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, containsInAnyOrder(pt2id));
// No contains
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("FGHIJK"));
map.setLoadSynchronous(true);
results = myPatientDao.search(map);
ids = toUnqualifiedVersionlessIdValues(results);
assertThat(ids, containsInAnyOrder(pt2id));
}
@Test
public void testSearchWithContainsDisabled() {
myDaoConfig.setAllowContainsSearches(false);
SearchParameterMap map = new SearchParameterMap();
map.setLoadSynchronous(true);
map.add(Patient.SP_NAME, new StringParam("FGHIJK").setContains(true));
try {
myPatientDao.search(map);
fail();
} catch (MethodNotAllowedException e) {
assertEquals(":contains modifier is disabled on this server", e.getMessage());
}
}
@Test
public void testSearchWithDate() {
IIdType orgId = myOrganizationDao.create(new Organization(), mySrd).getId();

View File

@ -68,6 +68,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu2");
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
retVal.setFetchSizeDefaultMaximum(10000);
return retVal;
}

View File

@ -57,6 +57,7 @@ public class TestDstu3Config extends BaseJavaConfigDstu3 {
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseDstu3");
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
retVal.setFetchSizeDefaultMaximum(10000);
return retVal;
}

View File

@ -58,6 +58,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
retVal.getTreatBaseUrlsAsLocal().add("https://fhirtest.uhn.ca/baseR4");
retVal.setIndexMissingFields(DaoConfig.IndexEnabledEnum.ENABLED);
retVal.setCountSearchResultsUpTo(TestR4Config.COUNT_SEARCH_RESULTS_UP_TO);
retVal.setFetchSizeDefaultMaximum(10000);
return retVal;
}

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR Structures - DSTU2.1 (2016May)</name>
@ -273,6 +273,22 @@
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
<Import-Package>
javax.servlet*;resolution:=optional,
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -2,6 +2,7 @@ package org.hl7.fhir.dstu2016may.hapi.validation;
import ca.uhn.fhir.context.FhirContext;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.dstu2016may.model.*;
import org.hl7.fhir.dstu2016may.model.Bundle.BundleEntryComponent;
@ -68,8 +69,8 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
Map<String, CodeSystem> codeSystems = myCodeSystems;
Map<String, ValueSet> valueSets = myValueSets;
if (codeSystems == null) {
codeSystems = new HashMap<String, CodeSystem>();
valueSets = new HashMap<String, ValueSet>();
codeSystems = new HashMap<>();
valueSets = new HashMap<>();
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu2016may/model/valueset/valuesets.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu2016may/model/valueset/v2-tables.xml");
@ -155,27 +156,33 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
private void loadCodeSystems(FhirContext theContext, Map<String, CodeSystem> theCodeSystems, Map<String, ValueSet> theValueSets, String theClasspath) {
ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath);
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
if (valuesetText != null) {
InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8);
InputStream inputStream = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
InputStreamReader reader = null;
if (inputStream != null) {
try {
reader = new InputStreamReader(inputStream, Charsets.UTF_8);
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof CodeSystem) {
CodeSystem nextValueSet = (CodeSystem) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextValueSet);
}
} else if (next.getResource() instanceof ValueSet) {
ValueSet nextValueSet = (ValueSet) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theValueSets.put(system, nextValueSet);
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof CodeSystem) {
CodeSystem nextValueSet = (CodeSystem) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextValueSet);
}
} else if (next.getResource() instanceof ValueSet) {
ValueSet nextValueSet = (ValueSet) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theValueSets.put(system, nextValueSet);
}
}
}
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(inputStream);
}
} else {
ourLog.warn("Unable to load resource: {}", theClasspath);

View File

@ -9,7 +9,7 @@
</parent>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)</name>
@ -361,6 +361,22 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
<Import-Package>
javax.servlet*;resolution:=optional,
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
<pluginManagement>
<plugins>

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR Structures - DSTU3</name>
@ -28,6 +28,18 @@
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>jacoco-maven-plugin</artifactId>
@ -272,5 +284,4 @@
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR Structures - HL7.org DSTU2</name>
@ -272,6 +272,22 @@
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
<Import-Package>
javax.servlet*;resolution:=optional,
*
</Import-Package>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -1,5 +1,5 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-structures-r4</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR Structures - FHIR R4</name>
@ -29,16 +29,16 @@
<!--
Optional dependencies from RI codebase
-->
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>es.nitaur.markdown</groupId>
<artifactId>txtmark</artifactId>
<optional>true</optional>
</dependency>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>ST4</artifactId>
@ -49,7 +49,7 @@
<artifactId>xpp3</artifactId>
<optional>true</optional>
</dependency>
<!--
Test dependencies on other optional parts of HAPI
-->
@ -262,6 +262,18 @@
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -2,6 +2,7 @@ package org.hl7.fhir.r4.hapi.ctx;
import ca.uhn.fhir.context.FhirContext;
import org.apache.commons.io.Charsets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBaseResource;
@ -141,27 +142,33 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
private void loadCodeSystems(FhirContext theContext, Map<String, CodeSystem> theCodeSystems, Map<String, ValueSet> theValueSets, String theClasspath) {
ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath);
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
if (valuesetText != null) {
InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8);
InputStream inputStream = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
InputStreamReader reader = null;
if (inputStream != null) {
try {
reader = new InputStreamReader(inputStream, Charsets.UTF_8);
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof CodeSystem) {
CodeSystem nextValueSet = (CodeSystem) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextValueSet);
}
} else if (next.getResource() instanceof ValueSet) {
ValueSet nextValueSet = (ValueSet) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theValueSets.put(system, nextValueSet);
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof CodeSystem) {
CodeSystem nextValueSet = (CodeSystem) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextValueSet);
}
} else if (next.getResource() instanceof ValueSet) {
ValueSet nextValueSet = (ValueSet) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theValueSets.put(system, nextValueSet);
}
}
}
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(inputStream);
}
} else {
ourLog.warn("Unable to load resource: {}", theClasspath);

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-utilities</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR - Utilities</name>
@ -122,6 +122,11 @@
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
</plugin>
</plugins>
</build>

View File

@ -9,7 +9,7 @@
</parent>
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR - Validation Resources DSTU2.1 (2016May)</name>
@ -20,6 +20,20 @@
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -9,7 +9,7 @@
</parent>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR - Validation Resources (DSTU2)</name>
@ -20,6 +20,20 @@
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -9,7 +9,7 @@
</parent>
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR - Validation Resources (DSTU3)</name>
@ -34,6 +34,20 @@
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -9,7 +9,7 @@
</parent>
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR - Validation Resources (FHIR R4)</name>
@ -34,6 +34,20 @@
<filtering>false</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -10,7 +10,7 @@
</parent>
<artifactId>hapi-fhir-validation</artifactId>
<packaging>jar</packaging>
<packaging>bundle</packaging>
<name>HAPI FHIR - Validation</name>
@ -246,6 +246,18 @@
<fork>true</fork>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Fragment-Host>
ca.uhn.hapi.fhir.hapi-fhir-base
</Fragment-Host>
</instructions>
</configuration>
</plugin>
</plugins>
</build>

View File

@ -2,7 +2,7 @@ package org.hl7.fhir.dstu3.hapi.validation;
import ca.uhn.fhir.context.FhirContext;
import org.apache.commons.io.Charsets;
import org.apache.commons.lang.WordUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
@ -24,243 +24,249 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class DefaultProfileValidationSupport implements IValidationSupport {
private static final String URL_PREFIX_VALUE_SET = "http://hl7.org/fhir/ValueSet/";
private static final String URL_PREFIX_STRUCTURE_DEFINITION = "http://hl7.org/fhir/StructureDefinition/";
private static final String URL_PREFIX_STRUCTURE_DEFINITION_BASE = "http://hl7.org/fhir/";
private static final String URL_PREFIX_VALUE_SET = "http://hl7.org/fhir/ValueSet/";
private static final String URL_PREFIX_STRUCTURE_DEFINITION = "http://hl7.org/fhir/StructureDefinition/";
private static final String URL_PREFIX_STRUCTURE_DEFINITION_BASE = "http://hl7.org/fhir/";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultProfileValidationSupport.class);
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultProfileValidationSupport.class);
private Map<String, CodeSystem> myCodeSystems;
private Map<String, StructureDefinition> myStructureDefinitions;
private Map<String, ValueSet> myValueSets;
private Map<String, CodeSystem> myCodeSystems;
private Map<String, StructureDefinition> myStructureDefinitions;
private Map<String, ValueSet> myValueSets;
@Override
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
@Override
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
ValueSetExpansionComponent retVal = new ValueSetExpansionComponent();
Set<String> wantCodes = new HashSet<String>();
for (ConceptReferenceComponent next : theInclude.getConcept()) {
wantCodes.add(next.getCode());
}
Set<String> wantCodes = new HashSet<>();
for (ConceptReferenceComponent next : theInclude.getConcept()) {
wantCodes.add(next.getCode());
}
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
for (ConceptDefinitionComponent next : system.getConcept()) {
if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) {
retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
}
}
CodeSystem system = fetchCodeSystem(theContext, theInclude.getSystem());
for (ConceptDefinitionComponent next : system.getConcept()) {
if (wantCodes.isEmpty() || wantCodes.contains(next.getCode())) {
retVal.addContains().setSystem(theInclude.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
}
}
return retVal;
}
return retVal;
}
@Override
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
ArrayList<IBaseResource> retVal = new ArrayList<>();
retVal.addAll(myCodeSystems.values());
retVal.addAll(myStructureDefinitions.values());
retVal.addAll(myValueSets.values());
return retVal;
}
@Override
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
ArrayList<IBaseResource> retVal = new ArrayList<>();
retVal.addAll(myCodeSystems.values());
retVal.addAll(myStructureDefinitions.values());
retVal.addAll(myValueSets.values());
return retVal;
}
@Override
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
return new ArrayList<StructureDefinition>(provideStructureDefinitionMap(theContext).values());
}
@Override
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
return new ArrayList<StructureDefinition>(provideStructureDefinitionMap(theContext).values());
}
@Override
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
return (CodeSystem) fetchCodeSystemOrValueSet(theContext, theSystem, true);
}
@Override
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
return (CodeSystem) fetchCodeSystemOrValueSet(theContext, theSystem, true);
}
private DomainResource fetchCodeSystemOrValueSet(FhirContext theContext, String theSystem, boolean codeSystem) {
synchronized (this) {
Map<String, CodeSystem> codeSystems = myCodeSystems;
Map<String, ValueSet> valueSets = myValueSets;
if (codeSystems == null || valueSets == null) {
codeSystems = new HashMap<String, CodeSystem>();
valueSets = new HashMap<String, ValueSet>();
private DomainResource fetchCodeSystemOrValueSet(FhirContext theContext, String theSystem, boolean codeSystem) {
synchronized (this) {
Map<String, CodeSystem> codeSystems = myCodeSystems;
Map<String, ValueSet> valueSets = myValueSets;
if (codeSystems == null || valueSets == null) {
codeSystems = new HashMap<String, CodeSystem>();
valueSets = new HashMap<String, ValueSet>();
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/valuesets.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v2-tables.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v3-codesystems.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/valuesets.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v2-tables.xml");
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/dstu3/model/valueset/v3-codesystems.xml");
myCodeSystems = codeSystems;
myValueSets = valueSets;
}
myCodeSystems = codeSystems;
myValueSets = valueSets;
}
if (codeSystem) {
return codeSystems.get(theSystem);
} else {
return valueSets.get(theSystem);
}
}
}
if (codeSystem) {
return codeSystems.get(theSystem);
} else {
return valueSets.get(theSystem);
}
}
}
@SuppressWarnings("unchecked")
@Override
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
Validate.notBlank(theUri, "theUri must not be null or blank");
@SuppressWarnings("unchecked")
@Override
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
Validate.notBlank(theUri, "theUri must not be null or blank");
if (theClass.equals(StructureDefinition.class)) {
return (T) fetchStructureDefinition(theContext, theUri);
}
if (theClass.equals(StructureDefinition.class)) {
return (T) fetchStructureDefinition(theContext, theUri);
}
if (theClass.equals(ValueSet.class) || theUri.startsWith(URL_PREFIX_VALUE_SET)) {
return (T) fetchValueSet(theContext, theUri);
}
if (theClass.equals(ValueSet.class) || theUri.startsWith(URL_PREFIX_VALUE_SET)) {
return (T) fetchValueSet(theContext, theUri);
}
return null;
}
return null;
}
@Override
public StructureDefinition fetchStructureDefinition(FhirContext theContext, String theUrl) {
String url = theUrl;
if (url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) {
// no change
} else if (url.indexOf('/') == -1) {
url = URL_PREFIX_STRUCTURE_DEFINITION + url;
} else if (StringUtils.countMatches(url, '/') == 1) {
url = URL_PREFIX_STRUCTURE_DEFINITION_BASE + url;
}
Map<String, StructureDefinition> map = provideStructureDefinitionMap(theContext);
StructureDefinition retVal = map.get(url);
@Override
public StructureDefinition fetchStructureDefinition(FhirContext theContext, String theUrl) {
String url = theUrl;
if (url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) {
// no change
} else if (url.indexOf('/') == -1) {
url = URL_PREFIX_STRUCTURE_DEFINITION + url;
} else if (StringUtils.countMatches(url, '/') == 1) {
url = URL_PREFIX_STRUCTURE_DEFINITION_BASE + url;
}
Map<String, StructureDefinition> map = provideStructureDefinitionMap(theContext);
StructureDefinition retVal = map.get(url);
if (retVal == null && url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) {
String tryUrl = URL_PREFIX_STRUCTURE_DEFINITION + StringUtils.capitalize(url.substring(URL_PREFIX_STRUCTURE_DEFINITION.length()));
retVal = map.get(tryUrl);
}
if (retVal == null && url.startsWith(URL_PREFIX_STRUCTURE_DEFINITION)) {
String tryUrl = URL_PREFIX_STRUCTURE_DEFINITION + StringUtils.capitalize(url.substring(URL_PREFIX_STRUCTURE_DEFINITION.length()));
retVal = map.get(tryUrl);
}
return retVal;
}
return retVal;
}
ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
return (ValueSet) fetchCodeSystemOrValueSet(theContext, theSystem, false);
}
ValueSet fetchValueSet(FhirContext theContext, String theSystem) {
return (ValueSet) fetchCodeSystemOrValueSet(theContext, theSystem, false);
}
public void flush() {
myCodeSystems = null;
myStructureDefinitions = null;
}
public void flush() {
myCodeSystems = null;
myStructureDefinitions = null;
}
@Override
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
CodeSystem cs = fetchCodeSystem(theContext, theSystem);
return cs != null && cs.getContent() != CodeSystemContentMode.NOTPRESENT;
}
@Override
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
CodeSystem cs = fetchCodeSystem(theContext, theSystem);
return cs != null && cs.getContent() != CodeSystemContentMode.NOTPRESENT;
}
private void loadCodeSystems(FhirContext theContext, Map<String, CodeSystem> theCodeSystems, Map<String, ValueSet> theValueSets, String theClasspath) {
ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath);
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
if (valuesetText != null) {
InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8);
private void loadCodeSystems(FhirContext theContext, Map<String, CodeSystem> theCodeSystems, Map<String, ValueSet> theValueSets, String theClasspath) {
ourLog.info("Loading CodeSystem/ValueSet from classpath: {}", theClasspath);
InputStream inputStream = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
InputStreamReader reader = null;
if (inputStream != null) {
try {
reader = new InputStreamReader(inputStream, Charsets.UTF_8);
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof CodeSystem) {
CodeSystem nextValueSet = (CodeSystem) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextValueSet);
}
} else if (next.getResource() instanceof ValueSet) {
ValueSet nextValueSet = (ValueSet) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theValueSets.put(system, nextValueSet);
}
}
}
} else {
ourLog.warn("Unable to load resource: {}", theClasspath);
}
}
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof CodeSystem) {
CodeSystem nextValueSet = (CodeSystem) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextValueSet);
}
} else if (next.getResource() instanceof ValueSet) {
ValueSet nextValueSet = (ValueSet) next.getResource();
nextValueSet.getText().setDivAsString("");
String system = nextValueSet.getUrl();
if (isNotBlank(system)) {
theValueSets.put(system, nextValueSet);
}
}
}
} finally {
IOUtils.closeQuietly(reader);
IOUtils.closeQuietly(inputStream);
}
} else {
ourLog.warn("Unable to load resource: {}", theClasspath);
}
}
private void loadStructureDefinitions(FhirContext theContext, Map<String, StructureDefinition> theCodeSystems, String theClasspath) {
ourLog.info("Loading structure definitions from classpath: {}", theClasspath);
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
if (valuesetText != null) {
InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8);
private void loadStructureDefinitions(FhirContext theContext, Map<String, StructureDefinition> theCodeSystems, String theClasspath) {
ourLog.info("Loading structure definitions from classpath: {}", theClasspath);
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theClasspath);
if (valuesetText != null) {
InputStreamReader reader = new InputStreamReader(valuesetText, Charsets.UTF_8);
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof StructureDefinition) {
StructureDefinition nextSd = (StructureDefinition) next.getResource();
nextSd.getText().setDivAsString("");
String system = nextSd.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextSd);
}
}
}
} else {
ourLog.warn("Unable to load resource: {}", theClasspath);
}
}
Bundle bundle = theContext.newXmlParser().parseResource(Bundle.class, reader);
for (BundleEntryComponent next : bundle.getEntry()) {
if (next.getResource() instanceof StructureDefinition) {
StructureDefinition nextSd = (StructureDefinition) next.getResource();
nextSd.getText().setDivAsString("");
String system = nextSd.getUrl();
if (isNotBlank(system)) {
theCodeSystems.put(system, nextSd);
}
}
}
} else {
ourLog.warn("Unable to load resource: {}", theClasspath);
}
}
private Map<String, StructureDefinition> provideStructureDefinitionMap(FhirContext theContext) {
Map<String, StructureDefinition> structureDefinitions = myStructureDefinitions;
if (structureDefinitions == null) {
structureDefinitions = new HashMap<String, StructureDefinition>();
private Map<String, StructureDefinition> provideStructureDefinitionMap(FhirContext theContext) {
Map<String, StructureDefinition> structureDefinitions = myStructureDefinitions;
if (structureDefinitions == null) {
structureDefinitions = new HashMap<String, StructureDefinition>();
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-resources.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-types.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-others.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-resources.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-types.xml");
loadStructureDefinitions(theContext, structureDefinitions, "/org/hl7/fhir/dstu3/model/profile/profiles-others.xml");
myStructureDefinitions = structureDefinitions;
}
return structureDefinitions;
}
myStructureDefinitions = structureDefinitions;
}
return structureDefinitions;
}
private CodeValidationResult testIfConceptIsInList(String theCode, List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive) {
String code = theCode;
if (theCaseSensitive == false) {
code = code.toUpperCase();
}
private CodeValidationResult testIfConceptIsInList(String theCode, List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive) {
String code = theCode;
if (theCaseSensitive == false) {
code = code.toUpperCase();
}
return testIfConceptIsInListInner(conceptList, theCaseSensitive, code);
}
return testIfConceptIsInListInner(conceptList, theCaseSensitive, code);
}
private CodeValidationResult testIfConceptIsInListInner(List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive, String code) {
CodeValidationResult retVal = null;
for (ConceptDefinitionComponent next : conceptList) {
String nextCandidate = next.getCode();
if (theCaseSensitive == false) {
nextCandidate = nextCandidate.toUpperCase();
}
if (nextCandidate.equals(code)) {
retVal = new CodeValidationResult(next);
break;
}
private CodeValidationResult testIfConceptIsInListInner(List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive, String code) {
CodeValidationResult retVal = null;
for (ConceptDefinitionComponent next : conceptList) {
String nextCandidate = next.getCode();
if (theCaseSensitive == false) {
nextCandidate = nextCandidate.toUpperCase();
}
if (nextCandidate.equals(code)) {
retVal = new CodeValidationResult(next);
break;
}
// recurse
retVal = testIfConceptIsInList(code, next.getConcept(), theCaseSensitive);
if (retVal != null) {
break;
}
}
// recurse
retVal = testIfConceptIsInList(code, next.getConcept(), theCaseSensitive);
if (retVal != null) {
break;
}
}
return retVal;
}
return retVal;
}
@Override
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
if (cs != null) {
boolean caseSensitive = true;
if (cs.hasCaseSensitive()) {
caseSensitive = cs.getCaseSensitive();
}
@Override
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
if (cs != null) {
boolean caseSensitive = true;
if (cs.hasCaseSensitive()) {
caseSensitive = cs.getCaseSensitive();
}
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
if (retVal != null) {
return retVal;
}
}
if (retVal != null) {
return retVal;
}
}
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
}
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
}
}

View File

@ -2,6 +2,7 @@ package org.hl7.fhir.instance.hapi.validation;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.io.IOUtils;
import org.hl7.fhir.instance.model.Bundle;
import org.hl7.fhir.instance.model.Bundle.BundleEntryComponent;
import org.hl7.fhir.instance.model.CodeType;
@ -44,9 +45,9 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
if (valueSets == null) {
valueSets = new HashMap<String, ValueSet>();
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/valuesets.xml");
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v2-tables.xml");
loadCodeSystems(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml");
loadValueSets(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/valuesets.xml");
loadValueSets(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v2-tables.xml");
loadValueSets(theContext, valueSets, "/org/hl7/fhir/instance/model/valueset/v3-codesystems.xml");
myCodeSystems = valueSets;
}
@ -108,26 +109,34 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
return false;
}
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);
}
private void loadValueSets(FhirContext theContext, Map<String, ValueSet> theValueSets, String theFile) {
InputStream valuesetText = DefaultProfileValidationSupport.class.getResourceAsStream(theFile);
try {
if (valuesetText != null) {
InputStreamReader reader = null;
try {
reader = new InputStreamReader(valuesetText, "UTF-8");
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);
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)) {
theValueSets.put(system, nextValueSet);
}
}
} catch (UnsupportedEncodingException e) {
// Shouldn't happen!
throw new InternalErrorException("UTF-8 encoding not supported on this platform", e);
} finally {
IOUtils.closeQuietly(reader);
}
}
} finally {
IOUtils.closeQuietly(valuesetText);
}
}
@ -136,7 +145,7 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
ValueSet vs = fetchCodeSystem(theContext, theCodeSystem);
if (vs != null) {
for (ValueSet.ConceptDefinitionComponent nextConcept : vs.getCodeSystem().getConcept()) {
if (nextConcept.getCode().equals(theCode)){
if (nextConcept.getCode().equals(theCode)) {
ValueSet.ConceptDefinitionComponent component = new ValueSet.ConceptDefinitionComponent(new CodeType(theCode));
return new CodeValidationResult(component);
}

View File

@ -0,0 +1,218 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>3.3.0-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<groupId>ca.uhn.hapi.fhir.karaf</groupId>
<artifactId>hapi-fhir</artifactId>
<packaging>pom</packaging>
<name>HAPI FHIR - Apache Karaf :: Features</name>
<properties>
<features.file>features.xml</features.file>
<pax-logging-version>1.8.6</pax-logging-version>
<felix-framework-version>3.2.2</felix-framework-version>
</properties>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-converter</artifactId>
<version>${project.version}</version>
</dependency>
<!-- The validate plugin will export these provided dependencies bundles export packages first -->
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.3.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-api</artifactId>
<version>${pax-logging-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.logging</groupId>
<artifactId>pax-logging-service</artifactId>
<version>${pax-logging-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.framework</artifactId>
<version>${felix-framework-version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.configadmin</artifactId>
<version>1.8.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.api</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.aries.blueprint</groupId>
<artifactId>org.apache.aries.blueprint.core</artifactId>
<version>1.0.1</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.core</artifactId>
<version>${apache_karaf_version}</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.karaf.features</groupId>
<artifactId>framework</artifactId>
<version>${apache_karaf_version}</version>
<type>kar</type>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>filter</id>
<phase>generate-resources</phase>
<goals>
<goal>resources</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>target/classes/features.xml</file>
<type>xml</type>
<classifier>features</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.karaf.tooling</groupId>
<artifactId>karaf-maven-plugin</artifactId>
<version>${apache_karaf_version}</version>
<configuration>
<descriptors>
<descriptor>file://${project.build.directory}/classes/${features.file}</descriptor>
<descriptor>mvn:org.apache.karaf.features/enterprise/${apache_karaf_version}/xml/features</descriptor>
</descriptors>
<distribution>org.apache.karaf.features:framework</distribution>
<javase>1.8</javase>
<framework>
<feature>framework</feature>
</framework>
<features>
<feature>hapi-fhir*</feature>
</features>
</configuration>
<executions>
<execution>
<id>validate</id>
<phase>process-resources</phase>
<goals>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,135 @@
<?xml version='1.0' encoding='UTF-8'?>
<!--
HAPI FHIR - Apache Karaf Features
Copyright (C) 2014 - 2018 University Health Network
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<features name='hapi-fhir-${project.version}' xmlns="http://karaf.apache.org/xmlns/features/v1.3.0">
<feature name='hapi-fhir' version='${project.version}' start-level='50'>
<feature prerequisite="true">wrap</feature>
<bundle dependency='true'>mvn:com.google.code.gson/gson/${gson_version}</bundle>
<bundle dependency='true'>mvn:org.apache.commons/commons-lang3/${commons_lang3_version}</bundle>
<bundle dependency='true'>mvn:commons-codec/commons-codec/${commons_codec_version}</bundle>
<bundle dependency='true'>mvn:commons-io/commons-io/${commons_io_version}</bundle>
<bundle dependency='true'>mvn:com.google.guava/guava/${guava_version}</bundle>
<bundle dependency='true'>wrap:mvn:com.google.errorprone/error_prone_annotations/${error_prone_annotations_version}</bundle>
<bundle dependency='true'>mvn:org.codehaus.woodstox/stax2-api/${stax2_api_version}</bundle>
<bundle dependency='true'>mvn:org.codehaus.woodstox/woodstox-core-asl/${woodstox_core_asl_version}</bundle>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-base/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-client' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<bundle dependency='true'>mvn:org.apache.httpcomponents/httpcore-osgi/${httpcore_version}</bundle>
<bundle dependency='true'>mvn:org.apache.httpcomponents/httpclient-osgi/${httpclient_version}</bundle>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-client/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-utilities' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<bundle dependency='true'>mvn:com.google.code.gson/gson/${gson_version}</bundle>
<bundle dependency='true'>mvn:commons-codec/commons-codec/${commons_codec_version}</bundle>
<bundle dependency='true'>mvn:commons-io/commons-io/${commons_io_version}</bundle>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-utilities/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-dstu2' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-structures-dstu2/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-hl7org-dstu2' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<feature version='${project.version}'>hapi-fhir-utilities</feature>
<bundle dependency='true'>
mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.saxon/${servicemix_saxon_version}
</bundle>
<bundle dependency='true'>
mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xmlresolver/${servicemix_xmlresolver_version}
</bundle>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-structures-hl7org-dstu2/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-dstu2.1' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<feature version='${project.version}'>hapi-fhir-utilities</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-structures-dstu2.1/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-dstu3' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<feature version='${project.version}'>hapi-fhir-utilities</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-structures-dstu3/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-r4' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<feature version='${project.version}'>hapi-fhir-utilities</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-structures-r4/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-ph-schematron' version='${project.version}' start-level='50'>
<bundle dependency='true'>
mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.saxon/${servicemix_saxon_version}
</bundle>
<bundle dependency='true'>
mvn:org.apache.servicemix.bundles/org.apache.servicemix.bundles.xmlresolver/${servicemix_xmlresolver_version}
</bundle>
<bundle dependency='true'>mvn:com.google.code.findbugs/jsr305/${jsr305_version}</bundle>
<bundle>mvn:com.phloc/phloc-schematron/${phloc_schematron_version}</bundle>
<bundle>mvn:com.phloc/phloc-commons/${phloc_commons_version}</bundle>
</feature>
<feature name='hapi-fhir-validation' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir</feature>
<feature version='${project.version}'>hapi-fhir-utilities</feature>
<feature version='${project.version}'>hapi-fhir-ph-schematron</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-converter/${project.version}</bundle>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-validation/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-validation-dstu2' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir-validation</feature>
<feature version='${project.version}'>hapi-fhir-dstu2</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-validation-resources-dstu2/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-validation-hl7org-dstu2' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir-validation</feature>
<feature version='${project.version}'>hapi-fhir-hl7org-dstu2</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-validation-resources-dstu2/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-validation-dstu2.1' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir-validation</feature>
<feature version='${project.version}'>hapi-fhir-dstu2.1</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-validation-resources-dstu2.1/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-validation-dstu3' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir-validation</feature>
<feature version='${project.version}'>hapi-fhir-dstu3</feature>
<feature version='${project.version}'>hapi-fhir-r4</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-validation-resources-dstu3/${project.version}</bundle>
</feature>
<feature name='hapi-fhir-validation-r4' version='${project.version}' start-level='50'>
<feature version='${project.version}'>hapi-fhir-validation</feature>
<feature version='${project.version}'>hapi-fhir-r4</feature>
<bundle>mvn:ca.uhn.hapi.fhir/hapi-fhir-validation-resources-r4/${project.version}</bundle>
</feature>
</features>

View File

@ -0,0 +1,181 @@
<!--
Licensed to the Apache Software Foundation (ASF) under one or more
contributor license agreements. See the NOTICE file distributed with
this work for additional information regarding copyright ownership.
The ASF licenses this file to You under the Apache License, Version 2.0
(the "License"); you may not use this file except in compliance with
the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>3.3.0-SNAPSHOT</version>
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-karaf-integration-tests</artifactId>
<packaging>jar</packaging>
<name>HAPI-FHIR Apache Karaf Integration Tests</name>
<description>
Integration tests for the HAPI-FHIR Apache Karaf features
</description>
<properties>
<pax.exam.version>4.9.1</pax.exam.version>
</properties>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-client</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-r4</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-r4</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation</artifactId>
<version>${project.version}</version>
</dependency>
<!-- karaf test -->
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-container-karaf</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ops4j.pax.exam</groupId>
<artifactId>pax-exam-junit4</artifactId>
<version>${pax.exam.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.xmlunit</groupId>
<artifactId>xmlunit-core</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.karaf</groupId>
<artifactId>apache-karaf</artifactId>
<version>${apache_karaf_version}</version>
<scope>test</scope>
<type>tar.gz</type>
</dependency>
<dependency>
<groupId>org.apache.karaf.shell</groupId>
<artifactId>org.apache.karaf.shell.console</artifactId>
<version>${apache_karaf_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir.karaf</groupId>
<artifactId>hapi-fhir</artifactId>
<version>${project.version}</version>
<classifier>features</classifier>
<type>xml</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.karaf.features</groupId>
<artifactId>enterprise</artifactId>
<version>${apache_karaf_version}</version>
<classifier>features</classifier>
<type>xml</type>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.servicemix.bundles</groupId>
<artifactId>org.apache.servicemix.bundles.hamcrest</artifactId>
<version>1.3_1</version>
<scope>runtime</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.servicemix.tooling</groupId>
<artifactId>depends-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>generate-depends-file</id>
<goals>
<goal>generate-depends-file</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<forkCount>1</forkCount>
<reuseForks>false</reuseForks>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,142 @@
package ca.uhn.fhir.tests.integration.karaf;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.karaf.options.LogLevelOption;
import org.ops4j.pax.exam.options.DefaultCompositeOption;
import java.io.File;
import static org.ops4j.pax.exam.CoreOptions.maven;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.configureConsole;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.karafDistributionConfiguration;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.keepRuntimeFolder;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.logLevel;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.features;
public enum PaxExamOptions {
KARAF(
karafDistributionConfiguration()
.frameworkUrl(
maven()
.groupId("org.apache.karaf")
.artifactId("apache-karaf")
.versionAsInProject()
.type("zip"))
.name("Apache Karaf")
.useDeployFolder(false)
.unpackDirectory(new File("target/paxexam/unpack/")),
keepRuntimeFolder(),
configureConsole().ignoreLocalConsole(),
logLevel(LogLevelOption.LogLevel.INFO)
),
WRAP(
features(
maven()
.groupId("org.apache.karaf.features")
.artifactId("enterprise")
.type("xml")
.classifier("features")
.versionAsInProject(),
"wrap")
),
HAPI_FHIR_CLIENT(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-client")
),
HAPI_FHIR_HL7ORG_DSTU2(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-hl7org-dstu2")
),
HAPI_FHIR_DSTU2_1(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-dstu2.1")
),
HAPI_FHIR_DSTU3(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-dstu3")
),
HAPI_FHIR_R4(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-r4")
),
HAPI_FHIR_VALIDATION_DSTU2(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-validation-dstu2")
),
HAPI_FHIR_VALIDATION_HL7ORG_DSTU2(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-validation-hl7org-dstu2")
),
HAPI_FHIR_VALIDATION_DSTU3(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-validation-dstu3")
),
HAPI_FHIR_VALIDATION_R4(
features(
maven()
.groupId("ca.uhn.hapi.fhir.karaf")
.artifactId("hapi-fhir")
.type("xml")
.classifier("features")
.versionAsInProject(),
"hapi-fhir-validation-r4")
);
private final Option[] options;
PaxExamOptions(Option... options) {
this.options = options;
}
public Option option() {
return new DefaultCompositeOption(options);
}
}

View File

@ -0,0 +1,63 @@
package ca.uhn.fhir.tests.integration.karaf.client;
import java.io.IOException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.PreferReturnEnum;
import ca.uhn.fhir.rest.client.api.IGenericClient;
import org.hl7.fhir.dstu3.model.Patient;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_CLIENT;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_DSTU3;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;
/**
* Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
@Ignore(value = "Relies on external service being up and running")
public class FhirClientTest {
private FhirContext fhirContext = FhirContext.forDstu3();
private IGenericClient client = fhirContext.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu3");
private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirClientTest.class);
@Configuration
public Option[] config() throws IOException {
return options(
KARAF.option(),
HAPI_FHIR_CLIENT.option(),
HAPI_FHIR_DSTU3.option(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
WRAP.option(),
when(false)
.useOptions(
debugConfiguration("5005", true))
);
}
@Test
public void createPatient() throws Exception {
Patient patient = new Patient();
patient.setId("PATIENTID");
patient.getMeta().addProfile("http://BAR");
patient.addName().addGiven("GIVEN");
MethodOutcome execute = client.create().resource(patient).prefer(PreferReturnEnum.REPRESENTATION).execute();
ourLog.info(execute.toString());
}
}

View File

@ -0,0 +1,331 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Condition;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.valueset.ConditionVerificationStatusEnum;
import ca.uhn.fhir.model.dstu2.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.primitive.DateDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.SchemaBaseValidator;
import ca.uhn.fhir.validation.ValidationFailureException;
import ca.uhn.fhir.validation.ValidationResult;
import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
import org.apache.commons.io.IOUtils;
import org.hamcrest.Matcher;
import org.hamcrest.Matchers;
import org.hamcrest.core.StringContains;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_VALIDATION_DSTU2;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;
/**
* Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class Dstu2ResourceValidatorDstu2Test {
private FhirContext ourCtx = FhirContext.forDstu2();
private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(Dstu2ResourceValidatorDstu2Test.class);
@Configuration
public Option[] config() throws IOException {
return options(
KARAF.option(),
WRAP.option(),
HAPI_FHIR_VALIDATION_DSTU2.option(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
when(false)
.useOptions(
debugConfiguration("5005", true))
);
}
private FhirValidator createFhirValidator() {
FhirValidator val = ourCtx.newValidator();
val.setValidateAgainstStandardSchema(true);
val.setValidateAgainstStandardSchematron(true);
return val;
}
private String logOperationOutcome(ValidationResult result) {
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
ourLog.info(encoded);
return encoded;
}
/**
* See issue #50
*/
@Test()
public void testOutOfBoundsDate() {
Patient p = new Patient();
p.setBirthDate(new DateDt("2000-12-31"));
// Put in an invalid date
IParser parser = ourCtx.newXmlParser();
parser.setParserErrorHandler(new StrictErrorHandler());
String encoded = parser.setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
ourLog.info(encoded);
assertThat(encoded, StringContains.containsString("2000-15-31"));
ValidationResult result = ourCtx.newValidator().validateWithResult(encoded);
String resultString = parser.setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(resultString);
assertEquals(2, ((OperationOutcome)result.toOperationOutcome()).getIssue().size());
assertThat(resultString, StringContains.containsString("cvc-pattern-valid"));
try {
parser.parseResource(encoded);
fail();
} catch (DataFormatException e) {
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"2000-15-31\": Invalid date/time format: \"2000-15-31\"", e.getMessage());
}
}
@Test
public void testSchemaBundleValidatorIsSuccessful() throws IOException {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("bundle-example.json"), StandardCharsets.UTF_8);
Bundle b = ourCtx.newJsonParser().parseResource(Bundle.class, res);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b));
FhirValidator val = createFhirValidator();
ValidationResult result = val.validateWithResult(b);
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
assertTrue(result.toString(), result.isSuccessful());
assertNotNull(operationOutcome);
assertEquals(1, operationOutcome.getIssue().size());
}
@SuppressWarnings("deprecation")
@Test
public void testSchemaResourceValidator() throws IOException {
String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("patient-example-dicom.json"));
Patient p = ourCtx.newJsonParser().parseResource(Patient.class, res);
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p));
FhirValidator val = ourCtx.newValidator();
val.setValidateAgainstStandardSchema(true);
val.setValidateAgainstStandardSchematron(false);
val.validate(p);
p.getAnimal().getBreed().setText("The Breed");
try {
val.validate(p);
fail();
} catch (ValidationFailureException e) {
OperationOutcome operationOutcome = (OperationOutcome) e.getOperationOutcome();
ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome));
assertEquals(1, operationOutcome.getIssue().size());
assertThat(operationOutcome.getIssueFirstRep().getDetailsElement().getValue(), containsString("cvc-complex-type"));
}
}
/**
* Make sure that the elements that appear in all resources (meta, language, extension, etc)
* all appear in the correct order
*/
@Test
public void testValidateResourceWithResourceElements() {
TestPatientFor327 patient = new TestPatientFor327();
patient.setBirthDate(new Date(), TemporalPrecisionEnum.DAY);
patient.setId("123");
patient.getText().setDiv("<div>FOO</div>");
patient.getText().setStatus(NarrativeStatusEnum.GENERATED);
patient.getLanguage().setValue("en");
patient.addUndeclaredExtension(true, "http://foo").setValue(new StringDt("MOD"));
ResourceMetadataKeyEnum.UPDATED.put(patient, new InstantDt(new Date()));
List<ResourceReferenceDt> conditions = new ArrayList<ResourceReferenceDt>();
Condition condition = new Condition();
condition.getPatient().setReference("Patient/123");
condition.addBodySite().setText("BODY SITE");
condition.getCode().setText("CODE");
condition.setVerificationStatus(ConditionVerificationStatusEnum.CONFIRMED);
conditions.add(new ResourceReferenceDt(condition));
patient.setCondition(conditions);
patient.addIdentifier().setSystem("http://foo").setValue("123");
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
FhirValidator val = createFhirValidator();
ValidationResult result = val.validateWithResult(encoded);
String messageString = logOperationOutcome(result);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("No issues"));
}
/**
* See
* https://groups.google.com/d/msgid/hapi-fhir/a266083f-6454-4cf0-a431-c6500f052bea%40googlegroups.com?utm_medium=
* email&utm_source=footer
*/
@Test
public void testValidateWithExtensionsJson() {
PatientProfileDstu2 myPatient = new PatientProfileDstu2();
myPatient.setColorPrimary(new CodeableConceptDt("http://example.com#animalColor", "furry-grey"));
myPatient.setColorSecondary(new CodeableConceptDt("http://example.com#animalColor", "furry-white"));
myPatient.setOwningOrganization(new ResourceReferenceDt("Organization/2.25.79433498044103547197447759549862032393"));
myPatient.addName().addFamily("FamilyName");
myPatient.addUndeclaredExtension(new ExtensionDt().setUrl("http://foo.com/example").setValue(new StringDt("String Extension")));
IParser p = FhirContext.forDstu2().newJsonParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(myPatient);
ourLog.info(messageString);
//@formatter:off
assertThat(messageString, stringContainsInOrder(
"meta",
"String Extension",
"Organization/2.25.79433498044103547197447759549862032393",
"furry-grey",
"furry-white",
"FamilyName"
));
assertThat(messageString, not(stringContainsInOrder(
"extension",
"meta"
)));
//@formatter:on
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
ValidationResult result = val.validateWithResult(messageString);
logOperationOutcome(result);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("valueReference"));
assertThat(messageString, not(containsString("valueResource")));
}
private Matcher<? super String> stringContainsInOrder(java.lang.String... substrings) {
return Matchers.stringContainsInOrder(Arrays.asList(substrings));
}
/**
* See
* https://groups.google.com/d/msgid/hapi-fhir/a266083f-6454-4cf0-a431-c6500f052bea%40googlegroups.com?utm_medium=
* email&utm_source=footer
*/
@Test
public void testValidateWithExtensionsXml() {
PatientProfileDstu2 myPatient = new PatientProfileDstu2();
myPatient.setColorPrimary(new CodeableConceptDt("http://example.com#animalColor", "furry-grey"));
myPatient.setColorSecondary(new CodeableConceptDt("http://example.com#animalColor", "furry-white"));
myPatient.setOwningOrganization(new ResourceReferenceDt("Organization/2.25.79433498044103547197447759549862032393"));
myPatient.addName().addFamily("FamilyName");
myPatient.addUndeclaredExtension(new ExtensionDt().setUrl("http://foo.com/example").setValue(new StringDt("String Extension")));
IParser p = FhirContext.forDstu2().newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(myPatient);
ourLog.info(messageString);
//@formatter:off
assertThat(messageString, stringContainsInOrder(
"meta",
"Organization/2.25.79433498044103547197447759549862032393",
"furry-grey",
"furry-white",
"String Extension",
"FamilyName"
));
assertThat(messageString, not(stringContainsInOrder(
"extension",
"meta"
)));
assertThat(messageString, containsString("url=\"http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#animal-colorSecondary\""));
assertThat(messageString, containsString("url=\"http://foo.com/example\""));
//@formatter:on
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
ValidationResult result = val.validateWithResult(messageString);
logOperationOutcome(result);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("valueReference"));
assertThat(messageString, not(containsString("valueResource")));
}
@ResourceDef(name = "Patient")
public static class TestPatientFor327 extends Patient {
private static final long serialVersionUID = 1L;
@Child(name = "testCondition")
@ca.uhn.fhir.model.api.annotation.Extension(url = "testCondition", definedLocally = true, isModifier = false)
private List<ResourceReferenceDt> testConditions = null;
public List<ResourceReferenceDt> getConditions() {
return this.testConditions;
}
public void setCondition(List<ResourceReferenceDt> ref) {
this.testConditions = ref;
}
}
}

View File

@ -0,0 +1,72 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.util.ElementUtil;
@ResourceDef(name="Patient", profile = "http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient")
public class PatientProfileDstu2 extends Patient {
private static final long serialVersionUID = 1L;
@Child(name="owner", min=0, max=1)
@Extension(url="http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#owningOrganization", definedLocally=false, isModifier=false)
@Description(shortDefinition="The organization that owns this animal")
private ResourceReferenceDt owningOrganization;
public ResourceReferenceDt getOwningOrganization() {
if (owningOrganization == null) {
owningOrganization = new ResourceReferenceDt();
}
return owningOrganization;
}
public PatientProfileDstu2 setOwningOrganization(ResourceReferenceDt owningOrganization) {
this.owningOrganization = owningOrganization;
return this;
}
@Child(name="colorPrimary", min=0, max=1)
@Extension(url="http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#animal-colorPrimary", definedLocally=false, isModifier=false)
@Description(shortDefinition="The animals primary color")
private CodeableConceptDt colorPrimary;
@Child(name="colorSecondary", min=0, max=1)
@Extension(url="http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#animal-colorSecondary", definedLocally=false, isModifier=false)
@Description(shortDefinition="The animals secondary color")
private CodeableConceptDt colorSecondary;
public CodeableConceptDt getColorPrimary() {
if (this.colorPrimary == null) {
return new CodeableConceptDt();
}
return colorPrimary;
}
public void setColorPrimary(CodeableConceptDt colorPrimary) {
this.colorPrimary = colorPrimary;
}
public CodeableConceptDt getColorSecondary() {
if (this.colorSecondary == null) {
return new CodeableConceptDt();
}
return colorSecondary;
}
public void setColorSecondary(CodeableConceptDt colorSecondary) {
this.colorSecondary = colorSecondary;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(owningOrganization) && ElementUtil.isEmpty(colorPrimary)
&& ElementUtil.isEmpty(colorSecondary) ;
}
}

View File

@ -0,0 +1,60 @@
package ca.uhn.fhir.tests.integration.karaf.dstu21;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu2016may.model.Identifier;
import org.hl7.fhir.dstu2016may.model.Patient;
@ResourceDef(name = "Patient")
public class PatientWithExtendedContactDstu3 extends Patient {
private static final long serialVersionUID = 1L;
/**
* A contact party (e.g. guardian, partner, friend) for the patient.
*/
@Child(name = "contact", type = {}, order = Child.REPLACE_PARENT, min = 0, max = Child.MAX_UNLIMITED, modifier = false, summary = false)
@Description(shortDefinition = "A contact party (e.g. guardian, partner, friend) for the patient", formalDefinition = "A contact party (e.g. guardian, partner, friend) for the patient.")
protected List<CustomContactComponent> customContact;
public List<CustomContactComponent> getCustomContact() {
if (customContact == null) {
customContact = new ArrayList<CustomContactComponent>();
}
return customContact;
}
@Block()
public static class CustomContactComponent extends ContactComponent {
private static final long serialVersionUID = 1L;
@Child(name = "contact-eyecolour", type = { Identifier.class }, modifier = true)
@Description(shortDefinition = "Application ID")
@Extension(url = "http://foo.com/contact-eyecolour", definedLocally = false, isModifier = false)
private Identifier myEyeColour;
/*
* Get messageHeaderApplicationId
*/
public Identifier getEyeColour() {
if (myEyeColour == null) {
myEyeColour = new Identifier();
}
return myEyeColour;
}
/*
* Set messageHeaderApplicationId
*/
public void setEyeColour(Identifier messageHeaderApplicationId) {
this.myEyeColour = messageHeaderApplicationId;
}
}
}

View File

@ -0,0 +1,136 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2hl7org;
import java.io.IOException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.ValidationResult;
import org.hl7.fhir.instance.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.instance.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.instance.model.DateType;
import org.hl7.fhir.instance.model.Observation;
import org.hl7.fhir.instance.model.QuestionnaireResponse;
import org.hl7.fhir.instance.model.StringType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_VALIDATION_HL7ORG_DSTU2;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;
/**
* Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class FhirInstanceValidatorTest {
private FhirInstanceValidator ourValidator = new FhirInstanceValidator(new DefaultProfileValidationSupport());
private FhirContext ourCtxHl7OrgDstu2 = FhirContext.forDstu2Hl7Org();
private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidatorTest.class);
@Configuration
public Option[] config() throws IOException {
return options(
KARAF.option(),
WRAP.option(),
HAPI_FHIR_VALIDATION_HL7ORG_DSTU2.option(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
when(false)
.useOptions(
debugConfiguration("5005", true))
);
}
@Test
public void testQuestionnaireResponse() {
QuestionnaireResponse qr = new QuestionnaireResponse();
qr.setStatus(QuestionnaireResponse.QuestionnaireResponseStatus.COMPLETED);
qr.getGroup().addGroup().addQuestion().setLinkId("foo");
qr.getGroup().addQuestion().setLinkId("bar");
FhirValidator val = ourCtxHl7OrgDstu2.newValidator();
val.registerValidatorModule(ourValidator);
ValidationResult result = val.validateWithResult(qr);
String encoded = ourCtxHl7OrgDstu2.newJsonParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(encoded);
assertTrue(result.isSuccessful());
}
@Test
public void testObservation() {
Observation o = new Observation();
o.addIdentifier().setSystem("http://acme.org").setValue("1234");
o.setStatus(Observation.ObservationStatus.FINAL);
o.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
o.getEncounter().setReference("Encounter/1234");
FhirValidator val = ourCtxHl7OrgDstu2.newValidator();
val.registerValidatorModule(ourValidator);
ValidationResult result = val.validateWithResult(o);
String encoded = ourCtxHl7OrgDstu2.newJsonParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(encoded);
assertTrue(result.isSuccessful());
}
@Test
public void testParametersWithTwoParameters() {
org.hl7.fhir.instance.model.Patient patient = new org.hl7.fhir.instance.model.Patient();
patient.addName().addGiven("James");
patient.setBirthDateElement(new DateType("2011-02-02"));
org.hl7.fhir.instance.model.Parameters input = new org.hl7.fhir.instance.model.Parameters();
input.addParameter().setName("mode").setValue(new StringType("create"));
input.addParameter().setName("resource").setResource(patient);
FhirValidator val = ourCtxHl7OrgDstu2.newValidator();
val.registerValidatorModule(ourValidator);
ValidationResult result = val.validateWithResult(input);
String encoded = ourCtxHl7OrgDstu2.newJsonParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(encoded);
assertTrue(result.isSuccessful());
assertThat(encoded, not(containsString("A parameter must have a value or a resource, but not both")));
}
@Test
public void testParametersHl7OrgDstu2() {
org.hl7.fhir.instance.model.Patient patient = new org.hl7.fhir.instance.model.Patient();
patient.addName().addGiven("James");
patient.setBirthDateElement(new DateType("2011-02-02"));
org.hl7.fhir.instance.model.Parameters input = new org.hl7.fhir.instance.model.Parameters();
input.addParameter().setName("resource").setResource(patient);
FhirValidator val = ourCtxHl7OrgDstu2.newValidator();
val.registerValidatorModule(ourValidator);
ValidationResult result = val.validateWithResult(input);
ourLog.info(ourCtxHl7OrgDstu2.newJsonParser().setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome()));
assertTrue(result.isSuccessful());
}
}

View File

@ -0,0 +1,106 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2hl7org;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.util.ElementUtil;
import org.hl7.fhir.instance.model.Attachment;
import org.hl7.fhir.instance.model.BackboneElement;
import org.hl7.fhir.instance.model.DateType;
import org.hl7.fhir.instance.model.Patient;
import org.hl7.fhir.instance.model.StringType;
import org.hl7.fhir.instance.model.api.IBaseBackboneElement;
@ResourceDef(name="Patient")
public class MyObservationWithExtensions extends Patient {
@Extension(url = "urn:patientext:att", definedLocally = false, isModifier = false)
@Child(name = "extAtt", order = 0)
private Attachment myExtAtt;
@Extension(url = "urn:patientext:moreext", definedLocally = false, isModifier = false)
@Child(name = "moreExt", order = 1)
private MoreExt myMoreExt;
@Extension(url = "urn:modext", definedLocally = false, isModifier = true)
@Child(name = "modExt", order = 2)
private DateType myModExt;
public Attachment getExtAtt() {
return myExtAtt;
}
public MoreExt getMoreExt() {
return myMoreExt;
}
public void setMoreExt(MoreExt theMoreExt) {
myMoreExt = theMoreExt;
}
public DateType getModExt() {
return myModExt;
}
public void setModExt(DateType theModExt) {
myModExt = theModExt;
}
public void setExtAtt(Attachment theExtAtt) {
myExtAtt = theExtAtt;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(myExtAtt, myModExt, myMoreExt);
}
/**
* Block class for child element: <b>Observation.referenceRange</b> (Provides guide for interpretation)
*
* <p>
* <b>Definition:</b> Guidance on how to interpret the value by comparison to a normal or recommended range
* </p>
*/
@Block(name = "Observation.someExtensions")
public static class MoreExt extends BackboneElement implements IBaseBackboneElement {
@Extension(url = "urn:patientext:moreext:1", definedLocally = false, isModifier = false)
@Child(name = "str1", order = 0)
private StringType myStr1;
@Extension(url = "urn:patientext:moreext:2", definedLocally = false, isModifier = false)
@Child(name = "str2", order = 1)
private StringType myStr2;
public StringType getStr1() {
return myStr1;
}
public void setStr1(StringType theStr1) {
myStr1 = theStr1;
}
public StringType getStr2() {
return myStr2;
}
public void setStr2(StringType theStr2) {
myStr2 = theStr2;
}
@Override
public boolean isEmpty() {
return ElementUtil.isEmpty(myStr1, myStr2);
}
@Override
public BackboneElement copy() {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,11 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2hl7org;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.instance.model.Organization;
@ResourceDef()
public class MyOrganizationDstu2 extends Organization {
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,64 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2hl7org;
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.instance.model.DateTimeType;
import org.hl7.fhir.instance.model.Patient;
import org.hl7.fhir.instance.model.Reference;
import org.hl7.fhir.instance.model.StringType;
@ResourceDef()
public class MyPatientHl7Org extends Patient {
private static final long serialVersionUID = 1L;
@Child(name="petName")
@Extension(url="http://example.com/dontuse#petname", definedLocally=false, isModifier=false)
@Description(shortDefinition="The name of the patient's favourite pet")
private StringType myPetName;
@Child(name="importantDates", max=Child.MAX_UNLIMITED)
@Extension(url="http://example.com/dontuse#importantDates", definedLocally=false, isModifier=true)
@Description(shortDefinition="Some dates of note for the patient")
private List<DateTimeType> myImportantDates;
@Child(name="managingOrganization", order=Child.REPLACE_PARENT, min=0, max=1, type={
MyOrganizationDstu2.class })
@Description(
shortDefinition="Organization that is the custodian of the patient record",
formalDefinition="Organization that is the custodian of the patient record"
)
private Reference myManagingOrganization;
@Override
public boolean isEmpty() {
return super.isEmpty() && myPetName.isEmpty();
}
public List<DateTimeType> getImportantDates() {
if (myImportantDates==null) {
myImportantDates = new ArrayList<DateTimeType>();
}
return myImportantDates;
}
public StringType getPetName() {
return myPetName;
}
public void setImportantDates(List<DateTimeType> theImportantDates) {
myImportantDates = theImportantDates;
}
public void setPetName(StringType thePetName) {
myPetName = thePetName;
}
}

View File

@ -0,0 +1,26 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2hl7org;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.instance.model.Address.AddressUse;
import org.hl7.fhir.instance.model.Enumeration;
import org.hl7.fhir.instance.model.Patient;
@ResourceDef(name = "Patient")
public class MyPatientWithOneDeclaredEnumerationExtension extends Patient {
private static final long serialVersionUID = 1L;
@Child(order = 0, name = "foo")
@ca.uhn.fhir.model.api.annotation.Extension(url = "urn:foo", definedLocally = true, isModifier = false)
private Enumeration<AddressUse> myFoo;
public Enumeration<AddressUse> getFoo() {
return myFoo;
}
public void setFoo(Enumeration<AddressUse> theFoo) {
myFoo = theFoo;
}
}

View File

@ -0,0 +1,206 @@
package ca.uhn.fhir.tests.integration.karaf.dstu2hl7org;
import java.util.List;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.instance.model.BackboneElement;
import org.hl7.fhir.instance.model.CodeableConcept;
import org.hl7.fhir.instance.model.DateType;
import org.hl7.fhir.instance.model.DomainResource;
import org.hl7.fhir.instance.model.Identifier;
import org.hl7.fhir.instance.model.ResourceType;
import org.hl7.fhir.instance.model.StringType;
@ResourceDef(name = "ResourceWithExtensionsA", id="0001")
public class ResourceWithExtensionsA extends DomainResource {
/*
* NB: several unit tests depend on the structure here
* so check the unit tests immediately after any changes
*/
private static final long serialVersionUID = 1L;
@Child(name = "foo1", type = StringType.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://foo/#f1", definedLocally=true, isModifier=false)
private List<StringType> myFoo1;
@Child(name = "foo2", type = StringType.class, order = 1, min = 0, max = 1)
@Extension(url = "http://foo/#f2", definedLocally=true, isModifier=true)
private StringType myFoo2;
@Child(name = "bar1", type = Bar1.class, order = 2, min = 1, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/#b1", definedLocally=true, isModifier=false)
private List<Bar1> myBar1;
@Child(name = "bar2", type = Bar1.class, order = 3, min = 1, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/#b2", definedLocally=true, isModifier=false)
private Bar1 myBar2;
@Child(name="baz", type = CodeableConcept.class, order = 4)
@Extension(url= "http://baz/#baz", definedLocally=true, isModifier=false)
@Description(shortDefinition = "Contains a codeable concept")
private CodeableConcept myBaz;
@Child(name = "identifier", type = Identifier.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
private List<Identifier> myIdentifier;
public List<Bar1> getBar1() {
return myBar1;
}
public Bar1 getBar2() {
return myBar2;
}
public List<StringType> getFoo1() {
return myFoo1;
}
public StringType getFoo2() {
return myFoo2;
}
public CodeableConcept getBaz() { return myBaz; }
public List<Identifier> getIdentifier() {
return myIdentifier;
}
public void setBar1(List<Bar1> theBar1) {
myBar1 = theBar1;
}
public void setBar2(Bar1 theBar2) {
myBar2 = theBar2;
}
public void setFoo1(List<StringType> theFoo1) {
myFoo1 = theFoo1;
}
public void setFoo2(StringType theFoo2) {
myFoo2 = theFoo2;
}
public void setBaz(CodeableConcept myBaz) { this.myBaz = myBaz; }
public void setIdentifier(List<Identifier> theValue) {
myIdentifier = theValue;
}
@Block(name = "Bar1")
public static class Bar1 extends BackboneElement {
public Bar1() {
super();
}
@Child(name = "bar11", type = DateType.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/#b1/1", definedLocally=true, isModifier=false)
private List<DateType> myBar11;
@Child(name = "bar12", type = DateType.class, order = 1, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/#b1/2", definedLocally=true, isModifier=false)
private List<Bar2> myBar12;
@Override
public boolean isEmpty() {
return false; // not implemented
}
public List<DateType> getBar11() {
return myBar11;
}
public List<Bar2> getBar12() {
return myBar12;
}
public void setBar11(List<DateType> theBar11) {
myBar11 = theBar11;
}
public void setBar12(List<Bar2> theBar12) {
myBar12 = theBar12;
}
@Override
public BackboneElement copy() {
// TODO Auto-generated method stub
return null;
}
}
@Block(name = "Bar2")
public static class Bar2 extends BackboneElement {
@Child(name = "bar121", type = DateType.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/#b1/2/1", definedLocally=true, isModifier=false)
private List<DateType> myBar121;
@Child(name = "bar122", type = DateType.class, order = 1, min = 0, max = Child.MAX_UNLIMITED)
@Extension(url = "http://bar/#b1/2/2", definedLocally=true, isModifier=false)
private List<DateType> myBar122;
@Override
public boolean isEmpty() {
return false; // not implemented
}
public List<DateType> getBar121() {
return myBar121;
}
public List<DateType> getBar122() {
return myBar122;
}
public void setBar121(List<DateType> theBar121) {
myBar121 = theBar121;
}
public void setBar122(List<DateType> theBar122) {
myBar122 = theBar122;
}
@Override
public BackboneElement copy() {
// TODO Auto-generated method stub
return null;
}
}
@Override
public boolean isEmpty() {
return false; // not implemented
}
@Override
public DomainResource copy() {
// TODO Auto-generated method stub
return null;
}
@Override
public ResourceType getResourceType() {
// TODO Auto-generated method stub
return null;
}
}

View File

@ -0,0 +1,13 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu3.model.DiagnosticReport;
@ResourceDef(name = "DiagnosticReport", profile = CustomDiagnosticReport.PROFILE)
public class CustomDiagnosticReport extends DiagnosticReport {
public static final String PROFILE = "http://custom_DiagnosticReport";
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,13 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu3.model.Observation;
@ResourceDef(name = "Observation", profile = CustomObservation.PROFILE)
public class CustomObservation extends Observation {
public static final String PROFILE = "http://custom_Observation";
private static final long serialVersionUID = 1L;
}

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu3.model.BooleanType;
import org.hl7.fhir.dstu3.model.Patient;
@ResourceDef(name = "Patient", profile = "Patient")
public class CustomPatientDstu3 extends Patient {
private static final long serialVersionUID = 1L;
@Child(name = "homeless", order = 1)
@Extension(url = "/StructureDefinition/homeless", definedLocally = true, isModifier = false)
@Description(shortDefinition = "The patient being homeless, true if homeless")
private BooleanType homeless;
public BooleanType getHomeless() {
return homeless;
}
public void setHomeless(final BooleanType homeless) {
this.homeless = homeless;
}
}

View File

@ -0,0 +1,46 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.MessageHeader;
import org.hl7.fhir.exceptions.FHIRException;
@ResourceDef(name = "MessageHeader")
public class FooMessageHeader extends MessageHeader {
private static final long serialVersionUID = 1L;
@Block()
public static class FooMessageSourceComponent extends MessageSourceComponent {
private static final long serialVersionUID = 1L;
@Child(name = "ext-messageheader-application-id", type = Identifier.class, modifier = true)
@Description(shortDefinition = "Message Header Application ID")
@Extension(url = "http://foo", definedLocally = false, isModifier = false)
private Identifier messageHeaderApplicationId;
/*
* Get messageHeaderApplicationId
*/
public Identifier getMessageHeaderApplicationId() throws FHIRException {
if (messageHeaderApplicationId == null) {
messageHeaderApplicationId = new Identifier();
}
return messageHeaderApplicationId;
}
/*
* Set messageHeaderApplicationId
*/
public void setmessageHeaderApplicationId(Identifier messageHeaderApplicationId) {
this.messageHeaderApplicationId = messageHeaderApplicationId;
}
}
}

View File

@ -0,0 +1,57 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.MessageHeader;
import org.hl7.fhir.exceptions.FHIRException;
@ResourceDef(name = "FooMessageHeader")
public class FooMessageHeaderWithExplicitField extends MessageHeader {
private static final long serialVersionUID = 1L;
/**
* The source application from which this message originated.
*/
@Child(name = "source", type = {}, order = Child.REPLACE_PARENT, min = 1, max = 1, modifier = false, summary = true)
@Description(shortDefinition = "Message Source Application", formalDefinition = "The source application from which this message originated.")
protected FooMessageSourceComponent source;
public void setSourceNew(FooMessageSourceComponent theSource) {
source = theSource;
}
@Block()
public static class FooMessageSourceComponent extends MessageSourceComponent {
private static final long serialVersionUID = 1L;
@Child(name = "ext-messageheader-application-id", type = Identifier.class, modifier = true)
@Description(shortDefinition = "Message Header Application ID")
@Extension(url = "http://foo", definedLocally = false, isModifier = false)
private Identifier messageHeaderApplicationId;
/*
* Get messageHeaderApplicationId
*/
public Identifier getMessageHeaderApplicationId() throws FHIRException {
if (messageHeaderApplicationId == null) {
messageHeaderApplicationId = new Identifier();
}
return messageHeaderApplicationId;
}
/*
* Set messageHeaderApplicationId
*/
public void setmessageHeaderApplicationId(Identifier messageHeaderApplicationId) {
this.messageHeaderApplicationId = messageHeaderApplicationId;
}
}
}

View File

@ -0,0 +1,52 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.StringType;
@ResourceDef()
public class MyPatientWithCustomUrlExtension extends Patient {
private static final long serialVersionUID = 1L;
@Child(name = "petName")
@Extension(url = "/petname", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The name of the patient's favourite pet")
private StringType myPetName;
@Child(name = "customid")
@Extension(url = "/customid", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The customid of the patient's ")
private IdType myCustomId;
public StringType getPetName() {
if (myPetName == null) {
myPetName = new StringType();
}
return myPetName;
}
public void setPetName(final StringType thePetName) {
myPetName = thePetName;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && getCustomId().isEmpty() && getPetName().isEmpty();
}
public IdType getCustomId() {
if (myCustomId == null) {
myCustomId = new IdType();
}
return myCustomId;
}
public void setCustomId(final IdType myCustomId) {
this.myCustomId = myCustomId;
}
}

View File

@ -0,0 +1,66 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import java.util.List;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import org.hl7.fhir.dstu3.model.Address.AddressUse;
import org.hl7.fhir.dstu3.model.Enumeration;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.Patient;
@ResourceDef(name = "Patient")
public class MyPatientWithOneDeclaredEnumerationExtensionDstu3 extends Patient {
private static final long serialVersionUID = 1L;
@Child(order = 0, name = "foo")
@Extension(url = "urn:foo", definedLocally = true, isModifier = false)
private Enumeration<AddressUse> myFoo;
/**
* A contact party (e.g. guardian, partner, friend) for the patient.
*/
@Child(name = "contact", type = {}, order=Child.REPLACE_PARENT, min=0, max=Child.MAX_UNLIMITED, modifier=false, summary=false)
@Description(shortDefinition="A contact party (e.g. guardian, partner, friend) for the patient", formalDefinition="A contact party (e.g. guardian, partner, friend) for the patient." )
protected List<ContactComponent> contact;
public Enumeration<AddressUse> getFoo() {
return myFoo;
}
public void setFoo(Enumeration<AddressUse> theFoo) {
myFoo = theFoo;
}
@Block()
public static class MessageSourceComponent extends ContactComponent {
private static final long serialVersionUID = 1L;
@Child(name = "contact-eyecolour", type = { Identifier.class }, modifier = true)
@Description(shortDefinition = "Application ID")
@Extension(url = "http://foo.com/contact-eyecolour", definedLocally = false, isModifier = false)
private Identifier myEyeColour;
/*
* Get messageHeaderApplicationId
*/
public Identifier getEyeColour() {
if (myEyeColour == null) {
myEyeColour = new Identifier();
}
return myEyeColour;
}
/*
* Set messageHeaderApplicationId
*/
public void setEyeColour(Identifier messageHeaderApplicationId) {
this.myEyeColour = messageHeaderApplicationId;
}
}
}

View File

@ -0,0 +1,72 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.util.ElementUtil;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.Reference;
@ResourceDef(name="Patient", profile = "http://hl7.org/fhir/StructureDefinition/Patient")
public class PatientProfileDstu3 extends Patient {
private static final long serialVersionUID = 1L;
@Child(name="owner", min=0, max=1)
@Extension(url="http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#owningOrganization", definedLocally=false, isModifier=false)
@Description(shortDefinition="The organization that owns this animal")
private Reference owningOrganization;
public Reference getOwningOrganization() {
if (owningOrganization == null) {
owningOrganization = new Reference();
}
return owningOrganization;
}
public PatientProfileDstu3 setOwningOrganization(Reference owningOrganization) {
this.owningOrganization = owningOrganization;
return this;
}
@Child(name="colorPrimary", min=0, max=1)
@Extension(url="http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#animal-colorPrimary", definedLocally=false, isModifier=false)
@Description(shortDefinition="The animals primary color")
private CodeableConcept colorPrimary;
@Child(name="colorSecondary", min=0, max=1)
@Extension(url="http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#animal-colorSecondary", definedLocally=false, isModifier=false)
@Description(shortDefinition="The animals secondary color")
private CodeableConcept colorSecondary;
public CodeableConcept getColorPrimary() {
if (this.colorPrimary == null) {
return new CodeableConcept();
}
return colorPrimary;
}
public void setColorPrimary(CodeableConcept colorPrimary) {
this.colorPrimary = colorPrimary;
}
public CodeableConcept getColorSecondary() {
if (this.colorSecondary == null) {
return new CodeableConcept();
}
return colorSecondary;
}
public void setColorSecondary(CodeableConcept colorSecondary) {
this.colorSecondary = colorSecondary;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(owningOrganization) && ElementUtil.isEmpty(colorPrimary)
&& ElementUtil.isEmpty(colorSecondary) ;
}
}

View File

@ -0,0 +1,81 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.model.api.annotation.Block;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.util.ElementUtil;
import org.hl7.fhir.dstu3.model.BackboneElement;
import org.hl7.fhir.dstu3.model.Patient;
import org.hl7.fhir.dstu3.model.StringType;
@ResourceDef(name = "Patient")
public class PatientWithCustomCompositeExtension extends Patient {
private static final long serialVersionUID = 1L;
/**
* A custom extension
*/
@Child(name = "foo")
@Extension(url="http://acme.org/fooParent", definedLocally = false, isModifier = false)
protected FooParentExtension fooParentExtension;
public FooParentExtension getFooParentExtension() {
return fooParentExtension;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(fooParentExtension);
}
public void setFooParentExtension(FooParentExtension theFooParentExtension) {
fooParentExtension = theFooParentExtension;
}
@Block
public static class FooParentExtension extends BackboneElement {
private static final long serialVersionUID = 4522090347756045145L;
@Child(name = "childA")
@Extension(url = "http://acme.org/fooChildA", definedLocally = false, isModifier = false)
private StringType myChildA;
@Child(name = "childB")
@Extension(url = "http://acme.org/fooChildB", definedLocally = false, isModifier = false)
private StringType myChildB;
@Override
public FooParentExtension copy() {
FooParentExtension copy = new FooParentExtension();
copy.myChildA = myChildA;
copy.myChildB = myChildB;
return copy;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(myChildA, myChildB);
}
public StringType getChildA() {
return myChildA;
}
public StringType getChildB() {
return myChildB;
}
public void setChildA(StringType theChildA) {
myChildA = theChildA;
}
public void setChildB(StringType theChildB) {
myChildB = theChildB;
}
}
}

View File

@ -0,0 +1,410 @@
package ca.uhn.fhir.tests.integration.karaf.dstu3;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.StrictErrorHandler;
import ca.uhn.fhir.validation.*;
import ca.uhn.fhir.validation.schematron.SchematronBaseValidator;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.Validate;
import org.hamcrest.core.StringContains;
import org.hl7.fhir.dstu3.conformance.ProfileUtilities;
import org.hl7.fhir.dstu3.context.IWorkerContext;
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.dstu3.hapi.validation.DefaultProfileValidationSupport;
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.utilities.validation.ValidationMessage;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_VALIDATION_DSTU3;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;
/**
* Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class ResourceValidatorDstu3FeatureTest {
private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceValidatorDstu3FeatureTest.class);
private FhirContext ourCtx = FhirContext.forDstu3();
@Configuration
public Option[] config() throws IOException {
return options(
KARAF.option(),
HAPI_FHIR_VALIDATION_DSTU3.option(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
WRAP.option(),
when(false)
.useOptions(
debugConfiguration("5005", true))
);
}
private List<SingleValidationMessage> logResultsAndReturnNonInformationalOnes(ValidationResult theOutput) {
List<SingleValidationMessage> retVal = new ArrayList<>();
int index = 0;
for (SingleValidationMessage next : theOutput.getMessages()) {
ourLog.info("Result {}: {} - {} - {}",
new Object[]{index, next.getSeverity(), next.getLocationString(), next.getMessage()});
index++;
if (next.getSeverity() != ResultSeverityEnum.INFORMATION) {
retVal.add(next);
}
}
return retVal;
}
/**
* See issue #50
*/
@Test
public void testOutOfBoundsDate() {
Patient p = new Patient();
p.setBirthDateElement(new DateType("2000-12-31"));
// Put in an invalid date
IParser parser = ourCtx.newXmlParser();
parser.setParserErrorHandler(new StrictErrorHandler());
String encoded = parser.setPrettyPrint(true).encodeResourceToString(p).replace("2000-12-31", "2000-15-31");
ourLog.info(encoded);
assertThat(encoded, StringContains.containsString("2000-15-31"));
ValidationResult result = ourCtx.newValidator().validateWithResult(encoded);
String resultString = parser.setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(resultString);
assertEquals(2, ((OperationOutcome) result.toOperationOutcome()).getIssue().size());
assertThat(resultString, StringContains.containsString("cvc-pattern-valid"));
try {
parser.parseResource(encoded);
fail();
} catch (DataFormatException e) {
assertEquals("DataFormatException at [[row,col {unknown-source}]: [2,4]]: Invalid attribute value \"2000-15-31\": Invalid date/time format: \"2000-15-31\"", e.getMessage());
}
}
@Test
public void testValidateCareTeamXsd() {
CareTeam careTeam = new CareTeam();
careTeam
.addParticipant()
.setMember(new Reference("http://example.com/Practitioner/1647bbb2-3b12-43cc-923c-a475f817e881"))
.setOnBehalfOf(new Reference("Organization/5859a28f-01e7-42d8-a8ba-48b31679a828"));
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
String encoded = parser.encodeResourceToString(careTeam);
ourLog.info(encoded);
FhirValidator val = ourCtx.newValidator();
ValidationResult result = val.validateWithResult(encoded);
String resultString = parser.setPrettyPrint(true).encodeResourceToString(result.toOperationOutcome());
ourLog.info(resultString);
assertThat(resultString, containsString("No issues detected during validation"));
}
@Test
public void testValidateCodeableConceptContainingOnlyBadCode() {
Patient p = new Patient();
p.getMaritalStatus().addCoding().setSystem("http://hl7.org/fhir/v3/MaritalStatus").setCode("FOO");
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
val.registerValidatorModule(new FhirInstanceValidator());
ValidationResult output = val.validateWithResult(p);
List<SingleValidationMessage> all = logResultsAndReturnNonInformationalOnes(output);
assertEquals("None of the codes provided are in the value set http://hl7.org/fhir/ValueSet/marital-status (http://hl7.org/fhir/ValueSet/marital-status, and a code should come from this value set unless it has no suitable code) (codes = http://hl7.org/fhir/v3/MaritalStatus#FOO)", output.getMessages().get(0).getMessage());
assertEquals(ResultSeverityEnum.WARNING, output.getMessages().get(0).getSeverity());
}
@Test
public void testValidateCodeableConceptContainingOnlyGoodCode() {
Patient p = new Patient();
p.getMaritalStatus().addCoding().setSystem("http://hl7.org/fhir/v3/MaritalStatus").setCode("M");
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
val.registerValidatorModule(new FhirInstanceValidator());
ValidationResult output = val.validateWithResult(p);
List<SingleValidationMessage> all = logResultsAndReturnNonInformationalOnes(output);
assertEquals(0, all.size());
assertEquals(0, output.getMessages().size());
}
@Test
public void testValidateJsonNumericId() {
String input = "{\"resourceType\": \"Patient\",\n" +
" \"id\": 123,\n" +
" \"meta\": {\n" +
" \"versionId\": \"29\",\n" +
" \"lastUpdated\": \"2015-12-22T19:53:11.000Z\"\n" +
" },\n" +
" \"communication\": {\n" +
" \"language\": {\n" +
" \"coding\": [\n" +
" {\n" +
" \"system\": \"urn:ietf:bcp:47\",\n" +
" \"code\": \"hi\",\n" +
" \"display\": \"Hindi\",\n" +
" \"userSelected\": false\n" +
" }],\n" +
" \"text\": \"Hindi\"\n" +
" },\n" +
" \"preferred\": true\n" +
" }\n" +
"}";
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new FhirInstanceValidator());
ValidationResult output = val.validateWithResult(input);
OperationOutcome operationOutcome = (OperationOutcome) output.toOperationOutcome();
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
// ourLog.info(encoded);
assertThat(encoded, containsString("Error parsing JSON: the primitive value must be a string"));
}
@Test
public void testValidateQuestionnaireWithCanonicalUrl() {
String input = "{\n" +
" \"resourceType\": \"Questionnaire\",\n" +
" \"url\": \"http://some.example.url\",\n" +
" \"status\": \"active\",\n" +
" \"subjectType\": [\n" +
" \"Patient\"\n" +
" ],\n" +
" \"item\": [\n" +
" {\n" +
" \"linkId\": \"example-question\",\n" +
" \"text\": \"Is the sky blue?\",\n" +
" \"type\": \"choice\",\n" +
" \"options\": {\n" +
" \"reference\": \"http://loinc.org/vs/LL3044-6\"\n" +
" }\n" +
" }\n" +
" ]\n" +
"}";
Questionnaire q = new Questionnaire();
q = ourCtx.newJsonParser().parseResource(Questionnaire.class, input);
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
val.registerValidatorModule(new FhirInstanceValidator());
ValidationResult result = val.validateWithResult(q);
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
ourLog.info(encoded);
}
/**
* Make sure that the elements that appear in all resources (meta, language, extension, etc) all appear in the correct order
*/
@Test
public void testValidateResourceWithResourceElements() {
TestPatientFor327 patient = new TestPatientFor327();
patient.setBirthDate(new Date());
patient.setId("123");
patient.getText().setDivAsString("<div>FOO</div>");
patient.getText().setStatus(Narrative.NarrativeStatus.GENERATED);
patient.getLanguageElement().setValue("en");
patient.addExtension().setUrl("http://foo").setValue(new StringType("MOD"));
patient.getMeta().setLastUpdated(new Date());
List<Reference> conditions = new ArrayList<Reference>();
Condition condition = new Condition();
condition.getSubject().setReference("Patient/123");
condition.addBodySite().setText("BODY SITE");
condition.getCode().setText("CODE");
condition.setClinicalStatus(Condition.ConditionClinicalStatus.ACTIVE);
condition.setVerificationStatus(Condition.ConditionVerificationStatus.CONFIRMED);
conditions.add(new Reference(condition));
patient.setCondition(conditions);
patient.addIdentifier().setSystem("http://foo").setValue("123");
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient);
ourLog.info(encoded);
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
val.registerValidatorModule(new FhirInstanceValidator());
ValidationResult result = val.validateWithResult(encoded);
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
String ooencoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
ourLog.info(ooencoded);
assertTrue(result.isSuccessful());
assertThat(ooencoded, containsString("Unknown extension http://foo"));
}
/**
* See https://groups.google.com/d/msgid/hapi-fhir/a266083f-6454-4cf0-a431-c6500f052bea%40googlegroups.com?utm_medium= email&utm_source=footer
*/
@Test
public void testValidateWithExtensionsJson() {
PatientProfileDstu3 myPatient = new PatientProfileDstu3();
myPatient.setId("1");
myPatient.setColorPrimary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-grey")));
myPatient.setColorSecondary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-white")));
myPatient.setOwningOrganization(new Reference("Organization/2.25.79433498044103547197447759549862032393"));
myPatient.addName().setFamily("FamilyName");
myPatient.addExtension().setUrl("http://foo.com/example").setValue(new StringType("String Extension"));
IParser p = ourCtx.newJsonParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(myPatient);
// ourLog.info(messageString);
String[] strings = {"meta",
"String Extension",
"Organization/2.25.79433498044103547197447759549862032393",
"furry-grey",
"furry-white",
"FamilyName"};
assertThat(messageString, stringContainsInOrder(
Arrays.asList(strings)
));
String[] strings1 = {"extension",
"meta"};
assertThat(messageString, not(stringContainsInOrder(
Arrays.asList(strings1)
)));
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
val.registerValidatorModule(new FhirInstanceValidator());
ValidationResult result = val.validateWithResult(messageString);
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
ourLog.info(encoded);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("valueReference"));
assertThat(messageString, not(containsString("valueResource")));
}
/**
* See https://groups.google.com/d/msgid/hapi-fhir/a266083f-6454-4cf0-a431-c6500f052bea%40googlegroups.com?utm_medium= email&utm_source=footer
*/
@Test
public void testValidateWithExtensionsXml() {
PatientProfileDstu3 myPatient = new PatientProfileDstu3();
myPatient.setId("1");
myPatient.setColorPrimary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-grey")));
myPatient.setColorSecondary(new CodeableConcept().addCoding(new Coding().setSystem("http://example.com#animalColor").setCode("furry-white")));
myPatient.setOwningOrganization(new Reference("Organization/2.25.79433498044103547197447759549862032393"));
myPatient.addName().setFamily("FamilyName");
myPatient.addExtension().setUrl("http://foo.com/example").setValue(new StringType("String Extension"));
IParser p = ourCtx.newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(myPatient);
ourLog.info(messageString);
//@formatter:off
String[] strings = {"meta",
"Organization/2.25.79433498044103547197447759549862032393",
"furry-grey",
"furry-white",
"String Extension",
"FamilyName"};
assertThat(messageString, stringContainsInOrder(
Arrays.asList(strings)
));
String[] strings1 = {"extension",
"meta"};
assertThat(messageString, not(stringContainsInOrder(
Arrays.asList(strings1)
)));
assertThat(messageString, containsString("url=\"http://ahr.copa.inso.tuwien.ac.at/StructureDefinition/Patient#animal-colorSecondary\""));
assertThat(messageString, containsString("url=\"http://foo.com/example\""));
//@formatter:on
FhirValidator val = ourCtx.newValidator();
val.registerValidatorModule(new SchemaBaseValidator(ourCtx));
val.registerValidatorModule(new SchematronBaseValidator(ourCtx));
val.registerValidatorModule(new FhirInstanceValidator());
ValidationResult result = val.validateWithResult(messageString);
OperationOutcome operationOutcome = (OperationOutcome) result.toOperationOutcome();
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome);
ourLog.info(encoded);
assertTrue(result.isSuccessful());
assertThat(messageString, containsString("valueReference"));
assertThat(messageString, not(containsString("valueResource")));
}
@ResourceDef(name = "Patient")
public static class TestPatientFor327 extends Patient {
private static final long serialVersionUID = 1L;
@Child(name = "testCondition")
@ca.uhn.fhir.model.api.annotation.Extension(url = "testCondition", definedLocally = true, isModifier = false)
private List<Reference> testConditions = null;
public List<Reference> getConditions() {
return this.testConditions;
}
public void setCondition(List<Reference> ref) {
this.testConditions = ref;
}
}
}

View File

@ -0,0 +1,114 @@
package ca.uhn.fhir.tests.integration.karaf.r4;
import java.io.IOException;
import java.util.List;
import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
import org.hl7.fhir.r4.model.Base;
import org.hl7.fhir.r4.model.BooleanType;
import org.hl7.fhir.r4.model.Observation;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.StringType;
import org.hl7.fhir.r4.model.StructureDefinition;
import org.hl7.fhir.r4.utils.FHIRPathEngine;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_VALIDATION_R4;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;
/**
* Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class FhirInstanceValidatorR4Test {
private FhirContext ourCtx = FhirContext.forR4();
private FHIRPathEngine ourEngine = new FHIRPathEngine(new HapiWorkerContext(ourCtx, new DefaultProfileValidationSupport()));
private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirInstanceValidatorR4Test.class);
@Configuration
public Option[] config() throws IOException {
return options(
KARAF.option(),
HAPI_FHIR_VALIDATION_R4.option(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
WRAP.option(),
when(false)
.useOptions(
debugConfiguration("5005", true))
);
}
@Test
public void testAs() throws Exception {
Observation obs = new Observation();
obs.setValue(new StringType("FOO"));
List<Base> value = ourEngine.evaluate(obs, "Observation.value.as(String)");
assertEquals(1, value.size());
assertEquals("FOO", ((StringType)value.get(0)).getValue());
}
@Test
public void testExistsWithNoValue() throws FHIRException {
Patient patient = new Patient();
patient.setDeceased(new BooleanType());
List<Base> eval = ourEngine.evaluate(patient, "Patient.deceased.exists()");
ourLog.info(eval.toString());
assertFalse(((BooleanType)eval.get(0)).getValue());
}
@Test
public void testExistsWithValue() throws FHIRException {
Patient patient = new Patient();
patient.setDeceased(new BooleanType(false));
List<Base> eval = ourEngine.evaluate(patient, "Patient.deceased.exists()");
ourLog.info(eval.toString());
assertTrue(((BooleanType)eval.get(0)).getValue());
}
@Test
public void testConcatenation() throws FHIRException {
String exp = "Patient.name.family & '.'";
Patient p = new Patient();
p.addName().setFamily("TEST");
String result = ourEngine.evaluateToString(p, exp);
assertEquals("TEST.", result);
}
@Test
public void testConcatenationFunction() throws FHIRException {
String exp = "element.first().path.startsWith(%resource.type) and element.tail().all(path.startsWith(%resource.type&'.'))";
StructureDefinition sd = new StructureDefinition();
StructureDefinition.StructureDefinitionDifferentialComponent diff = sd.getDifferential();
diff.addElement().setPath("Patient.name");
Patient p = new Patient();
p.addName().setFamily("TEST");
List<Base> result = ourEngine.evaluate(null, p, diff, exp);
ourLog.info(result.toString());
// assertEquals("TEST.", result);
}
}

View File

@ -0,0 +1,275 @@
package ca.uhn.fhir.tests.integration.karaf.r4;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import com.google.common.collect.Sets;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Extension;
import org.hl7.fhir.r4.model.Medication;
import org.hl7.fhir.r4.model.MedicationDispense;
import org.hl7.fhir.r4.model.MedicationRequest;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.hl7.fhir.r4.model.StringType;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_R4;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.core.IsNot.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;
/**
* Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class R4JsonParserTest {
private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(R4JsonParserTest.class);
private FhirContext ourCtx = FhirContext.forR4();
@Configuration
public Option[] config() throws IOException {
return options(
KARAF.option(),
WRAP.option(),
HAPI_FHIR_R4.option(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
when(false)
.useOptions(
debugConfiguration("5005", true))
);
}
private Bundle createBundleWithPatient() {
Bundle b = new Bundle();
b.setId("BUNDLEID");
b.getMeta().addProfile("http://FOO");
Patient p = new Patient();
p.setId("PATIENTID");
p.getMeta().addProfile("http://BAR");
p.addName().addGiven("GIVEN");
b.addEntry().setResource(p);
return b;
}
/**
* See #814
*/
@Test
public void testDuplicateContainedResourcesNotOutputtedTwice() {
MedicationDispense md = new MedicationDispense();
MedicationRequest mr = new MedicationRequest();
md.addAuthorizingPrescription().setResource(mr);
Medication med = new Medication();
md.setMedication(new Reference(med));
mr.setMedication(new Reference(med));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(md);
ourLog.info(encoded);
int idx = encoded.indexOf("\"Medication\"");
assertNotEquals(-1, idx);
idx = encoded.indexOf("\"Medication\"", idx + 1);
assertEquals(-1, idx);
}
/**
* See #814
*/
@Test
public void testDuplicateContainedResourcesNotOutputtedTwiceWithManualIds() {
MedicationDispense md = new MedicationDispense();
MedicationRequest mr = new MedicationRequest();
mr.setId("#MR");
md.addAuthorizingPrescription().setResource(mr);
Medication med = new Medication();
med.setId("#MED");
md.setMedication(new Reference(med));
mr.setMedication(new Reference(med));
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(md);
ourLog.info(encoded);
int idx = encoded.indexOf("\"Medication\"");
assertNotEquals(-1, idx);
idx = encoded.indexOf("\"Medication\"", idx + 1);
assertEquals(-1, idx);
}
@Test
public void testExcludeNothing() {
IParser parser = ourCtx.newJsonParser().setPrettyPrint(true);
Set<String> excludes = new HashSet<>();
// excludes.add("*.id");
parser.setDontEncodeElements(excludes);
Bundle b = createBundleWithPatient();
String encoded = parser.encodeResourceToString(b);
ourLog.info(encoded);
assertThat(encoded, containsString("BUNDLEID"));
assertThat(encoded, containsString("http://FOO"));
assertThat(encoded, containsString("PATIENTID"));
assertThat(encoded, containsString("http://BAR"));
assertThat(encoded, containsString("GIVEN"));
b = parser.parseResource(Bundle.class, encoded);
assertEquals("BUNDLEID", b.getIdElement().getIdPart());
assertEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
@Test
public void testExcludeRootStuff() {
IParser parser = ourCtx.newJsonParser().setPrettyPrint(true);
Set<String> excludes = new HashSet<>();
excludes.add("id");
excludes.add("meta");
parser.setDontEncodeElements(excludes);
Bundle b = createBundleWithPatient();
String encoded = parser.encodeResourceToString(b);
ourLog.info(encoded);
assertThat(encoded, not(containsString("BUNDLEID")));
assertThat(encoded, not(containsString("http://FOO")));
assertThat(encoded, (containsString("PATIENTID")));
assertThat(encoded, (containsString("http://BAR")));
assertThat(encoded, containsString("GIVEN"));
b = parser.parseResource(Bundle.class, encoded);
assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
assertEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
@Test
public void testExcludeStarDotStuff() {
IParser parser = ourCtx.newJsonParser().setPrettyPrint(true);
Set<String> excludes = new HashSet<>();
excludes.add("*.id");
excludes.add("*.meta");
parser.setDontEncodeElements(excludes);
Bundle b = createBundleWithPatient();
String encoded = parser.encodeResourceToString(b);
ourLog.info(encoded);
assertThat(encoded, not(containsString("BUNDLEID")));
assertThat(encoded, not(containsString("http://FOO")));
assertThat(encoded, not(containsString("PATIENTID")));
assertThat(encoded, not(containsString("http://BAR")));
assertThat(encoded, containsString("GIVEN"));
b = parser.parseResource(Bundle.class, encoded);
assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
assertNotEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
/**
* Test that long JSON strings don't get broken up
*/
@Test
public void testNoBreakInLongString() {
String longString = StringUtils.leftPad("", 100000, 'A');
Patient p = new Patient();
p.addName().setFamily(longString);
String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(p);
assertThat(encoded, containsString(longString));
}
@Test
public void testParseAndEncodeExtensionWithValueWithExtension() {
String input = "{\n" +
" \"resourceType\": \"Patient\",\n" +
" \"extension\": [\n" +
" {\n" +
" \"url\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/BirthWeight\",\n" +
" \"_valueDecimal\": {\n" +
" \"extension\": [\n" +
" {\n" +
" \"url\": \"http://www.hl7.org/fhir/extension-data-absent-reason.html\",\n" +
" \"valueCoding\": {\n" +
" \"system\": \"http://hl7.org/fhir/ValueSet/birthweight\",\n" +
" \"code\": \"Underweight\",\n" +
" \"userSelected\": false\n" +
" }\n" +
" }\n" +
" ]\n" +
" }\n" +
" }\n" +
" ],\n" +
" \"identifier\": [\n" +
" {\n" +
" \"system\": \"https://purl.org/elab/fhir/network/StructureDefinition/1/EuroPrevallStudySubjects\",\n" +
" \"value\": \"1\"\n" +
" }\n" +
" ],\n" +
" \"gender\": \"female\"\n" +
"}";
IParser jsonParser = ourCtx.newJsonParser();
IParser xmlParser = ourCtx.newXmlParser();
jsonParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
xmlParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
Patient parsed = jsonParser.parseResource(Patient.class, input);
ourLog.info(jsonParser.setPrettyPrint(true).encodeResourceToString(parsed));
assertThat(xmlParser.encodeResourceToString(parsed), containsString("Underweight"));
assertThat(jsonParser.encodeResourceToString(parsed), containsString("Underweight"));
}
@Test
public void testParseExtensionOnPrimitive() throws IOException {
String input = IOUtils.toString(R4JsonParserTest.class.getResourceAsStream("/extension-on-line.txt"));
IParser parser = ourCtx.newJsonParser().setPrettyPrint(true);
Patient pt = parser.parseResource(Patient.class, input);
StringType line0 = pt.getAddressFirstRep().getLine().get(0);
assertEquals("535 Sheppard Avenue West, Unit 1907", line0.getValue());
Extension houseNumberExt = line0.getExtensionByUrl("http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-houseNumber");
assertEquals("535", ((StringType) houseNumberExt.getValue()).getValue());
}
}

View File

@ -0,0 +1,195 @@
package ca.uhn.fhir.tests.integration.karaf.r4;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.parser.IParser;
import com.google.common.collect.Sets;
import org.hamcrest.core.IsNot;
import org.hl7.fhir.r4.model.Bundle;
import org.hl7.fhir.r4.model.Patient;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.ops4j.pax.exam.Configuration;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.junit.PaxExam;
import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
import org.ops4j.pax.exam.spi.reactors.PerClass;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.HAPI_FHIR_R4;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.KARAF;
import static ca.uhn.fhir.tests.integration.karaf.PaxExamOptions.WRAP;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.options;
import static org.ops4j.pax.exam.CoreOptions.when;
import static org.ops4j.pax.exam.karaf.options.KarafDistributionOption.debugConfiguration;
/**
* Useful docs about this test: https://ops4j1.jira.com/wiki/display/paxexam/FAQ
*/
@RunWith(PaxExam.class)
@ExamReactorStrategy(PerClass.class)
public class R4XmlParserTest {
private final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(R4XmlParserTest.class);
private FhirContext ourCtx = FhirContext.forR4();
@Configuration
public Option[] config() throws IOException {
return options(
KARAF.option(),
WRAP.option(),
HAPI_FHIR_R4.option(),
mavenBundle().groupId("org.apache.servicemix.bundles").artifactId("org.apache.servicemix.bundles.hamcrest").versionAsInProject(),
when(false)
.useOptions(
debugConfiguration("5005", true))
);
}
private Bundle createBundleWithPatient() {
Bundle b = new Bundle();
b.setId("BUNDLEID");
b.getMeta().addProfile("http://FOO");
Patient p = new Patient();
p.setId("PATIENTID");
p.getMeta().addProfile("http://BAR");
p.addName().addGiven("GIVEN");
b.addEntry().setResource(p);
return b;
}
@Test
public void testParseAndEncodeXmlNumericEntity() {
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
" <name>\n" +
" <family value=\"A &#xA; B\"/>\n" +
" </name>\n" +
"</Patient>";
Patient p = ourCtx.newXmlParser().parseResource(Patient.class, input);
assertEquals("A \n B", p.getNameFirstRep().getFamily());
String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(p);
ourLog.info(output);
}
@Test
public void testExcludeNothing() {
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
Set<String> excludes = new HashSet<>();
// excludes.add("*.id");
parser.setDontEncodeElements(excludes);
Bundle b = createBundleWithPatient();
String encoded = parser.encodeResourceToString(b);
ourLog.info(encoded);
assertThat(encoded, containsString("BUNDLEID"));
assertThat(encoded, containsString("http://FOO"));
assertThat(encoded, containsString("PATIENTID"));
assertThat(encoded, containsString("http://BAR"));
assertThat(encoded, containsString("GIVEN"));
b = parser.parseResource(Bundle.class, encoded);
assertEquals("BUNDLEID", b.getIdElement().getIdPart());
assertEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
@Test
public void testExcludeRootStuff() {
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
Set<String> excludes = new HashSet<>();
excludes.add("id");
excludes.add("meta");
parser.setDontEncodeElements(excludes);
Bundle b = createBundleWithPatient();
String encoded = parser.encodeResourceToString(b);
ourLog.info(encoded);
assertThat(encoded, IsNot.not(containsString("BUNDLEID")));
assertThat(encoded, IsNot.not(containsString("http://FOO")));
assertThat(encoded, (containsString("PATIENTID")));
assertThat(encoded, (containsString("http://BAR")));
assertThat(encoded, containsString("GIVEN"));
b = parser.parseResource(Bundle.class, encoded);
assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
assertEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
@Test
public void testExcludeStarDotStuff() {
IParser parser = ourCtx.newXmlParser().setPrettyPrint(true);
Set<String> excludes = new HashSet<>();
excludes.add("*.id");
excludes.add("*.meta");
parser.setDontEncodeElements(excludes);
Bundle b = createBundleWithPatient();
String encoded = parser.encodeResourceToString(b);
ourLog.info(encoded);
assertThat(encoded, IsNot.not(containsString("BUNDLEID")));
assertThat(encoded, IsNot.not(containsString("http://FOO")));
assertThat(encoded, IsNot.not(containsString("PATIENTID")));
assertThat(encoded, IsNot.not(containsString("http://BAR")));
assertThat(encoded, containsString("GIVEN"));
b = parser.parseResource(Bundle.class, encoded);
assertNotEquals("BUNDLEID", b.getIdElement().getIdPart());
assertNotEquals("Patient/PATIENTID", ((Patient) b.getEntry().get(0).getResource()).getId());
assertEquals("GIVEN", ((Patient) b.getEntry().get(0).getResource()).getNameFirstRep().getGivenAsSingleString());
}
@Test
public void testParseAndEncodeExtensionWithValueWithExtension() {
String input = "<Patient xmlns=\"http://hl7.org/fhir\">\n" +
" <extension url=\"https://purl.org/elab/fhir/network/StructureDefinition/1/BirthWeight\">\n" +
" <valueDecimal>\n" +
" <extension url=\"http://www.hl7.org/fhir/extension-data-absent-reason.html\">\n" +
" <valueCoding>\n" +
" <system value=\"http://hl7.org/fhir/ValueSet/birthweight\"/>\n" +
" <code value=\"Underweight\"/>\n" +
" <userSelected value=\"false\"/>\n" +
" </valueCoding>\n" +
" </extension>\n" +
" </valueDecimal>\n" +
" </extension>\n" +
" <identifier>\n" +
" <system value=\"https://purl.org/elab/fhir/network/StructureDefinition/1/EuroPrevallStudySubjects\"/>\n" +
" <value value=\"1\"/>\n" +
" </identifier>\n" +
" <gender value=\"female\"/>\n" +
"</Patient>";
IParser xmlParser = ourCtx.newXmlParser();
IParser jsonParser = ourCtx.newJsonParser();
jsonParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
xmlParser.setDontEncodeElements(Sets.newHashSet("id", "meta"));
Patient parsed = xmlParser.parseResource(Patient.class, input);
ourLog.info(jsonParser.setPrettyPrint(true).encodeResourceToString(parsed));
assertThat(xmlParser.encodeResourceToString(parsed), containsString("Underweight"));
assertThat(jsonParser.encodeResourceToString(parsed), containsString("Underweight"));
}
}

View File

@ -0,0 +1,53 @@
{
"resourceType": "Bundle",
"id": "example",
"meta": {
"versionId": "1",
"lastUpdated": "2014-08-18T01:43:30Z"
},
"type": "searchset",
"total": 3,
"link": [
{
"relation": "next",
"url": "https://example.com/base/MedicationOrder?patient=347&searchId=ff15fd40-ff71-4b48-b366-09c706bed9d0&page=2"
},
{
"relation": "self",
"url": "https://example.com/base/MedicationOrder?patient=347&_include=MedicationOrder.medication"
}
],
"entry": [
{
"fullUrl": "http://example.com/base/MedicationOrder/3123/_history/1",
"resource": {
"resourceType": "MedicationOrder",
"id": "3123",
"meta" : {
"versionId" : "1",
"lastUpdated" : "2014-08-16T05:31:17Z"
},
"patient": {
"reference": "Patient/347"
},
"medicationReference": {
"reference": "Medication/example"
}
},
"search": {
"mode": "match",
"score": 1
}
},
{
"fullUrl": "http://example.com/base/Medication/example",
"resource": {
"resourceType": "Medication",
"id": "example"
},
"search": {
"mode": "include"
}
}
]
}

View File

@ -0,0 +1,72 @@
<Bundle
xmlns="http://hl7.org/fhir">
<id value="487d3669-0e1c-4867-b124-400d1849548d"></id>
<type value="searchset"></type>
<base value="http://localhost:19080/fhir/dstu1"></base>
<link>
<relation value="just trying add link"></relation>
<url value="blarion"></url>
</link>
<link>
<relation value="self"></relation>
<url value="http://localhost:19080/fhir/dstu1/Observation?subject.identifier=puppet|CLONE-AA102"></url>
</link>
<entry>
<link>
<relation value="orionhealth.edit"></relation>
<url value="Observation"></url>
</link>
<resource>
<Observation
xmlns="http://hl7.org/fhir">
<id value="0d87f02c-da2c-4551-9ead-2956f0165a4f"></id>
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
</extension>
<code>
<coding>
<system value="http://loinc.org"></system>
<code value="8867-4"></code>
</coding>
</code>
<valueString value="observationValue"></valueString>
<status value="final"></status>
<reliability value="ok"></reliability>
<subject>
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
</subject>
</Observation>
</resource>
</entry>
<entry>
<link>
<relation value="orionhealth.edit"></relation>
<url value="Observation"></url>
</link>
<resource>
<Observation
xmlns="http://hl7.org/fhir">
<id value="c54ac0cc-a99f-40aa-9541-c5aa853a2e88"></id>
<extension url="http://orionhealth.com/fhir/extensions#created-by"></extension>
<extension url="http://orionhealth.com/fhir/extensions#last-modified-by"></extension>
<extension url="http://orionhealth.com/fhir/extensions#received-instant">
<valueInstant value="2015-06-25T17:08:47.190+12:00"></valueInstant>
</extension>
<code>
<coding>
<system value="http://loinc.org"></system>
<code value="3141-9"></code>
</coding>
</code>
<valueString value="observationValue"></valueString>
<status value="final"></status>
<reliability value="ok"></reliability>
<subject>
<reference value="Patient/INGE6TSFFVAUCMJQGJAHA5LQOBSXI"></reference>
</subject>
</Observation>
</resource>
</entry>
</Bundle>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,77 @@
<Bundle xmlns="http://hl7.org/fhir">
<id value="fe7ff16d-8bdf-47a5-9de3-20165c6fe440" />
<meta>
<lastUpdated value="2016-08-25T12:17:12.159-04:00" />
</meta>
<type value="searchset" />
<total value="208" />
<link>
<relation value="self" />
<url value="http://foo.uhn.on.ca:25180/uhn-fhir-service-2.1/DiagnosticReport?_format=xml&amp;_include=DiagnosticReport%3Aencounter&amp;_include=Encounter%3AfacilityLocation&amp;_include=Observation%3Aperformer&amp;_include=DiagnosticReport%3Aresult&amp;_include=Encounter%3Alocation&amp;_include=Location.partOf&amp;_include=Encounter%3Aparticipant&amp;_include=DiagnosticReport%3Apatient&amp;subject%3Aidentifier=urn%3Aoid%3A2.16.840.1.113883.3.239.18.148%7C7000135" />
</link>
<entry>
<fullUrl value="http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-2.1/DiagnosticReport/7162221" />
<resource>
<DiagnosticReport xmlns="http://hl7.org/fhir">
<id value="7162221" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/diagnosticreport" />
</meta>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="10017.1" />
</coding>
<text value="Date Dictated" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<valueString value="Fri, 26 Sep 2014" />
<interpretation>
<coding>
<system value="urn:uhn:qcpr:interpretation_codes" />
<code value="N" />
</coding>
</interpretation>
</Observation>
</contained>
<extension url="http://fhir.uhn.ca/Profile/diagnosticreport#source_system_status">
<valueString value="F" />
</extension>
<identifier>
<system value="urn:uhn:qcpr:order_ids" />
<value value="GI93#discharge_5677961273802d07ad7d079141525bba" />
</identifier>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.5" />
<code value="5053" />
</coding>
<text value="Unscheduled Discharge Summary" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<encounter>
<reference value="Encounter/5885735" />
</encounter>
<effectiveDateTime value="2014-09-26T11:55:00-04:00" />
<issued value="2014-09-26T11:55:33.000-04:00" />
</DiagnosticReport>
</resource>
</entry>
</Bundle>

View File

@ -0,0 +1,50 @@
<Bundle xmlns="http://hl7.org/fhir">
<id value="fe7ff16d-8bdf-47a5-9de3-20165c6fe440" />
<meta>
<lastUpdated value="2016-08-25T12:17:12.159-04:00" />
</meta>
<type value="searchset" />
<total value="208" />
<link>
<relation value="self" />
<url value="http://foo.uhn.on.ca:25180/uhn-fhir-service-2.1/DiagnosticReport?_format=xml&amp;_include=DiagnosticReport%3Aencounter&amp;_include=Encounter%3AfacilityLocation&amp;_include=Observation%3Aperformer&amp;_include=DiagnosticReport%3Aresult&amp;_include=Encounter%3Alocation&amp;_include=Location.partOf&amp;_include=Encounter%3Aparticipant&amp;_include=DiagnosticReport%3Apatient&amp;subject%3Aidentifier=urn%3Aoid%3A2.16.840.1.113883.3.239.18.148%7C7000135" />
</link>
<entry>
<fullUrl value="http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-2.1/DiagnosticReport/7162221" />
<resource>
<DiagnosticReport xmlns="http://hl7.org/fhir">
<id value="7162221" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/diagnosticreport" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/diagnosticreport#source_system_status">
<valueString value="F" />
</extension>
<identifier>
<system value="urn:uhn:qcpr:order_ids" />
<value value="GI93#discharge_5677961273802d07ad7d079141525bba" />
</identifier>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.5" />
<code value="5053" />
</coding>
<text value="Unscheduled Discharge Summary" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<encounter>
<reference value="Encounter/5885735" />
</encounter>
<effectiveDateTime value="2014-09-26T11:55:00-04:00" />
<issued value="2014-09-26T11:55:33.000-04:00" />
<result>
<reference value="#1" />
</result>
</DiagnosticReport>
</resource>
</entry>
</Bundle>

View File

@ -0,0 +1,317 @@
<Bundle xmlns="http://hl7.org/fhir">
<id value="fe7ff16d-8bdf-47a5-9de3-20165c6fe440" />
<meta>
<lastUpdated value="2016-08-25T12:17:12.159-04:00" />
</meta>
<type value="searchset" />
<total value="208" />
<link>
<relation value="self" />
<url value="http://foo.uhn.on.ca:25180/uhn-fhir-service-2.1/DiagnosticReport?_format=xml&amp;_include=DiagnosticReport%3Aencounter&amp;_include=Encounter%3AfacilityLocation&amp;_include=Observation%3Aperformer&amp;_include=DiagnosticReport%3Aresult&amp;_include=Encounter%3Alocation&amp;_include=Location.partOf&amp;_include=Encounter%3Aparticipant&amp;_include=DiagnosticReport%3Apatient&amp;subject%3Aidentifier=urn%3Aoid%3A2.16.840.1.113883.3.239.18.148%7C7000135" />
</link>
<entry>
<fullUrl value="http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-2.1/DiagnosticReport/7162221" />
<resource>
<DiagnosticReport xmlns="http://hl7.org/fhir">
<id value="7162221" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/diagnosticreport" />
</meta>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<id value="1" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="10017.1" />
</coding>
<text value="Date Dictated" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<valueString value="Fri, 26 Sep 2014" />
<interpretation>
<coding>
<system value="urn:uhn:qcpr:interpretation_codes" />
<code value="N" />
</coding>
</interpretation>
</Observation>
</contained>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<id value="2" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="1126527.2" />
</coding>
<text value="Dictated by" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<performer>
<reference value="#3" />
</performer>
<valueString value="Gered Trystan King" />
<interpretation>
<coding>
<system value="urn:uhn:qcpr:interpretation_codes" />
<code value="normal" />
</coding>
</interpretation>
</Observation>
</contained>
<contained>
<Practitioner xmlns="http://hl7.org/fhir">
<id value="3" />
<identifier>
<system value="urn:uhn:qcpr:user_ids" />
<value value="160920" />
</identifier>
<name>
<family value="Gered Trystan King" />
</name>
</Practitioner>
</contained>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<id value="4" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="14002.3" />
</coding>
<text value="Attending/Staff" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<performer>
<reference value="#5" />
</performer>
<valueString value="Gered Trystan King" />
<interpretation>
<coding>
<system value="urn:uhn:qcpr:interpretation_codes" />
<code value="normal" />
</coding>
</interpretation>
</Observation>
</contained>
<contained>
<Practitioner xmlns="http://hl7.org/fhir">
<id value="5" />
<identifier>
<system value="urn:uhn:qcpr:user_ids" />
<value value="160920" />
</identifier>
<name>
<family value="Gered Trystan King" />
</name>
</Practitioner>
</contained>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<id value="6" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="10063.4" />
</coding>
<text value="Distribute Y/N?" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<valueString value="yes" />
<interpretation>
<coding>
<system value="urn:uhn:qcpr:interpretation_codes" />
<code value="N" />
</coding>
</interpretation>
</Observation>
</contained>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<id value="7" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="14001.5" />
</coding>
<text value="Medical Records Report" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<valueString value="Medical Records Report" />
</Observation>
</contained>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<id value="8" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="10060.6" />
</coding>
<text value="Report Type" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<valueString value="Unscheduled Discharge Summary" />
<interpretation>
<coding>
<system value="urn:uhn:qcpr:interpretation_codes" />
<code value="N" />
</coding>
</interpretation>
</Observation>
</contained>
<contained>
<Observation xmlns="http://hl7.org/fhir">
<id value="9" />
<meta>
<lastUpdated value="2014-09-26T11:55:33.000-04:00" />
<profile value="http://fhir.uhn.ca/Profile/observation" />
</meta>
<extension url="http://fhir.uhn.ca/Profile/observation#source_system_status">
<valueString value="F" />
</extension>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.6" />
<code value="10064.7" />
</coding>
<text value="Review/Query?" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<issued value="2014-09-26T11:55:33.000-04:00" />
<valueString value="no" />
<interpretation>
<coding>
<system value="urn:uhn:qcpr:interpretation_codes" />
<code value="N" />
</coding>
</interpretation>
</Observation>
</contained>
<extension url="http://fhir.uhn.ca/Profile/diagnosticreport#source_system_status">
<valueString value="F" />
</extension>
<identifier>
<system value="urn:uhn:qcpr:order_ids" />
<value value="GI93#discharge_5677961273802d07ad7d079141525bba" />
</identifier>
<status value="final" />
<code>
<coding>
<system value="urn:oid:1.3.6.1.4.1.12201.102.5" />
<code value="5053" />
</coding>
<text value="Unscheduled Discharge Summary" />
</code>
<subject>
<reference value="Patient/5556918" />
</subject>
<context>
<reference value="Encounter/5885735" />
</context>
<effectiveDateTime value="2014-09-26T11:55:00-04:00" />
<issued value="2014-09-26T11:55:33.000-04:00" />
<result>
<reference value="#1" />
</result>
<result>
<reference value="#2" />
</result>
<result>
<reference value="#4" />
</result>
<result>
<reference value="#6" />
</result>
<result>
<reference value="#7" />
</result>
<result>
<reference value="#8" />
</result>
<result>
<reference value="#9" />
</result>
</DiagnosticReport>
</resource>
</entry>
</Bundle>

View File

@ -0,0 +1,55 @@
{
"resourceType": "Consent",
"id": "consent-example-basic",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">\n <p>\n\tAuthorize Normal access for Treatment\n\t</p><p>\n Patient &quot;P. van de Heuvel&quot; wishes to have all of the PHI collected at the Good Health Psychiatric Hospital \n available for normal treatment use.\n </p>\n </div>"
},
"status": "active",
"patient": {
"reference": "Patient/f001",
"display": "P. van de Heuvel"
},
"period": {
"start": "1964-01-01",
"end": "2016-01-01"
},
"dateTime": "2016-05-11",
"organization": [
{
"reference": "Organization/Infoway",
"display": "Canada Infoway"
}
],
"sourceAttachment": {
"title": "The terms of the consent in lawyer speak."
},
"identifier": [
{
"use": "usual",
"type": {
"coding": [
{
"system": "http://hl7.org/fhir/v2/0203",
"code": "MR"
}
]
},
"system": "urn:oid:1.2.36.146.595.217.0.1",
"value": "12345",
"period": {
"start": "2001-05-06"
},
"assigner": {
"display": "Acme Healthcare"
}
}
],
"extension":[
{
"url" : "http://hl7.org/fhir/StructureDefinition/PruebaExtension",
"valueString" : "123456789"
}
],
"policyRule": "http://goodhealth.org/consent/policy/opt-in"
}

View File

@ -0,0 +1,140 @@
{
"resourceType":"Patient",
"text":{
"status":"generated",
"div":"<div>\n <table>\n <tbody>\n <tr>\n <td>Name</td>\n <td>Peter James <b>Chalmers</b> (\"Jim\")</td>\n </tr>\n <tr>\n <td>Address</td>\n <td>534 Erewhon, Pleasantville, Vic, 3999</td>\n </tr>\n <tr>\n <td>Contacts</td>\n <td>Home: unknown. Work: (03) 5555 6473</td>\n </tr>\n <tr>\n <td>Id</td>\n <td>MRN: 12345 (Acme Healthcare)</td>\n </tr>\n </tbody>\n </table>\n </div>"
},
"extension":[
{
"url":"urn:patientext:att",
"valueAttachment":{
"contentType":"aaaa",
"data":"AAAA"
}
},
{
"url":"urn:patientext:moreext",
"extension":[
{
"url":"urn:patientext:moreext:1",
"valueString":"str1"
},
{
"url":"urn:patientext:moreext:2",
"valueString":"str2"
}
]
}
],
"modifierExtension":[
{
"url":"urn:modext",
"valueDate":"2011-01-02"
}
],
"identifier":[
{
"use":"usual",
"system":"urn:oid:1.2.36.146.595.217.0.1",
"value":"12345",
"period":{
"start":"2001-05-06"
},
"assigner":{
"display":"Acme Healthcare"
}
}
],
"active":true,
"name":[
{
"use":"official",
"family":[
"Chalmers"
],
"given":[
"Peter",
"James"
]
},
{
"use":"usual",
"given":[
"Jim"
]
}
],
"telecom":[
{
"use":"home"
},
{
"system":"phone",
"value":"(03) 5555 6473",
"use":"work"
}
],
"gender":"male",
"birthDate":"1974-12-25",
"deceasedBoolean":false,
"address":[
{
"use":"home",
"line":[
"534 Erewhon St"
],
"city":"PleasantVille",
"state":"Vic",
"postalCode":"3999"
},
{
"use":"old",
"line":[
"SecondAddress"
]
}
],
"contact":[
{
"relationship":[
{
"coding":[
{
"system":"http://hl7.org/fhir/patient-contact-relationship",
"code":"partner"
}
]
}
],
"name":{
"family":[
"du",
"Marché"
],
"_family":[
{
"extension":[
{
"url":"http://hl7.org/fhir/Profile/iso-21090#qualifier",
"valueCode":"VV"
}
]
},
null
],
"given":[
"Bénédicte"
]
},
"telecom":[
{
"system":"phone",
"value":"+33 (237) 998327"
}
]
}
],
"managingOrganization":{
"reference":"Organization/1"
}
}

View File

@ -0,0 +1,128 @@
<Patient xmlns="http://hl7.org/fhir">
<text>
<status value="generated"/>
<div xmlns="http://www.w3.org/1999/xhtml">
<table>
<tbody>
<tr>
<td>Name</td>
<td>Peter James <b>Chalmers</b> (&quot;Jim&quot;)</td>
</tr>
<tr>
<td>Address</td>
<td>534 Erewhon, Pleasantville, Vic, 3999</td>
</tr>
<tr>
<td>Contacts</td>
<td>Home: unknown. Work: (03) 5555 6473</td>
</tr>
<tr>
<td>Id</td>
<td>MRN: 12345 (Acme Healthcare)</td>
</tr>
</tbody>
</table>
</div>
</text>
<extension url="urn:patientext:att">
<valueAttachment>
<contentType value="aaaa"/>
<data value="AAAA"/>
</valueAttachment>
</extension>
<extension url="urn:patientext:moreext">
<extension url="urn:patientext:moreext:1">
<valueString value="str1"/>
</extension>
<extension url="urn:patientext:moreext:2">
<valueString value="str2"/>
</extension>
</extension>
<modifierExtension url="urn:modext">
<valueDate value="2011-01-02"/>
</modifierExtension>
<identifier>
<use value="usual"/>
<system value="urn:oid:1.2.36.146.595.217.0.1"/>
<value value="12345"/>
<period>
<start value="2001-05-06"/>
</period>
<assigner>
<display value="Acme Healthcare"/>
</assigner>
</identifier>
<active value="true"/>
<name>
<use value="official"/>
<family value="Chalmers"/>
<given value="Peter"/>
<given value="James"/>
</name>
<name>
<use value="usual"/>
<given value="Jim"/>
</name>
<telecom>
<use value="home"/>
</telecom>
<telecom>
<system value="phone"/>
<value value="(03) 5555 6473"/>
<use value="work"/>
</telecom>
<gender value="male"/>
<birthDate value="1974-12-25"/>
<deceasedBoolean value="false"/>
<address>
<use value="home"/>
<line value="534 Erewhon St"/>
<city value="PleasantVille"/>
<state value="Vic"/>
<postalCode value="3999"/>
</address>
<address>
<use value="old"/>
<line value="SecondAddress"/>
</address>
<contact>
<relationship>
<coding>
<system value="http://hl7.org/fhir/patient-contact-relationship"/>
<code value="partner"/>
</coding>
</relationship>
<name>
<family value="du">
<extension url="http://hl7.org/fhir/Profile/iso-21090#qualifier">
<valueCode value="VV"/>
</extension>
</family>
<family value="Marché"/>
<given value="Bénédicte"/>
</name>
<telecom>
<system value="phone"/>
<value value="+33 (237) 998327"/>
</telecom>
</contact>
<managingOrganization>
<reference value="Organization/1"/>
</managingOrganization>
</Patient>

View File

@ -0,0 +1,58 @@
{
"resourceType": "Patient",
"name": [
{
"family": "Doe",
"given": [
"John",
"W."
]
}
],
"gender": "male",
"birthDate": "2012-02-14",
"address": [
{
"use": "home",
"line": [
"535 Sheppard Avenue West, Unit 1907",
"RR 66, Station A, RPO 123"
],
"_line": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-houseNumber",
"valueString": "535"
},
{
"url": "http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-streetName",
"valueString": "Sheppard"
},
{
"url": "http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-streetNameType",
"valueString": "Avenue"
},
{
"url": "http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-direction",
"valueString": "West"
},
{
"url": "http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-unitID",
"valueString": "1907"
},
{
"url": "http://hl7.org/fhir/StructureDefinition/iso21090-ADXP-postBox",
"valueString": "1234"
}
]
}
],
"city": "Toronto",
"state": "ON",
"postalCode": "M3H4X8"
}
]
}

View File

@ -0,0 +1,60 @@
{
"resourceType": "Patient",
"id": "dicom",
"text": {
"status": "generated",
"div": "<div> Patient MINT_TEST, ID = MINT1234. Age = 56y, Size =\n 1.83m, Weight = 72.58kg </div>"
},
"http://nema.org/fhir/extensions#0010:1010": [
{
"valueQuantity": {
"value": 56,
"units": "Y"
}
}
],
"http://nema.org/fhir/extensions#0010:1020": [
{
"valueQuantity": {
"value": 1.83,
"units": "m"
}
}
],
"http://nema.org/fhir/extensions#0010:1030": [
{
"valueQuantity": {
"value": 72.58,
"units": "kg"
}
}
],
"identifier": [
{
"system": "http://nema.org/examples/patients",
"value": "MINT1234"
}
],
"name": [
{
"family": [
"MINT_TEST"
]
}
],
"gender": "male",
"_gender": {
"http://nema.org/examples/extensions#gender": [
{
"valueCoding": {
"system": "http://nema.org/examples/gender",
"code": "M"
}
}
]
},
"managingOrganization": {
"reference": "Organization/1"
},
"active": true
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,455 @@
<QuestionnaireResponse xmlns="http://hl7.org/fhir">
<identifier>
<value value="1234567890"/>
</identifier>
<questionnaire>
<reference value="Questionnaire/q_jon"/>
</questionnaire>
<status value="completed"/>
<subject>
<reference value="http://fhirtest.uhn.ca/baseDstu3/Patient/proband"/>
</subject>
<author>
<reference value="http://fhirtest.uhn.ca/baseDstu3/Practitioner/f007"/>
</author>
<authored value="2016-01-08"/>
<item>
<linkId value="root"/>
<item>
<linkId value="g1"/>
<text value="CLINICAL INFORMATION"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="1.1"/>
</extension>
<linkId value="1.1"/>
<text value="Patient Clinical Information"/>
<answer>
<valueString value="Previous chest X-RAY was suspicious. Heavy smoker, 15 pack years."/>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="1.2"/>
</extension>
<linkId value="1.2"/>
<text value="Previous Examination (Date and Modality)"/>
<answer>
<valueString value="Chest XR - September 23, 2015"/>
</answer>
</item>
</item>
<item>
<linkId value="g2"/>
<text value="IMAGING PROCEDURE DESCRIPTION"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="2.1"/>
</extension>
<linkId value="2.1"/>
<text value="Overall Image Quality:"/>
<answer>
<valueCoding>
<code value="2.1a"/>
<display value="Adequate"/>
</valueCoding>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="2.2"/>
</extension>
<linkId value="2.2"/>
<text value="Intravenous Contrast Used?"/>
<answer>
<valueBoolean value="false"/>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="2.3"/>
</extension>
<linkId value="2.3"/>
<text value="Additional Comments"/>
<answer>
<valueString value="n/a."/>
</answer>
</item>
</item>
<item>
<linkId value="g3"/>
<text value="FINDINGS"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3"/>
</extension>
<linkId value="g3.0"/>
<text value="T Category"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.1"/>
</extension>
<linkId value="g3.1"/>
<text value="Location of Main Nodule/Mass (Primary tumor, or Reference tumor)"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.1.1"/>
</extension>
<linkId value="q3.1.1"/>
<text value="Location of main nodule/mass:"/>
<answer>
<valueCoding>
<code value="3.1.1a"/>
<display value="Peripheral"/>
</valueCoding>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.1.2"/>
</extension>
<linkId value="3.1.2"/>
<answer>
<valueString value="Right Upper Lung, Posterior segment."/>
</answer>
</item>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.2"/>
</extension>
<linkId value="g3.2"/>
<text value="Size and characteristics of main nodule/mass"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.2.1"/>
</extension>
<linkId value="3.2.1"/>
<text value="Size of the nodule/mass:"/>
<answer>
<valueCoding>
<code value="3.2.1a"/>
<display value="Solid nodule/mass"/>
</valueCoding>
</answer>
<item><!-- Measurement, image, series, etc for all 3 answer choices goes here. Conditonal. -->
<linkId value="g3.2.1"/>
<item><!-- Group for answer choice a -->
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen"><!-- Note that this extension is at the group level. -->
<extension url="#question">
<valueString value="3.2.1"/>
</extension>
<extension url="#answer">
<valueCoding>
<code value="3.2.1a"/>
</valueCoding>
</extension>
</extension>
<linkId value="g3.2.1a"/>
<item>
<linkId value="3.2.1a"/>
<text value="largest dimension:"/>
<answer>
<valueInteger value="20"/>
</answer>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-itemControl">
<valueCodeableConcept>
<coding>
<system value="http://hl7.org/fhir/ValueSet/questionnaire-item-control"/>
<code value="unit"/>
</coding>
</valueCodeableConcept>
</extension>
<text value="mm"/>
</item>
</item>
<item>
<linkId value="3.2.1a.image"/>
<text value="image"/>
<answer>
<valueString value="32"/>
</answer>
</item>
<item>
<linkId value="3.2.1a.series"/>
<text value="series"/>
<answer>
<valueString value="3"/>
</answer>
</item>
</item>
</item>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.2.2"/>
</extension>
<linkId value="3.2.2"/>
<text value="Plane in which the mass was measured:"/>
<answer>
<valueCoding>
<code value="3.2.2a"/>
<display value="Axial"/>
</valueCoding>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.2.3"/>
</extension>
<linkId value="3.2.3"/>
<answer>
<valueString value="Solid attenuation of mass, margins spiculated."/>
</answer>
</item>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.3"/>
</extension>
<linkId value="g3.3"/>
<text value="Structures directly involved"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.3.1"/>
</extension>
<linkId value="3.3.1"/>
<text value="State if there is bronchial involvement:"/>
<answer>
<valueCoding>
<code value="3.3.1b"/>
<display value="No"/>
</valueCoding>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.3.2"/>
</extension>
<linkId value="3.3.2"/>
<text value="Is there direct involvement of any other anatomical structures?"/>
<answer>
<valueBoolean value="false"/>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.3.3"/>
</extension>
<linkId value="3.3.3"/>
<text value="Are there additional suspicious pulmonary nodules?"/>
<answer>
<valueBoolean value="false"/>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="3.3.4"/>
</extension>
<linkId value="3.3.4"/>
<text value="Other notable intrathoracic findings (eg lymphangitis carcinomatosis):"/>
<answer>
<valueString value="n/a"/>
</answer>
</item>
</item>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="4"/>
</extension>
<linkId value="4.0"/>
<text value="N Category"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="4.1"/>
</extension>
<linkId value="4.1"/>
<text value="Are there enlarged lymph nodes?"/>
<answer>
<valueBoolean value="false"/>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="4.2"/>
</extension>
<linkId value="4.2"/>
<text value="Other notable findings:"/>
<answer>
<valueString value="Liner / scar atelectasis lingua, anterior segment of right upper lobe and bilateral lower lobes."/>
</answer>
</item>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="5"/>
</extension>
<linkId value="5.0"/>
<text value="M Category (Suspicious Extrathoracic Findings (M1b))"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="5.1"/>
</extension>
<linkId value="5.1"/>
<text value="Are there suspicious extrathoracic findings?"/>
<answer>
<valueBoolean value="true"/>
</answer>
<item>
<linkId value="g5.1.yes"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen">
<extension url="#question">
<valueString value="5.1"/>
</extension>
<extension url="#answer">
<valueBoolean value="true"/>
</extension>
</extension>
<linkId value="5.1.yes"/>
<text value="Applicable Structures and Descriptions:"/>
<answer>
<valueCoding>
<code value="5.1.yes.d"/>
<display value="Other"/>
</valueCoding>
</answer>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen">
<extension url="#question">
<valueString value="5.1.yes"/>
</extension>
<extension url="#answer">
<valueCoding>
<code value="5.1.yes.d"/>
</valueCoding>
</extension>
</extension>
<linkId value="5.1.yes.d.description"/>
<text value="Description of structures:"/>
<answer>
<valueString value="3 cm calcified thyroid nodule on TUL left."/>
</answer>
</item>
</item>
</item>
</item>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="6"/>
</extension>
<linkId value="6.0"/>
<text value="Additional Findings"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="6.1"/>
</extension>
<linkId value="6.1"/>
<text value="Are there additional findings?"/>
<answer>
<valueBoolean value="true"/>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="6.2"/>
</extension>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-enableWhen">
<extension url="#question">
<valueString value="6.1"/>
</extension>
<extension url="#answer">
<valueBoolean value="true"/>
</extension>
</extension>
<linkId value="6.2"/>
<text value="Findings and Descriptions:"/>
<answer>
<valueString value="Oligemic changes in right upper lobe from possible old pulmonary embolus."/>
</answer>
</item>
</item>
</item>
<item>
<linkId value="g7"/>
<text value="IMPRESSIONS"/>
<item>
<linkId value="g7.1"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="7.1"/>
</extension>
<linkId value="7.1"/>
<text value="Impression/Summary:"/>
<answer>
<valueString value="Spiculated mass in posterior segment of right upper lobe that has increasing size from 16 to 20 mm."/>
</answer>
</item>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="7.2"/>
</extension>
<linkId value="g7.2"/>
<text value="Radiologic Staging (TNM Version 7th edition)"/>
<item>
<linkId value="g7.20"/>
<text value="If this is a biopsy proven carcinoma, the preliminary radiologic stage is:"/>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="i)"/>
</extension>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-questionControl" >
<valueCodeableConcept>
<coding>
<code value="radio-button"/>
<display value="Radio Button"/>
</coding>
</valueCodeableConcept>
</extension>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-choiceOrientation" >
<valueCode value="horizontal"/>
</extension>
<linkId value="7.2i"/>
<text value="Primary Tumour (T):"/>
<answer>
<valueCoding>
<code value="T1a"/>
<display value="T1a"/>
</valueCoding>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="ii)"/>
</extension>
<linkId value="7.2ii"/>
<text value="Regional Lymph Nodes (N):"/>
<answer>
<valueCoding>
<code value="N0"/>
<display value="N0"/>
</valueCoding>
</answer>
</item>
<item>
<extension url="http://hl7.org/fhir/StructureDefinition/questionnaire-label">
<valueString value="iii)"/>
</extension>
<linkId value="7.2iii"/>
<text value="Distant Metastasis (M):"/>
<answer>
<valueCoding>
<code value="M0"/>
<display value="M0"/>
</valueCoding>
</answer>
</item>
</item>
</item>
</item>
</item>
</QuestionnaireResponse>

View File

@ -0,0 +1,73 @@
{
"resourceType": "Bundle",
"entry": [
{
"fullUrl": "http://localhost:5555/phr/baseDstu3/Person/PERSON1",
"resource": {
"resourceType": "Person",
"id": "PERSON1",
"meta": {
"versionId": "1",
"lastUpdated": "2017-08-17T16:19:40.109+03:00"
},
"identifier": [
{
"value": "081181-9984"
}
],
"name": [
{
"text": "Anna Testi",
"family": "Testi",
"given": [
"Anna"
]
},
{
"family": "asdfas"
}
],
"telecom": [
{
"use": "home"
},
{
"system": "phone",
"value": "(044) 1234567",
"use": "work"
}
],
"gender": "female",
"birthDate": "1981-11-08",
"address": [
{
"line": [
"Osuuspankkitie 2"
],
"city": "Helsinki",
"postalCode": "00120",
"country": "Suomi"
},
{
"city": "Blo-49847020"
}
],
"active": true,
"link": [
{
"target": {
"reference": "Patient/PATIENT1",
"display": "Anna Testi"
}
}
]
},
"request": {
"method": "PUT",
"url": "Person/PERSON1",
"ifMatch": "1"
}
}
]
}

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,298 @@
{
"resourceType": "TestScript",
"id": "search",
"text": {
"status": "generated",
"div": "<div><p><b>Generated Narrative with Details</b></p><p><b>id</b>: search</p><p><b>name</b>: Read, Search and Conditional Create and Delete</p><p><b>description</b>: Test Script for testing search, read, and conditional create and delete</p><h3>Fixtures</h3><table><tr><td>-</td><td><b>Resource</b></td></tr><tr><td>*</td><td><a>Patient/patient-example.xml</a></td></tr></table><blockquote><p><b>variable</b></p><p><b>name</b>: V1</p><p><b>sourceId</b>: R1</p><p><b>headerField</b>: Location</p></blockquote><blockquote><p><b>variable</b></p><p><b>name</b>: V2</p><p><b>sourceId</b>: R3</p><p><b>path</b>: fhir:Patient/fhir:name/fhir:given/@value</p></blockquote><blockquote><p><b>setup</b></p><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td><td><b>Type</b></td><td><b>Resource</b></td><td><b>Params</b></td></tr><tr><td>*</td><td>delete</td><td>Patient</td><td>given=John&amp;family=Doe</td></tr></table></blockquote></blockquote><blockquote><p><b>test</b></p><p><b>name</b>: Create</p><p><b>description</b>: Create, read, search, conditional create, conditional delete.</p><blockquote><p><b>metadata</b></p><h3>Links</h3><table><tr><td>-</td><td><b>Url</b></td><td><b>Description</b></td></tr><tr><td>*</td><td><a>http://hl7.org/implement/standards/FHIR-Develop/patient.html</a></td><td>FHIR Patient</td></tr></table><blockquote><p><b>operation</b></p><p><b>type</b>: create</p><p><b>resource</b>: Patient</p><p><b>description</b>: Conditional Create Operation</p><p><b>link</b>: <a>http://hl7-fhir.github.io/http.html#2.1.0.13.1</a></p><p><b>required</b>: true</p><p><b>validated</b>: true</p></blockquote><blockquote><p><b>operation</b></p><p><b>type</b>: delete</p><p><b>resource</b>: Patient</p><p><b>description</b>: Conditional Delete Operation</p><p><b>link</b>: <a>http://hl7-fhir.github.io/http.html#2.1.0.12.1</a></p><p><b>required</b>: true</p><p><b>validated</b>: true</p></blockquote><blockquote><p><b>operation</b></p><p><b>type</b>: read</p><p><b>resource</b>: Patient</p><p><b>description</b>: Patient Read Operation</p><p><b>link</b>: <a>http://hl7.org/implement/standards/FHIR-Develop/http.html#read</a></p><p><b>validated</b>: true</p></blockquote><blockquote><p><b>operation</b></p><p><b>type</b>: search</p><p><b>resource</b>: Patient</p><p><b>description</b>: Patient Search Operation</p><p><b>link</b>: <a>http://hl7-fhir.github.io/http.html#2.1.0.14</a></p><p><b>validated</b>: true</p></blockquote></blockquote><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Operations</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote><blockquote><p><b>action</b></p><h3>Asserts</h3><table><tr><td>-</td></tr><tr><td>*</td></tr></table></blockquote></blockquote></div>"
},
"url": "http://hl7.org/fhir/TestScript/search",
"name": "Read, Search and Conditional Create and Delete",
"status": "draft",
"description": "Test Script for testing search, read, and conditional create and delete",
"metadata": {
"capability": [
{
"required": true,
"description": "Patient Create and Read Operations",
"link": [
"http://hl7.org/implement/standards/FHIR-Develop/http.html#create",
"http://hl7.org/implement/standards/FHIR-Develop/http.html#read"
],
"conformance": {
"reference": "Conformance/example"
}
},
{
"required": true,
"description": "Patient Conditional Delete Operation",
"link": [
"http://hl7-fhir.github.io/http.html#2.1.0.12.1"
],
"conformance": {
"reference": "Conformance/example"
}
},
{
"required": true,
"description": "Patient Conditional Create Operation",
"link": [
"http://hl7-fhir.github.io/http.html#2.1.0.13.1"
],
"conformance": {
"reference": "Conformance/example"
}
}
]
},
"fixture": [
{
"id": "example-patient",
"resource": {
"reference": "Patient/example"
}
}
],
"variable": [
{
"name": "V1",
"headerField": "Location",
"sourceId": "R1"
},
{
"name": "V2",
"path": "fhir:Patient/fhir:name/fhir:given/@value",
"sourceId": "R3"
},
{
"name": "DefaultValue",
"defaultValue": "Replace at Runtime"
}
],
"setup": {
"action": [
{
"fhir_comments": [
" Conditional Delete "
],
"operation": {
"type": {
"code": "delete"
},
"resource": "Patient",
"params": "given=John&family=Doe"
}
}
]
},
"test": [
{
"id": "Test1",
"name": "Create",
"description": "Create, read, search, conditional create, conditional delete.",
"metadata": {
"link": [
{
"url": "http://hl7.org/implement/standards/FHIR-Develop/patient.html",
"description": "FHIR Patient"
}
],
"capability": [
{
"validated": true,
"description": "Patient Search Operation",
"link": [
"http://hl7.org/implement/standards/FHIR-Develop/http.html#search"
],
"conformance": {
"reference": "Conformance/example"
}
}
]
},
"action": [
{
"fhir_comments": [
" Create the patient using fixture "
],
"operation": {
"type": {
"code": "create"
},
"sourceId": "example-patient"
}
},
{
"assert": {
"responseCode": "201"
}
},
{
"fhir_comments": [
" Patient search by name. Save the responseBody in 'F1' fixture.\n\t\t\t\tSave the responseHeader in H1 "
],
"operation": {
"type": {
"code": "search"
},
"resource": "Patient",
"contentType": "json",
"params": "?given=John&family=Doe",
"responseId": "R1"
}
},
{
"fhir_comments": [
" Verify that the Location in response-header is valid "
],
"assert": {
"headerField": "Location",
"operator": "notEmpty",
"warningOnly": true
}
},
{
"fhir_comments": [
" Verify that the birthdate got persisted and is being returned properly "
],
"assert": {
"operator": "equals",
"path": "fhir:Patient/fhir:birthDate/@value",
"sourceId": "R1",
"value": "1974-12-31"
}
},
{
"fhir_comments": [
" Verify that the navigation links are valid "
],
"assert": {
"navigationLinks": true,
"warningOnly": true
}
},
{
"fhir_comments": [
" Use the Location returned earlier to grab the resource\n\t\t \t\tto verify that Location was pointing to correct resource. "
],
"operation": {
"type": {
"code": "search"
},
"accept": "json",
"responseId": "R2",
"url": "${V1}"
}
},
{
"assert": {
"contentType": "json"
}
},
{
"assert": {
"response": "okay"
}
},
{
"fhir_comments": [
" Search for the resource but this time using the birthdate\n\t\t\t\tas a search parameter to make sure search by birthDate works "
],
"operation": {
"type": {
"code": "search"
},
"resource": "Patient",
"accept": "json",
"params": "?given=John&family=Doe&birthdate=1974-12-31",
"responseId": "R3"
}
},
{
"assert": {
"contentType": "json"
}
},
{
"assert": {
"response": "okay"
}
},
{
"fhir_comments": [
" Verify that the birthDate matches expectations "
],
"assert": {
"compareToSourceId": "R2",
"compareToSourcePath": "fhir:Patient/fhir:birthDate/@value",
"path": "fhir:Patient/fhir:birthDate/@value",
"sourceId": "R3"
}
},
{
"fhir_comments": [
" Verify that the name matches expectations "
],
"assert": {
"path": "fhir:Patient/fhir:name/fhir:given/@value",
"sourceId": "R3",
"value": "John"
}
},
{
"fhir_comments": [
" Conditional Create "
],
"operation": {
"type": {
"code": "create"
},
"requestHeader": [
{
"field": "If-None-Exist",
"value": "Patient?given=John&Doe&birthdate=1974-12-31"
}
],
"sourceId": "F1"
}
},
{
"fhir_comments": [
" The response code of 200 verifies that the resource\n\t\t\t\talready exists and did not get created "
],
"assert": {
"responseCode": "200"
}
},
{
"fhir_comments": [
" Conditional Delete "
],
"operation": {
"type": {
"code": "delete"
},
"resource": "Patient",
"params": "?given=John&family=Doe&birthdate=1974-12-31"
}
},
{
"fhir_comments": [
" Search again and make sure the patient has been deleted.\n\t\t \t\t This time perform read by id using variable "
],
"operation": {
"type": {
"code": "read"
},
"resource": "Patient",
"params": "/${V2}"
}
},
{
"assert": {
"responseCode": "410"
}
}
]
}
]
}

130
pom.xml
View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<parent>
<groupId>org.sonatype.oss</groupId>
@ -411,6 +412,11 @@
<id>anthonys123</id>
<name>Anthony Sute</name>
</developer>
<developer>
<id>johnpoth</id>
<name>John Poth</name>
<organization>Red Hat</organization>
</developer>
</developers>
<licenses>
@ -431,24 +437,38 @@
<scmPubCheckoutDirectory>${user.home}/sites/scm/hapi-fhir</scmPubCheckoutDirectory>
<!-- Dependency Versions -->
<apache_karaf_version>4.1.4</apache_karaf_version>
<commons_codec_version>1.10</commons_codec_version>
<commons_io_version>2.5</commons_io_version>
<commons_lang3_version>3.6</commons_lang3_version>
<derby_version>10.14.1.0</derby_version>
<error_prone_annotations_version>2.0.18</error_prone_annotations_version>
<guava_version>23.0</guava_version>
<gson_version>2.8.1</gson_version>
<jaxb_api_version>2.3.0</jaxb_api_version>
<jaxb_core_version>2.3.0</jaxb_core_version>
<jersey_version>2.25.1</jersey_version>
<jetty_version>9.4.8.v20171121</jetty_version>
<jsr305_version>3.0.2</jsr305_version>
<!--<hibernate_version>5.2.10.Final</hibernate_version>-->
<hibernate_version>5.2.12.Final</hibernate_version>
<hibernate_validator_version>5.4.1.Final</hibernate_validator_version>
<!-- Update lucene version when you update hibernate-search version -->
<hibernate_search_version>5.7.1.Final</hibernate_search_version>
<httpcore_version>4.4.6</httpcore_version>
<httpclient_version>4.5.3</httpclient_version>
<lucene_version>5.5.4</lucene_version>
<maven_assembly_plugin_version>2.5.3</maven_assembly_plugin_version>
<maven_license_plugin_version>1.8</maven_license_plugin_version>
<phloc_schematron_version>2.7.1</phloc_schematron_version>
<phloc_commons_version>4.4.11</phloc_commons_version>
<servicemix_saxon_version>9.5.1-5_1</servicemix_saxon_version>
<servicemix_xmlresolver_version>1.2_5</servicemix_xmlresolver_version>
<spring_version>5.0.3.RELEASE</spring_version>
<spring-boot.version>1.5.6.RELEASE</spring-boot.version>
<stax2_api_version>3.1.4</stax2_api_version>
<thymeleaf-version>3.0.9.RELEASE</thymeleaf-version>
<woodstox_core_asl_version>4.4.1</woodstox_core_asl_version>
<!-- We are aiming to still work on a very old version of SLF4j even though we depend on the newest, just to be nice to users of the API. This version is tested in the hapi-fhir-cobertura. -->
<slf4j_target_version>1.6.0</slf4j_target_version>
@ -532,7 +552,7 @@
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>23.0</version>
<version>${guava_version}</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
@ -567,12 +587,12 @@
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.10</version>
<version>${commons_codec_version}</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.5</version>
<version>${commons_io_version}</version>
</dependency>
<dependency>
<groupId>directory-naming</groupId>
@ -590,7 +610,7 @@
<groupId>es.nitaur.markdown</groupId>
<artifactId>txtmark</artifactId>
<version>0.16</version>
</dependency>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
@ -619,7 +639,7 @@
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.1</version>
<version>${gson_version}</version>
</dependency>
<dependency>
<groupId>com.sun.xml.bind</groupId>
@ -657,9 +677,9 @@
<version>2.0.1</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>lt.velykis.maven.skins</groupId>
@ -713,7 +733,7 @@
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.6</version>
<version>${commons_lang3_version}</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
@ -733,7 +753,7 @@
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.3</version>
<version>${httpclient_version}</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
@ -743,7 +763,7 @@
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.6</version>
<version>${httpcore_version}</version>
</dependency>
<dependency>
<groupId>org.apache.lucene</groupId>
@ -828,7 +848,7 @@
<dependency>
<groupId>org.codehaus.woodstox</groupId>
<artifactId>woodstox-core-asl</artifactId>
<version>4.4.1</version>
<version>${woodstox_core_asl_version}</version>
</dependency>
<dependency>
<groupId>org.ebaysf.web</groupId>
@ -1127,7 +1147,7 @@
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>3.3.0</version>
<version>3.5.0</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
@ -1301,7 +1321,8 @@
<plugin>
<groupId>org.jacoco</groupId>
<artifactId>
jacoco-maven-plugin</artifactId>
jacoco-maven-plugin
</artifactId>
<version>0.7.9</version>
</plugin>
<plugin>
@ -1549,7 +1570,9 @@
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken>http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css</replacetoken>
<replacetoken>
http://netdna.bootstrapcdn.com/twitter-bootstrap/2.3.1/css/bootstrap-responsive.min.css
</replacetoken>
<replacevalue>./css/bootstrap-responsive.min.css</replacevalue>
</replace>
<replace dir="target/site" summary="true">
@ -1559,8 +1582,10 @@
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken>http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css</replacetoken>
<replacevalue>https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css</replacevalue>
<replacetoken>http://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css
</replacetoken>
<replacevalue>https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css
</replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
@ -1604,28 +1629,35 @@
<echo>Adding Fontawesome</echo>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[<a href="download.html" title="Download">Download</a>]]></replacetoken>
<replacevalue><![CDATA[<a href="download.html" title="Download"><i class="fa fa-download"></i> Download</a>]]></replacevalue>
<replacetoken>
<![CDATA[<a href="download.html" title="Download">Download</a>]]></replacetoken>
<replacevalue>
<![CDATA[<a href="download.html" title="Download"><i class="fa fa-download"></i> Download</a>]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink">GitHub Project</a>]]></replacetoken>
<replacevalue><![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink"><i class="fa fa-github"></i> GitHub Project</a>]]></replacevalue>
<replacetoken>
<![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink">GitHub Project</a>]]></replacetoken>
<replacevalue>
<![CDATA[<a href="https://github.com/jamesagnew/hapi-fhir/" title="GitHub Project" class="externalLink"><i class="fa fa-github"></i> GitHub Project</a>]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Test Servers <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-fire"></i>&nbsp;Test Servers&nbsp;<]]></replacevalue>
<replacevalue>
<![CDATA[data-toggle="dropdown"><i class="fa fa-fire"></i>&nbsp;Test Servers&nbsp;<]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Documentation <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-book"></i>&nbsp;Documentation&nbsp;<]]></replacevalue>
<replacevalue>
<![CDATA[data-toggle="dropdown"><i class="fa fa-book"></i>&nbsp;Documentation&nbsp;<]]></replacevalue>
</replace>
<replace dir="target/site" summary="true">
<include name="*.html"/>
<replacetoken><![CDATA[data-toggle="dropdown">Get Help <]]></replacetoken>
<replacevalue><![CDATA[data-toggle="dropdown"><i class="fa fa-support"></i>&nbsp;Get Help&nbsp;<]]></replacevalue>
<replacevalue>
<![CDATA[data-toggle="dropdown"><i class="fa fa-support"></i>&nbsp;Get Help&nbsp;<]]></replacevalue>
</replace>
<echo>Changing Breadcrumbs</echo>
<replace dir="target/site" summary="true">
@ -1802,21 +1834,6 @@
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>3.1.1</version>
<configuration>
<failBuildOnCVSS>8</failBuildOnCVSS>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
@ -1856,9 +1873,12 @@
<configuration>
<reportsDirectories>
<reportDirectory>${project.basedir}/hapi-fhir-base/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu2/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-jpaserver-base/target/surefire-reports/</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu/target/surefire-reports/
</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-structures-dstu2/target/surefire-reports/
</reportDirectory>
<reportDirectory>${project.basedir}/hapi-fhir-jpaserver-base/target/surefire-reports/
</reportDirectory>
</reportsDirectories>
</configuration>
</plugin>
@ -2000,6 +2020,8 @@
<module>hapi-fhir-cli</module>
<module>hapi-fhir-dist</module>
<module>examples</module>
<module>osgi/hapi-fhir-karaf-features</module>
<module>osgi/hapi-fhir-karaf-integration-tests</module>
<module>example-projects/hapi-fhir-base-example-embedded-ws</module>
<module>example-projects/hapi-fhir-standalone-overlay-example</module>
<module>example-projects/hapi-fhir-jpaserver-cds-example</module>
@ -2075,6 +2097,28 @@
</plugins>
</build>
</profile>
<profile>
<id>OWASP</id>
<build>
<plugins>
<plugin>
<groupId>org.owasp</groupId>
<artifactId>dependency-check-maven</artifactId>
<version>3.1.1</version>
<configuration>
<failBuildOnCVSS>8</failBuildOnCVSS>
</configuration>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>

View File

@ -41,6 +41,28 @@
</ul>
]]>
</action>
<action tyoe="add" issue="871">
A number of HAPI FHIR modules have been converted so that they now work
as OSGi modules. Unlike the previous OSGi module, which was a mega-JAR
with all of HAPI FHIR in it, this is simply the appropriate
OSGi manifest inside the existing JARs. Thanks to John Poth
for the Pull Request!
<![CDATA[
<br/><br/>
Note that this does not cover all modules in the project. Current support includes:
<ul>
<li>HAPI-FHIR structures DSTU2, HL7ORGDSTU2, DSTU2.1, DSTU3, R4</li>
<li>HAPI-FHIR Resource validation DSTU2, HL7ORGDSTU2, DSTU2.1, DSTU3, R4</li>
<li>Apache Karaf features for all the above</li>
<li> Integration Tests</li>
</ul>
Remaining work includes:
<ul>
<li>HAPI-FHIR Server support</li>
<li> HAPI-FHIR narrative support. This might be tricky as Thymeleaf doesn't support OSGi.</li>
</ul>
]]>
</action>
<action type="fix">
Fix a crash in the JSON parser when parsing extensions on repeatable
elements (e.g. Patient.address.line) where there is an extension on the
@ -275,6 +297,13 @@
Suport for the :contains string search parameter modifier has been added to
the JPA server. Thanks to Anthony Sute for the pull request!
</action>
<action type="fix">
All instances of DefaultProfileValidationSupport (i.e. one for
each version of FHIR) have been fixed so that they explicitly
close any InputStreams they open in order to read the built-in
profile resources. Leaving these open caused resource starvation
in some cases under heavy load.
</action>
</release>
<release version="3.2.0" date="2018-01-13">
<action type="add">