diff --git a/.gitignore b/.gitignore index d3ee296ebcb..491a273dcfe 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,13 @@ /bin /target +target/ +.idea/ +.project/ +.settings/ +.metadata/ +RemoteSystemsTempFiles/ +Servers/ +*.iml *.log *.log* nohup.out diff --git a/hapi-deployable-pom/.project b/hapi-deployable-pom/.project new file mode 100644 index 00000000000..4b06e2a7715 --- /dev/null +++ b/hapi-deployable-pom/.project @@ -0,0 +1,17 @@ + + + hapi-deployable-pom + + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.m2e.core.maven2Nature + + diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml new file mode 100644 index 00000000000..8d4332ff500 --- /dev/null +++ b/hapi-deployable-pom/pom.xml @@ -0,0 +1,115 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-fhir + 0.8-SNAPSHOT + ../pom.xml + + + hapi-deployable-pom + pom + + HAPI FHIR - Deployable Artifact Parent POM + + + + + org.apache.maven.plugins + maven-project-info-reports-plugin + 2.7 + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven_javadoc_plugin_version} + + + default + + javadoc + + + + http://docs.oracle.com/javaee/7/api + + + + + + + + + + + DIST + + + + org.apache.maven.plugins + maven-javadoc-plugin + true + + 128m + 1g + true + false + false + + + + package + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + ${maven_source_plugin_version} + + + package + + jar-no-fork + + + + + + org.codehaus.mojo + license-maven-plugin + ${maven_license_plugin_version} + + + first + + update-file-header + + process-sources + + apache_v2 + true + true + + src/main/java + + + + + + + + + + + diff --git a/hapi-fhir-base/.gitignore b/hapi-fhir-base/.gitignore index 4dc009173e3..f7e179f26d2 100644 --- a/hapi-fhir-base/.gitignore +++ b/hapi-fhir-base/.gitignore @@ -1,2 +1,3 @@ /target /bin +/target/ diff --git a/hapi-fhir-base/examples/pom.xml b/hapi-fhir-base/examples/pom.xml index 0f63e05510a..d20bcfb8574 100644 --- a/hapi-fhir-base/examples/pom.xml +++ b/hapi-fhir-base/examples/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 0.7 + 0.8-SNAPSHOT ../../pom.xml @@ -17,7 +17,12 @@ ca.uhn.hapi.fhir hapi-fhir-base - 0.7 + 0.8-SNAPSHOT + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT javax.servlet diff --git a/hapi-fhir-base/examples/pom.xml.orig b/hapi-fhir-base/examples/pom.xml.orig new file mode 100644 index 00000000000..09ea3151fb1 --- /dev/null +++ b/hapi-fhir-base/examples/pom.xml.orig @@ -0,0 +1,55 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-fhir + 0.8-SNAPSHOT + ../../pom.xml + + + hapi-fhir-base-examples + jar + + HAPI FHIR - Examples (for site) + + + + ca.uhn.hapi.fhir + hapi-fhir-base + 0.8-SNAPSHOT +<<<<<<< HEAD +======= + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT +>>>>>>> versions + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + junit + junit + ${junit_version} + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + + diff --git a/hapi-fhir-base/examples/src/main/java/example/GenericClientExample.java b/hapi-fhir-base/examples/src/main/java/example/GenericClientExample.java index 08d82b1a6bd..6d6df92d50b 100644 --- a/hapi-fhir-base/examples/src/main/java/example/GenericClientExample.java +++ b/hapi-fhir-base/examples/src/main/java/example/GenericClientExample.java @@ -6,6 +6,8 @@ import java.util.List; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.model.api.Bundle; import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.base.resource.BaseConformance; +import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; import ca.uhn.fhir.model.dstu.resource.Conformance; import ca.uhn.fhir.model.dstu.resource.Observation; import ca.uhn.fhir.model.dstu.resource.OperationOutcome; @@ -82,19 +84,19 @@ public class GenericClientExample { // START SNIPPET: conformance // Retrieve the server's conformance statement and print its // description - Conformance conf = client.conformance(); - System.out.println(conf.getDescription().getValue()); + BaseConformance conf = client.conformance(); + System.out.println(conf.getDescriptionElement().getValue()); // END SNIPPET: conformance } { // START SNIPPET: delete // Retrieve the server's conformance statement and print its // description - OperationOutcome outcome = client.delete().resourceById(new IdDt("Patient", "1234")).execute(); + BaseOperationOutcome outcome = client.delete().resourceById(new IdDt("Patient", "1234")).execute(); // outcome may be null if the server didn't return one if (outcome != null) { - System.out.println(outcome.getIssueFirstRep().getDetails().getValue()); + System.out.println(outcome.getIssueFirstRep().getDetailsElement().getValue()); } // END SNIPPET: delete } diff --git a/hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProviderMore.java b/hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProviderMore.java index ce1b6884786..f454c958fbf 100644 --- a/hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProviderMore.java +++ b/hapi-fhir-base/examples/src/main/java/example/RestfulPatientResourceProviderMore.java @@ -19,6 +19,7 @@ import ca.uhn.fhir.model.api.Tag; import ca.uhn.fhir.model.api.TagList; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; import ca.uhn.fhir.rest.annotation.TagListParam; import ca.uhn.fhir.model.dstu.composite.CodingDt; import ca.uhn.fhir.model.dstu.resource.Conformance; @@ -430,7 +431,7 @@ public List searchByObservationNames( // The list here will contain 0..* codings, and any observations which match any of the // given codings should be returned - List wantedCodings = theCodings.getListAsCodings(); + List wantedCodings = theCodings.getListAsCodings(); List retVal = new ArrayList(); // ...populate... diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 9d358eb4822..a206b79e09f 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -3,9 +3,9 @@ ca.uhn.hapi.fhir - hapi-fhir - 0.7 - ../pom.xml + hapi-deployable-pom + 0.8-SNAPSHOT + ../hapi-deployable-pom/pom.xml hapi-fhir-base @@ -178,7 +178,7 @@ javax.servlet javax.servlet-api - 3.1.0 + ${servlet_api_version} provided @@ -189,395 +189,16 @@ ${junit_version} test - - xmlunit - xmlunit - 1.5 - test - - - org.eclipse.jetty - jetty-servlets - 9.1.1.v20140108 - test - - - org.eclipse.jetty - jetty-servlet - 9.1.1.v20140108 - test - - - org.eclipse.jetty - jetty-server - 9.1.1.v20140108 - test - - - org.eclipse.jetty - jetty-servlet - 9.1.1.v20140108 - test - - - org.eclipse.jetty - jetty-util - 9.1.1.v20140108 - test - - - org.eclipse.jetty - jetty-webapp - 9.1.1.v20140108 - test - - - org.eclipse.jetty - jetty-http - 9.1.1.v20140108 - test - - - - - org.mockito - mockito-all - 1.9.5 - test - - - net.sf.json-lib - json-lib - 2.4 - jdk15 - test - - - commons-logging - commons-logging - - - - - net.sf.json-lib - json-lib - 2.4 - jdk15-sources - test - - - directory-naming - naming-java - 0.8 - test - - - commons-logging - commons-logging - - - - - org.hamcrest - hamcrest-all - ${hamcrest_version} - test - - - com.google.guava - guava - ${guava_version} - test - - - - - - - - org.apache.maven.plugins - maven-changes-plugin - 2.10 - false - - - - changes-report - - - - - atom_1.0 - - http://sourceforge.net/support/tracker.php?aid=%ISSUE% - https://sourceforge.net/p/hl7api/bugs/%ISSUE%/ - https://sourceforge.net/p/hl7api/feature-requests/%ISSUE%/ - - false - - - - org.apache.maven.plugins - maven-project-info-reports-plugin - 2.7 - - - - project-team - issue-tracking - license - scm - - - - - - - - - - UTF-8 - ${user.home}/sites/hapi-fhir - ${user.home}/sites/scm/hapi-fhir - - - - - - maven-site-plugin - ${maven_site_plugin_version} - - false - true - - - - org.apache.maven.wagon - wagon-scm - 2.2 - - - org.apache.maven.scm - maven-scm-manager-plexus - 1.9 - - - org.apache.maven.scm - maven-scm-provider-gitexe - 1.9 - - - org.apache.maven.scm - maven-scm-api - 1.9 - - - - - - - - maven-antrun-plugin - 1.7 - - - addSyntaxHighlighter - site - - run - - - - Adding Syntax Highlighter - - - ]]> - - var elements = document.getElementsByClassName("source"); - for (var i=0; i < elements.length; i++) { - var pres = elements[i].getElementsByTagName("pre"); - for (var j = 0; j < pres.length; j++) { - var pre = pres[j]; - if (pre.innerHTML.match(/\/\*/)) { - pre.className = 'brush: java'; - } else if (pre.innerHTML.match(/^\/\//)) { - pre.className = 'brush: java'; - } else if (pre.innerHTML.match(/^\{/)) { - pre.className = 'brush: jscript'; - } else if (pre.innerHTML.match(/^\#/)) { - pre.className = 'brush: bash'; - } else if (pre.innerHTML.match(/\<\;\//)) { - pre.className = 'brush: xml'; - } else { - pre.className = 'brush: java'; - } - } - } - - SyntaxHighlighter.all(); - - - ]]> - - - - - - addAnalytics - post-site - - - Adding Google analytics in target/site for <body> - - - - - ]]> - - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-1395874-5', 'auto'); - ga('require', 'displayfeatures'); - ga('require', 'linkid', 'linkid.js'); - ga('send', 'pageview'); - - - - ]]> - - Adding Google analytics in target/site for <BODY> - - - ]]> - - (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ - (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o), - m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) - })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - - ga('create', 'UA-1395874-5', 'auto'); - ga('require', 'displayfeatures'); - ga('require', 'linkid', 'linkid.js'); - ga('send', 'pageview'); - - - - ]]> - - Adding social plugins for HAPI - - - - -
-
- - -

- - -

- - ]]>
-
- - -
-
- - run - -
-
-
- - maven-site-plugin - - - stage-for-scm-publish - post-site - - stage - - - ${siteMainDirectory} - - - - - - org.apache.maven.plugins - maven-scm-publish-plugin - 1.1 - - ${scmPubCheckoutDirectory} - \${siteMainDirectory} - true - gh-pages - scm:git:git@github.com:jamesagnew/hapi-fhir.git - - - - scm-publish - site-deploy - - publish-scm - - - - -
src/main/resources true -
@@ -585,40 +206,10 @@ MINI - DEFAULT - - - true - + SITE - - org.apache.maven.plugins - maven-surefire-report-plugin - ${maven_surefire_plugin_version} - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven_javadoc_plugin_version} - - - http://docs.oracle.com/javaee/7/api - - - - - default - - javadoc - - - - + + - + hapi-fhir-jpaserver-base jar @@ -44,7 +35,7 @@ ca.uhn.hapi.fhir hapi-fhir-base - 0.7 + 0.8-SNAPSHOT commons-logging @@ -52,11 +43,16 @@ + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT + - org.slf4j - jcl-over-slf4j - ${slf4j_version} + org.slf4j + jcl-over-slf4j + ${slf4j_version} @@ -74,58 +70,25 @@ - org.jscience - jscience - ${jscience_version} + org.jscience + jscience + ${jscience_version} - - - - + + + + junit @@ -145,16 +108,17 @@ 1.4 test - + javax.servlet javax.servlet-api 3.1.0 provided - - - + + + @@ -254,21 +218,21 @@ 1.1.0.Final - javax.el - javax.el-api - 3.0.0 + javax.el + javax.el-api + 3.0.0 - org.glassfish - javax.el - 3.0.0 + org.glassfish + javax.el + 3.0.0 - + - com.google.guava - guava - ${guava_version} + com.google.guava + guava + ${guava_version} @@ -282,10 +246,10 @@ org.apache.maven.plugins - maven-compiler-plugin + maven-site-plugin - 1.6 - 1.6 + true + true diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProvider.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProvider.java index f06f0635026..3c415cb4c5d 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProvider.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/provider/JpaResourceProvider.java @@ -11,6 +11,7 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.dao.IFhirResourceDao; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue; import ca.uhn.fhir.model.dstu.resource.OperationOutcome; import ca.uhn.fhir.model.dstu.valueset.IssueSeverityEnum; import ca.uhn.fhir.model.primitive.IdDt; @@ -160,7 +161,9 @@ public class JpaResourceProvider extends BaseJpaProvider im try { MethodOutcome retVal = new MethodOutcome(); retVal.setOperationOutcome(new OperationOutcome()); - retVal.getOperationOutcome().addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDetails("Resource validates successfully"); + BaseIssue issue = retVal.getOperationOutcome().addIssue(); + issue.getSeverityElement().setValue("information"); + issue.setDetails("Resource validates successfully"); return retVal; } finally { endRequest(theRequest); diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoTest.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoTest.java index dce096145ac..9eafa2a3257 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoTest.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/dao/FhirResourceDaoTest.java @@ -970,7 +970,7 @@ public class FhirResourceDaoTest { { Patient patient = new Patient(); patient.addIdentifier("urn:system", "001"); - patient.addName().addGiven("testSearchStringParamWithNonNormalized_höra"); + patient.addName().addGiven("testSearchStringParamWithNonNormalized_h\u00F6ra"); ourPatientDao.create(patient); } { diff --git a/hapi-fhir-jpaserver-test/pom.xml b/hapi-fhir-jpaserver-test/pom.xml index a8ed63a776e..2450610c9d1 100644 --- a/hapi-fhir-jpaserver-test/pom.xml +++ b/hapi-fhir-jpaserver-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 0.7 + 0.8-SNAPSHOT ../pom.xml @@ -17,7 +17,7 @@ ca.uhn.hapi.fhir hapi-fhir-jpaserver-base - 0.7 + 0.8-SNAPSHOT org.thymeleaf @@ -127,7 +127,7 @@ ca.uhn.hapi.fhir hapi-tinder-plugin - 0.7 + 0.8-SNAPSHOT buildclient @@ -152,6 +152,13 @@ + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT + + org.apache.maven.plugins diff --git a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component index ff207aac0dd..6c40b81fe82 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component +++ b/hapi-fhir-jpaserver-uhnfhirtest/.settings/org.eclipse.wst.common.component @@ -6,13 +6,16 @@ - + uses - + uses - + + uses + + consumes diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index 8046c808545..ea4f87258d9 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 0.7 + 0.8-SNAPSHOT ../pom.xml @@ -16,12 +16,17 @@ ca.uhn.hapi.fhir hapi-fhir-jpaserver-base - 0.7 + 0.8-SNAPSHOT + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT ca.uhn.hapi.fhir hapi-fhir-testpage-overlay - 0.7 + 0.8-SNAPSHOT war provided @@ -29,7 +34,7 @@ ca.uhn.hapi.fhir hapi-fhir-jpaserver-test - 0.7 + 0.8-SNAPSHOT test @@ -185,7 +190,7 @@ ca.uhn.hapi.fhir hapi-tinder-plugin - 0.7 + 0.8-SNAPSHOT buildclient @@ -193,6 +198,7 @@ generate-jparest-server + dstu ca.uhn.test.jpasrv adversereaction @@ -202,7 +208,6 @@ appointment availability careplan - claim composition conceptmap condition @@ -256,7 +261,6 @@ specimen substance supply - user valueset @@ -266,6 +270,13 @@ + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT + + org.apache.maven.plugins diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml.orig b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml.orig new file mode 100644 index 00000000000..0418223e7d4 --- /dev/null +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml.orig @@ -0,0 +1,308 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-fhir + 0.8-SNAPSHOT + ../pom.xml + + + hapi-fhir-jpaserver-uhnfhirtest + + HAPI FHIR - fhirtest.uhn.ca Deployable WAR + + + + ca.uhn.hapi.fhir + hapi-fhir-jpaserver-base + 0.8-SNAPSHOT +<<<<<<< HEAD +======= + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT +>>>>>>> versions + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + 0.8-SNAPSHOT + war + provided + + + + ca.uhn.hapi.fhir + hapi-fhir-jpaserver-test + 0.8-SNAPSHOT + test + + + + org.springframework + spring-web + ${spring_version} + + + + org.hsqldb + hsqldb + 2.3.2 + provided + + + + org.apache.derby + derby + ${derby_version} + + + org.apache.derby + derbynet + ${derby_version} + + + org.apache.derby + derbyclient + ${derby_version} + + + + org.thymeleaf + thymeleaf + ${thymeleaf-version} + + + ch.qos.logback + logback-classic + ${logback_version} + + + org.slf4j + jcl-over-slf4j + ${slf4j_version} + + + org.slf4j + slf4j-api + ${slf4j_version} + + + + com.google.guava + guava + 17.0 + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + + org.eclipse.jetty + jetty-servlets + ${jetty_version} + test + + + org.eclipse.jetty + jetty-webapp + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-server + ${jetty_version} + test + + + org.eclipse.jetty + jetty-util + ${jetty_version} + test + + + + commons-dbcp + commons-dbcp + 1.4 + + + + + org.ebaysf.web + cors-filter + ${ebay_cors_filter_version} + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.7 + 1.7 + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + + [0.4,) + + + + + + + + + + + + + + + + + ca.uhn.hapi.fhir + hapi-tinder-plugin + 0.8-SNAPSHOT + + + buildclient + + generate-jparest-server + + + dstu + ca.uhn.test.jpasrv + + adversereaction + alert + allergyintolerance + appointmentresponse + appointment + availability + careplan + composition + conceptmap + condition + conformance + coverage + deviceobservationreport + device + diagnosticorder + diagnosticreport + documentmanifest + documentreference + encounter + familyhistory + geneexpression + geneticanalysis + group + gvfmeta + gvfvariant + imagingstudy + immunizationrecommendation + immunization + list + location + media + medicationadministration + medicationdispense + medicationprescription + medication + medicationstatement + messageheader + microarray + observation + operationoutcome + orderresponse + order + organization + other + patient + practitioner + procedure + profile + provenance + query + questionnaire + relatedperson + remittance + securityevent + sequencinganalysis + sequencinglab + slot + specimen + substance + supply + user + valueset + + true + ${project.build.directory}/hapi-fhir-jpaserver/WEB-INF + hapi-fhir-server-resourceproviders.xml + + + + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT + + + + + org.apache.maven.plugins + maven-war-plugin + + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + hapi-fhir-jpaserver + + + war + diff --git a/hapi-fhir-oauth2/.classpath b/hapi-fhir-oauth2/.classpath index afcbba556d2..d752e4f3e60 100644 --- a/hapi-fhir-oauth2/.classpath +++ b/hapi-fhir-oauth2/.classpath @@ -12,7 +12,7 @@ - + diff --git a/hapi-fhir-oauth2/.settings/org.eclipse.core.resources.prefs b/hapi-fhir-oauth2/.settings/org.eclipse.core.resources.prefs index f9fe34593fc..cdfe4f1b669 100644 --- a/hapi-fhir-oauth2/.settings/org.eclipse.core.resources.prefs +++ b/hapi-fhir-oauth2/.settings/org.eclipse.core.resources.prefs @@ -1,4 +1,5 @@ eclipse.preferences.version=1 encoding//src/main/java=UTF-8 encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 encoding/=UTF-8 diff --git a/hapi-fhir-oauth2/pom.xml b/hapi-fhir-oauth2/pom.xml index 5c901203cbe..b8f182797ab 100644 --- a/hapi-fhir-oauth2/pom.xml +++ b/hapi-fhir-oauth2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 0.7 + 0.8-SNAPSHOT ../pom.xml @@ -17,9 +17,15 @@ ca.uhn.hapi.fhir hapi-fhir-base - 0.7 + 0.8-SNAPSHOT - + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT + test + + org.mitre @@ -78,12 +84,6 @@ ${jetty_version} test - - org.eclipse.jetty - jetty-servlet - ${jetty_version} - test - org.eclipse.jetty jetty-util diff --git a/hapi-fhir-structures-dev/.classpath b/hapi-fhir-structures-dev/.classpath new file mode 100644 index 00000000000..f3e655204ba --- /dev/null +++ b/hapi-fhir-structures-dev/.classpath @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-structures-dev/.gitignore b/hapi-fhir-structures-dev/.gitignore new file mode 100644 index 00000000000..b83d22266ac --- /dev/null +++ b/hapi-fhir-structures-dev/.gitignore @@ -0,0 +1 @@ +/target/ diff --git a/hapi-fhir-structures-dev/pom.xml b/hapi-fhir-structures-dev/pom.xml new file mode 100644 index 00000000000..3e6696667b2 --- /dev/null +++ b/hapi-fhir-structures-dev/pom.xml @@ -0,0 +1,353 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-deployable-pom + 0.8-SNAPSHOT + ../hapi-deployable-pom/pom.xml + + + hapi-fhir-structures-dev + jar + + HAPI FHIR Structures - DEV (FHIR Latest) + + + + ca.uhn.hapi.fhir + hapi-fhir-base + 0.8-SNAPSHOT + + + + javax.servlet + javax.servlet-api + ${servlet_api_version} + provided + + + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT + test + + + junit + junit + ${junit_version} + test + + + xmlunit + xmlunit + 1.5 + test + + + org.eclipse.jetty + jetty-servlets + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-server + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-util + ${jetty_version} + test + + + org.eclipse.jetty + jetty-webapp + ${jetty_version} + test + + + org.eclipse.jetty + jetty-http + ${jetty_version} + test + + + ch.qos.logback + logback-classic + ${logback_version} + true + test + + + org.ebaysf.web + cors-filter + ${ebay_cors_filter_version} + test + + + org.thymeleaf + thymeleaf + ${thymeleaf-version} + test + + + com.phloc + phloc-schematron + ${phloc_schematron_version} + test + + + com.phloc + phloc-commons + ${phloc_commons_version} + test + + + + + + org.mockito + mockito-all + 1.9.5 + test + + + net.sf.json-lib + json-lib + 2.4 + jdk15 + test + + + commons-logging + commons-logging + + + + + net.sf.json-lib + json-lib + 2.4 + jdk15-sources + test + + + directory-naming + naming-java + 0.8 + test + + + commons-logging + commons-logging + + + + + org.hamcrest + hamcrest-all + ${hamcrest_version} + test + + + com.google.guava + guava + ${guava_version} + test + + + + + + + + + ca.uhn.hapi.fhir + hapi-tinder-plugin + 0.8-SNAPSHOT + + + + generate-structures + + + + + ca.uhn.fhir.model.dev + dev + + account + adversereaction + adversereactionrisk + alert + allergyintolerance + appointment + appointmentresponse + availability + careplan + + composition + conceptmap + condition + conformance + contract + contraindication + coverage + device + deviceobservationreport + diagnosticorder + diagnosticreport + documentmanifest + documentreference + encounter + familyhistory + geneexpression + geneticanalysis + group + imagingstudy + immunization + immunizationrecommendation + list + location + media + medication + medicationadministration + medicationdispense + medicationprescription + medicationstatement + messageheader + microarray + namespace + nutritionorder + observation + operationdefinition + operationoutcome + order + orderresponse + organization + other + patient + + practitioner + procedure + profile + + provenance + query + questionnaire + questionnaireanswers + referralrequest + relatedperson + remittance + riskassessment + securityclaim + securityevent + securitygroup + securityprincipal + + sequencinganalysis + sequencinglab + slot + specimen + subscription + substance + supply + user + valueset + + true + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + ca.uhn.hapi.fhir + hapi-tinder-plugin + [0.4-SNAPSHOT,) + + generate-structures + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven_javadoc_plugin_version} + + + + + + + diff --git a/hapi-fhir-structures-dev/pom.xml.versionsBackup b/hapi-fhir-structures-dev/pom.xml.versionsBackup new file mode 100644 index 00000000000..a130f34c7db --- /dev/null +++ b/hapi-fhir-structures-dev/pom.xml.versionsBackup @@ -0,0 +1,352 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-fhir + 0.7-SNAPSHOT + ../pom.xml + + + hapi-fhir-structures-dev + jar + + HAPI FHIR Structures - DEV (FHIR Latest) + + + + ca.uhn.hapi.fhir + hapi-fhir-base + 0.7-SNAPSHOT + + + + javax.servlet + javax.servlet-api + ${servlet_api_version} + provided + + + + + junit + junit + ${junit_version} + test + + + xmlunit + xmlunit + 1.5 + test + + + org.eclipse.jetty + jetty-servlets + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-server + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-util + ${jetty_version} + test + + + org.eclipse.jetty + jetty-webapp + ${jetty_version} + test + + + org.eclipse.jetty + jetty-http + ${jetty_version} + test + + + ch.qos.logback + logback-classic + ${logback_version} + true + test + + + org.ebaysf.web + cors-filter + ${ebay_cors_filter_version} + test + + + org.thymeleaf + thymeleaf + ${thymeleaf-version} + test + + + com.phloc + phloc-schematron + ${phloc_schematron_version} + test + + + com.phloc + phloc-commons + ${phloc_commons_version} + test + + + + + + org.mockito + mockito-all + 1.9.5 + test + + + net.sf.json-lib + json-lib + 2.4 + jdk15 + test + + + commons-logging + commons-logging + + + + + net.sf.json-lib + json-lib + 2.4 + jdk15-sources + test + + + directory-naming + naming-java + 0.8 + test + + + commons-logging + commons-logging + + + + + org.hamcrest + hamcrest-all + ${hamcrest_version} + test + + + com.google.guava + guava + ${guava_version} + test + + + + + + + + + ca.uhn.hapi.fhir + hapi-tinder-plugin + 0.7-SNAPSHOT + + + + generate-structures + + + + + ca.uhn.fhir.model.dev + dev + + account + adversereaction + adversereactionrisk + alert + allergyintolerance + appointment + appointmentresponse + availability + careplan + + composition + conceptmap + condition + conformance + contract + contraindication + coverage + device + deviceobservationreport + diagnosticorder + diagnosticreport + documentmanifest + documentreference + encounter + familyhistory + geneexpression + geneticanalysis + group + imagingstudy + immunization + immunizationrecommendation + list + location + media + medication + medicationadministration + medicationdispense + medicationprescription + medicationstatement + messageheader + microarray + namespace + nutritionorder + observation + operationdefinition + operationoutcome + order + orderresponse + organization + other + patient + person + practitioner + procedure + profile + + provenance + query + questionnaire + questionnaireanswers + referralrequest + relatedperson + remittance + riskassessment + securityclaim + securityevent + securitygroup + securityprincipal + + sequencinganalysis + sequencinglab + slot + specimen + subscription + substance + supply + user + valueset + + true + + + + org.apache.maven.plugins + maven-deploy-plugin + + true + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + ca.uhn.hapi.fhir + hapi-tinder-plugin + [0.4-SNAPSHOT,) + + generate-structures + + + + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + ${maven_javadoc_plugin_version} + + + + + + + diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java new file mode 100644 index 00000000000..de6f79ef724 --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/FhirDev.java @@ -0,0 +1,64 @@ +package ca.uhn.fhir.model.dev; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import org.apache.commons.lang3.StringUtils; + +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.IFhirVersion; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dev.resource.Profile; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.rest.server.provider.dev.ServerConformanceProvider; +import ca.uhn.fhir.rest.server.provider.dev.ServerProfileProvider; + +public class FhirDev implements IFhirVersion { + + private String myId; + + @Override + public Object createServerConformanceProvider(RestfulServer theServer) { + return new ServerConformanceProvider(theServer); + } + + @Override + public IResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition) { + Profile retVal = new Profile(); + + RuntimeResourceDefinition def = theRuntimeResourceDefinition; + + myId = def.getId(); + if (StringUtils.isBlank(myId)) { + myId = theRuntimeResourceDefinition.getName().toLowerCase(); + } + + retVal.setId(new IdDt(myId)); + return retVal; + } + + @Override + public IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer) { + return new ServerProfileProvider(theRestfulServer.getFhirContext()); + } + +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/AgeDt.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/AgeDt.java new file mode 100644 index 00000000000..8cddc638ad5 --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/AgeDt.java @@ -0,0 +1,25 @@ +package ca.uhn.fhir.model.dev.composite; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +public class AgeDt extends QuantityDt { + +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/BoundCodeableConceptDt.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/BoundCodeableConceptDt.java new file mode 100644 index 00000000000..0e8b505fd54 --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/BoundCodeableConceptDt.java @@ -0,0 +1,123 @@ +package ca.uhn.fhir.model.dev.composite; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import static org.apache.commons.lang3.StringUtils.defaultString; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import ca.uhn.fhir.model.api.IBoundCodeableConcept; +import ca.uhn.fhir.model.api.IValueSetEnumBinder; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +@DatatypeDef(name = "CodeableConcept", isSpecialization = true) +public class BoundCodeableConceptDt> extends CodeableConceptDt implements IBoundCodeableConcept { + + private IValueSetEnumBinder myBinder; + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder) { + myBinder = theBinder; + } + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder, T theValue) { + myBinder = theBinder; + setValueAsEnum(theValue); + } + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder, Collection theValues) { + myBinder = theBinder; + setValueAsEnum(theValues); + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated types, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValue + * The value to add, or null + */ + public void setValueAsEnum(Collection theValues) { + getCoding().clear(); + if (theValues != null) { + for (T next : theValues) { + getCoding().add(new CodingDt(myBinder.toSystemString(next), myBinder.toCodeString(next))); + } + } + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated type, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValue + * The value to add, or null + */ + public void setValueAsEnum(T theValue) { + getCoding().clear(); + if (theValue == null) { + return; + } + getCoding().add(new CodingDt(myBinder.toSystemString(theValue), myBinder.toCodeString(theValue))); + } + + /** + * Loops through the {@link #getCoding() codings} in this codeable concept + * and returns the first bound enumerated type that matches. Use + * caution using this method, see the return description for more + * information. + * + * @return Returns the bound enumerated type, or null if none + * are found. Note that a null return value doesn't neccesarily + * imply that this Codeable Concept has no codes, only that it has + * no codes that match the enum. + */ + public Set getValueAsEnum() { + Set retVal = new HashSet(); + for (CodingDt next : getCoding()) { + if (next == null) { + continue; + } + T nextT = myBinder.fromCodeString(defaultString(next.getCodeElement().getValue()), defaultString(next.getSystemElement().getValueAsString())); + if (nextT != null) { + retVal.add(nextT); + } else { + // TODO: throw special exception type? + } + } + return retVal; + } + +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/CountDt.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/CountDt.java new file mode 100644 index 00000000000..878c35de5e1 --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/CountDt.java @@ -0,0 +1,25 @@ +package ca.uhn.fhir.model.dev.composite; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +public class CountDt extends QuantityDt { + +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/DistanceDt.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/DistanceDt.java new file mode 100644 index 00000000000..51afb6e26ef --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/DistanceDt.java @@ -0,0 +1,25 @@ +package ca.uhn.fhir.model.dev.composite; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +public class DistanceDt extends QuantityDt { + +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/DurationDt.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/DurationDt.java new file mode 100644 index 00000000000..4a2dbd8997a --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/DurationDt.java @@ -0,0 +1,25 @@ +package ca.uhn.fhir.model.dev.composite; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +public class DurationDt extends QuantityDt { + +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/MoneyDt.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/MoneyDt.java new file mode 100644 index 00000000000..9c9fbf9cf75 --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/model/dev/composite/MoneyDt.java @@ -0,0 +1,25 @@ +package ca.uhn.fhir.model.dev.composite; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +public class MoneyDt extends QuantityDt { + +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java new file mode 100644 index 00000000000..f2e9ae9c740 --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerConformanceProvider.java @@ -0,0 +1,359 @@ +package ca.uhn.fhir.rest.server.provider.dev; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.lang3.StringUtils; + +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.context.RuntimeSearchParam; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dev.resource.Conformance; +import ca.uhn.fhir.model.dev.resource.OperationDefinition; +import ca.uhn.fhir.model.dev.resource.Conformance.Rest; +import ca.uhn.fhir.model.dev.resource.Conformance.RestOperation; +import ca.uhn.fhir.model.dev.resource.Conformance.RestResource; +import ca.uhn.fhir.model.dev.resource.Conformance.RestResourceSearchParam; +import ca.uhn.fhir.model.dev.resource.OperationDefinition.Parameter; +import ca.uhn.fhir.model.dev.valueset.RestfulConformanceModeEnum; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.primitive.BooleanDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.annotation.Metadata; +import ca.uhn.fhir.rest.method.BaseMethodBinding; +import ca.uhn.fhir.rest.method.DynamicSearchMethodBinding; +import ca.uhn.fhir.rest.method.IParameter; +import ca.uhn.fhir.rest.method.SearchMethodBinding; +import ca.uhn.fhir.rest.method.SearchParameter; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.ResourceBinding; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.util.ExtensionConstants; + +/** + * Server FHIR Provider which serves the conformance statement for a RESTful server implementation + * + *

+ * Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is + * always returned unless {@link #setCache(boolean)} is called with a value of false. This means that if + * you are adding anything to the returned conformance instance on each call you should call + * setCache(false) in your provider constructor. + *

+ */ +public class ServerConformanceProvider { + + private boolean myCache = true; + private volatile Conformance myConformance; + private String myPublisher = "Not provided"; + private final RestfulServer myRestfulServer; + + public ServerConformanceProvider(RestfulServer theRestfulServer) { + myRestfulServer = theRestfulServer; + } + + /** + * Gets the value of the "publisher" that will be placed in the generated conformance statement. As this + * is a mandatory element, the value should not be null (although this is not enforced). The value defaults + * to "Not provided" but may be set to null, which will cause this element to be omitted. + */ + public String getPublisher() { + return myPublisher; + } + + /** + * Actually create and return the conformance statement + * + * See the class documentation for an important note if you are extending this class + */ + @Metadata + public Conformance getServerConformance() { + if (myConformance != null && myCache) { + return myConformance; + } + + Conformance retVal = new Conformance(); + + retVal.setPublisher(myPublisher); + retVal.setDate(DateTimeDt.withCurrentTime()); + retVal.setFhirVersion("0.80"); // TODO: pull from model + retVal.setAcceptUnknown(false); // TODO: make this configurable - this is a fairly big effort since the parser needs to be modified to actually allow it + + retVal.getImplementation().setDescription(myRestfulServer.getImplementationDescription()); + retVal.getSoftware().setName(myRestfulServer.getServerName()); + retVal.getSoftware().setVersion(myRestfulServer.getServerVersion()); + retVal.addFormat(Constants.CT_FHIR_XML); + retVal.addFormat(Constants.CT_FHIR_JSON); + + Rest rest = retVal.addRest(); + rest.setMode(RestfulConformanceModeEnum.SERVER); + +// Set systemOps = new HashSet(); +// +// List bindings = new ArrayList(myRestfulServer.getResourceBindings()); +// Collections.sort(bindings, new Comparator() { +// @Override +// public int compare(ResourceBinding theArg0, ResourceBinding theArg1) { +// return theArg0.getResourceName().compareToIgnoreCase(theArg1.getResourceName()); +// } +// }); +// +// for (ResourceBinding next : bindings) { +// +// Set resourceOps = new HashSet(); +// RestResource resource = rest.addResource(); +// +// String resourceName = next.getResourceName(); +// RuntimeResourceDefinition def = myRestfulServer.getFhirContext().getResourceDefinition(resourceName); +// resource.getType().setValue(def.getName()); +// resource.getProfile().setReference(new IdDt(def.getResourceProfile())); +// +// TreeSet includes = new TreeSet(); +// +// // Map nameToSearchParam = new HashMap(); +// for (BaseMethodBinding nextMethodBinding : next.getMethodBindings()) { +// RestfulOperationTypeEnum resOp = nextMethodBinding.getResourceOperationType(); +// if (resOp != null) { +// if (resourceOps.contains(resOp) == false) { +// resourceOps.add(resOp); +// resource.addOperation().setCode(resOp); +// } +// } +// +// RestfulOperationSystemEnum sysOp = nextMethodBinding.getSystemOperationType(); +// if (sysOp != null) { +// if (systemOps.contains(sysOp) == false) { +// systemOps.add(sysOp); +// rest.addOperation().setCode(sysOp); +// } +// } +// +// if (nextMethodBinding instanceof SearchMethodBinding) { +// handleSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding); +// } else if (nextMethodBinding instanceof DynamicSearchMethodBinding) { +// handleDynamicSearchMethodBinding(resource, def, includes, (DynamicSearchMethodBinding) nextMethodBinding); +// } +// +// Collections.sort(resource.getOperation(), new Comparator() { +// @Override +// public int compare(RestResourceOperation theO1, RestResourceOperation theO2) { +// RestfulOperationTypeEnum o1 = theO1.getCode().getValueAsEnum(); +// RestfulOperationTypeEnum o2 = theO2.getCode().getValueAsEnum(); +// if (o1 == null && o2 == null) { +// return 0; +// } +// if (o1 == null) { +// return 1; +// } +// if (o2 == null) { +// return -1; +// } +// return o1.ordinal() - o2.ordinal(); +// } +// }); +// +// } +// +// for (String nextInclude : includes) { +// resource.addSearchInclude(nextInclude); +// } +// +// } + + myConformance = retVal; + return retVal; + } + + private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet includes, DynamicSearchMethodBinding searchMethodBinding) { + includes.addAll(searchMethodBinding.getIncludes()); + + List searchParameters = new ArrayList(); + searchParameters.addAll(searchMethodBinding.getSearchParams()); + sortRuntimeSearchParameters(searchParameters); + + if (!searchParameters.isEmpty()) { + + for (RuntimeSearchParam nextParameter : searchParameters) { + + String nextParamName = nextParameter.getName(); + + // String chain = null; + String nextParamUnchainedName = nextParamName; + if (nextParamName.contains(".")) { + // chain = nextParamName.substring(nextParamName.indexOf('.') + 1); + nextParamUnchainedName = nextParamName.substring(0, nextParamName.indexOf('.')); + } + + String nextParamDescription = nextParameter.getDescription(); + + /* + * If the parameter has no description, default to the one from the resource + */ + if (StringUtils.isBlank(nextParamDescription)) { + RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName); + if (paramDef != null) { + nextParamDescription = paramDef.getDescription(); + } + } + + RestResourceSearchParam param; + param = resource.addSearchParam(); + + param.setName(nextParamName); + // if (StringUtils.isNotBlank(chain)) { + // param.addChain(chain); + // } + param.setDocumentation(nextParamDescription); +// param.setType(nextParameter.getParamType()); + } + } + } + + private void handleSearchMethodBinding(Rest rest, RestResource resource, String resourceName, RuntimeResourceDefinition def, TreeSet includes, SearchMethodBinding searchMethodBinding) { + includes.addAll(searchMethodBinding.getIncludes()); + + List params = searchMethodBinding.getParameters(); + List searchParameters = new ArrayList(); + for (IParameter nextParameter : params) { + if ((nextParameter instanceof SearchParameter)) { + searchParameters.add((SearchParameter) nextParameter); + } + } + sortSearchParameters(searchParameters); + if (!searchParameters.isEmpty()) { + boolean allOptional = searchParameters.get(0).isRequired() == false; + + OperationDefinition query = null; + if (!allOptional) { + RestOperation operation = rest.addOperation(); + query = new OperationDefinition(); + operation.setDefinition(new ResourceReferenceDt(query)); + query.getDescriptionElement().setValue(searchMethodBinding.getDescription()); + query.addUndeclaredExtension(false, ExtensionConstants.QUERY_RETURN_TYPE, new CodeDt(resourceName)); + for (String nextInclude : searchMethodBinding.getIncludes()) { + query.addUndeclaredExtension(false, ExtensionConstants.QUERY_ALLOWED_INCLUDE, new StringDt(nextInclude)); + } + } + + for (SearchParameter nextParameter : searchParameters) { + + String nextParamName = nextParameter.getName(); + + // String chain = null; + String nextParamUnchainedName = nextParamName; + if (nextParamName.contains(".")) { + // chain = nextParamName.substring(nextParamName.indexOf('.') + 1); + nextParamUnchainedName = nextParamName.substring(0, nextParamName.indexOf('.')); + } + + String nextParamDescription = nextParameter.getDescription(); + + /* + * If the parameter has no description, default to the one from the resource + */ + if (StringUtils.isBlank(nextParamDescription)) { + RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName); + if (paramDef != null) { + nextParamDescription = paramDef.getDescription(); + } + } + + Parameter param; + if (query == null) { +// param = resource.addSearchParam(); + } else { + param = query.addParameter(); + param.addUndeclaredExtension(false, ExtensionConstants.PARAM_IS_REQUIRED, new BooleanDt(nextParameter.isRequired())); + } + +// param.setName(nextParamName); + // if (StringUtils.isNotBlank(chain)) { + // param.addChain(chain); + // } +// param.setDocumentation(nextParamDescription); +// param.setType(nextParameter.getParamType()); + for (Class nextTarget : nextParameter.getDeclaredTypes()) { + RuntimeResourceDefinition targetDef = myRestfulServer.getFhirContext().getResourceDefinition(nextTarget); + if (targetDef != null) { +// ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName()); +// if (code != null) { +// param.addTarget(code); +// } + } + } + } + } + } + + /** + * Sets the cache property (default is true). If set to true, the same response will be returned for each + * invocation. + *

+ * See the class documentation for an important note if you are extending this class + *

+ */ + public void setCache(boolean theCache) { + myCache = theCache; + } + + /** + * Sets the value of the "publisher" that will be placed in the generated conformance statement. As this + * is a mandatory element, the value should not be null (although this is not enforced). The value defaults + * to "Not provided" but may be set to null, which will cause this element to be omitted. + */ + public void setPublisher(String thePublisher) { + myPublisher = thePublisher; + } + + private void sortRuntimeSearchParameters(List searchParameters) { + Collections.sort(searchParameters, new Comparator() { + @Override + public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) { + return theO1.getName().compareTo(theO2.getName()); + } + }); + } + + private void sortSearchParameters(List searchParameters) { + Collections.sort(searchParameters, new Comparator() { + @Override + public int compare(SearchParameter theO1, SearchParameter theO2) { + if (theO1.isRequired() == theO2.isRequired()) { + return theO1.getName().compareTo(theO2.getName()); + } + if (theO1.isRequired()) { + return -1; + } + return 1; + } + }); + } +} diff --git a/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerProfileProvider.java b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerProfileProvider.java new file mode 100644 index 00000000000..1e11a5034fc --- /dev/null +++ b/hapi-fhir-structures-dev/src/main/java/ca/uhn/fhir/rest/server/provider/dev/ServerProfileProvider.java @@ -0,0 +1,79 @@ +package ca.uhn.fhir.rest.server.provider.dev; + +/* + * #%L + * HAPI FHIR Structures - DEV (FHIR Latest) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dev.resource.Profile; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.server.IResourceProvider; + +public class ServerProfileProvider implements IResourceProvider { + + private FhirContext myContext; + + public ServerProfileProvider(FhirContext theCtx) { + myContext = theCtx; + } + + @Override + public Class getResourceType() { + return Profile.class; + } + + @Read() + public Profile getProfileById(@IdParam IdDt theId) { + RuntimeResourceDefinition retVal = myContext.getResourceDefinitionById(theId.getValue()); + if (retVal==null) { + return null; + } + return (Profile) retVal.toProfile(); + } + + @Search() + public List getAllProfiles() { + List defs = new ArrayList(myContext.getResourceDefinitions()); + Collections.sort(defs, new Comparator() { + @Override + public int compare(RuntimeResourceDefinition theO1, RuntimeResourceDefinition theO2) { + int cmp = theO1.getName().compareTo(theO2.getName()); + if (cmp==0) { + cmp=theO1.getResourceProfile().compareTo(theO2.getResourceProfile()); + } + return cmp; + }}); + ArrayList retVal = new ArrayList(); + for (RuntimeResourceDefinition next : defs) { + retVal.add((Profile) next.toProfile()); + } + return retVal; + } + +} diff --git a/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/parser/MixedResourcesTest.java b/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/parser/MixedResourcesTest.java new file mode 100644 index 00000000000..7c69d480123 --- /dev/null +++ b/hapi-fhir-structures-dev/src/test/java/ca/uhn/fhir/parser/MixedResourcesTest.java @@ -0,0 +1,35 @@ +package ca.uhn.fhir.parser; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.resource.Appointment; +import ca.uhn.fhir.model.primitive.DateTimeDt; + + +public class MixedResourcesTest { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MixedResourcesTest.class); + @Test + public void testMixedResources() { + + // dstu + Appointment a1 = new Appointment(); + a1.getSchedule().addEvent().setStart(new DateTimeDt("2001-01-02T12:00:00")); + + ca.uhn.fhir.model.dev.resource.Appointment a2 = new ca.uhn.fhir.model.dev.resource.Appointment(); + a2.getStartElement().setValueAsString("2001-01-02T12:00:00"); + + IParser parser = new FhirContext().newXmlParser(); + String string = parser.encodeResourceToString(a1); + ourLog.info(string); + assertEquals("", string); + + string = parser.encodeResourceToString(a2); + ourLog.info(string); + assertEquals("", string); + + } +} diff --git a/hapi-fhir-structures-dstu/.classpath b/hapi-fhir-structures-dstu/.classpath index 81f7606d2eb..11236ee4d63 100644 --- a/hapi-fhir-structures-dstu/.classpath +++ b/hapi-fhir-structures-dstu/.classpath @@ -1,13 +1,20 @@ - - + + + + + + + + + @@ -16,12 +23,7 @@ - - - - - - + diff --git a/hapi-fhir-structures-dstu/.project b/hapi-fhir-structures-dstu/.project index 22a9a48b013..15d970207c9 100644 --- a/hapi-fhir-structures-dstu/.project +++ b/hapi-fhir-structures-dstu/.project @@ -5,11 +5,21 @@ + + org.eclipse.wst.common.project.facet.core.builder + + + org.eclipse.jdt.core.javabuilder + + org.eclipse.wst.validation.validationbuilder + + + org.eclipse.m2e.core.maven2Builder @@ -17,7 +27,10 @@ + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature org.eclipse.m2e.core.maven2Nature org.eclipse.jdt.core.javanature + org.eclipse.wst.common.project.facet.core.nature diff --git a/hapi-fhir-structures-dstu/.settings/org.eclipse.core.resources.prefs b/hapi-fhir-structures-dstu/.settings/org.eclipse.core.resources.prefs index 99f26c0203a..cdfe4f1b669 100644 --- a/hapi-fhir-structures-dstu/.settings/org.eclipse.core.resources.prefs +++ b/hapi-fhir-structures-dstu/.settings/org.eclipse.core.resources.prefs @@ -1,2 +1,5 @@ eclipse.preferences.version=1 +encoding//src/main/java=UTF-8 +encoding//src/test/java=UTF-8 +encoding//src/test/resources=UTF-8 encoding/=UTF-8 diff --git a/hapi-fhir-structures-dstu/pom.xml b/hapi-fhir-structures-dstu/pom.xml index 2bd5434f830..8f33b7f1160 100644 --- a/hapi-fhir-structures-dstu/pom.xml +++ b/hapi-fhir-structures-dstu/pom.xml @@ -4,9 +4,9 @@ ca.uhn.hapi.fhir - hapi-fhir - 0.7 - ../pom.xml + hapi-deployable-pom + 0.8-SNAPSHOT + ../hapi-deployable-pom/pom.xml hapi-fhir-structures-dstu @@ -18,8 +18,176 @@ ca.uhn.hapi.fhir hapi-fhir-base - 0.7 + 0.8-SNAPSHOT + + + javax.servlet + javax.servlet-api + ${servlet_api_version} + provided + + + + + junit + junit + ${junit_version} + test + + + xmlunit + xmlunit + 1.5 + test + + + org.eclipse.jetty + jetty-servlets + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-server + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-util + ${jetty_version} + test + + + org.eclipse.jetty + jetty-webapp + ${jetty_version} + test + + + org.eclipse.jetty + jetty-http + ${jetty_version} + test + + + ch.qos.logback + logback-classic + ${logback_version} + true + test + + + org.ebaysf.web + cors-filter + ${ebay_cors_filter_version} + test + + + org.thymeleaf + thymeleaf + ${thymeleaf-version} + test + + + com.phloc + phloc-schematron + ${phloc_schematron_version} + test + + + com.phloc + phloc-commons + ${phloc_commons_version} + test + + + + + + org.mockito + mockito-all + 1.9.5 + test + + + net.sf.json-lib + json-lib + 2.4 + jdk15 + test + + + commons-logging + commons-logging + + + + + net.sf.json-lib + json-lib + 2.4 + jdk15-sources + test + + + directory-naming + naming-java + 0.8 + test + + + commons-logging + commons-logging + + + + + org.hamcrest + hamcrest-all + ${hamcrest_version} + test + + + com.google.guava + guava + ${guava_version} + test + + + @@ -27,7 +195,7 @@ ca.uhn.hapi.fhir hapi-tinder-plugin - 0.7 + 0.8-SNAPSHOT @@ -38,8 +206,6 @@ ca.uhn.fhir.model.dstu - - adversereaction alert allergyintolerance @@ -47,7 +213,7 @@ appointment availability careplan - claim + composition conceptmap condition @@ -60,7 +226,6 @@ documentmanifest documentreference encounter - familyhistory geneexpression geneticanalysis @@ -80,7 +245,6 @@ medicationstatement messageheader microarray - observation operationoutcome orderresponse @@ -88,45 +252,27 @@ organization other patient - practitioner procedure profile - - provenance query - questionnaire relatedperson remittance - securityevent - sequencinganalysis sequencinglab slot specimen substance supply - - test user - valueset - - true - - org.apache.maven.plugins - maven-deploy-plugin - - true - -
@@ -159,16 +305,4 @@ - - - - org.apache.maven.plugins - maven-javadoc-plugin - ${maven_javadoc_plugin_version} - - - - - - diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java new file mode 100644 index 00000000000..07765b9beaa --- /dev/null +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java @@ -0,0 +1,321 @@ +package ca.uhn.fhir.model.dstu; + +/* + * #%L + * HAPI FHIR Structures - DSTU (FHIR 0.80) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import static org.apache.commons.lang3.StringUtils.isNotBlank; +import static org.apache.commons.lang3.StringUtils.join; + +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +import ca.uhn.fhir.context.*; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.text.WordUtils; + +import ca.uhn.fhir.context.BaseRuntimeElementDefinition.ChildTypeEnum; +import ca.uhn.fhir.model.api.IFhirVersion; +import ca.uhn.fhir.model.api.IPrimitiveDatatype; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.dstu.resource.Profile; +import ca.uhn.fhir.model.dstu.resource.Profile.ExtensionDefn; +import ca.uhn.fhir.model.dstu.resource.Profile.Structure; +import ca.uhn.fhir.model.dstu.resource.Profile.StructureElement; +import ca.uhn.fhir.model.dstu.resource.Profile.StructureElementDefinitionType; +import ca.uhn.fhir.model.dstu.valueset.DataTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.SlicingRulesEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider; +import ca.uhn.fhir.rest.server.provider.ServerProfileProvider; + +public class FhirDstu1 implements IFhirVersion { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirDstu1.class); + private Map myExtensionDefToCode = new HashMap(); + private String myId; + + @Override + public Object createServerConformanceProvider(RestfulServer theServer) { + return new ServerConformanceProvider(theServer); + } + + private void fillBasics(StructureElement theElement, BaseRuntimeElementDefinition def, LinkedList path, BaseRuntimeDeclaredChildDefinition theChild) { + if (path.isEmpty()) { + path.add(def.getName()); + theElement.setName(def.getName()); + } else { + path.add(WordUtils.uncapitalize(theChild.getElementName())); + theElement.setName(theChild.getElementName()); + } + theElement.setPath(StringUtils.join(path, '.')); + } + + private void fillExtensions(Structure theStruct, LinkedList path, List extList, String elementName, boolean theIsModifier) { + if (extList.size() > 0) { + StructureElement extSlice = theStruct.addElement(); + extSlice.setName(elementName); + extSlice.setPath(join(path, '.') + '.' + elementName); + extSlice.getSlicing().getDiscriminator().setValue("url"); + extSlice.getSlicing().setOrdered(false); + extSlice.getSlicing().setRules(SlicingRulesEnum.OPEN); + extSlice.getDefinition().addType().setCode(DataTypeEnum.EXTENSION); + + for (RuntimeChildDeclaredExtensionDefinition nextExt : extList) { + StructureElement nextProfileExt = theStruct.addElement(); + nextProfileExt.getDefinition().setIsModifier(theIsModifier); + nextProfileExt.setName(extSlice.getName()); + nextProfileExt.setPath(extSlice.getPath()); + fillMinAndMaxAndDefinitions(nextExt, nextProfileExt); + StructureElementDefinitionType type = nextProfileExt.getDefinition().addType(); + type.setCode(DataTypeEnum.EXTENSION); + if (nextExt.isDefinedLocally()) { + type.setProfile(nextExt.getExtensionUrl().substring(nextExt.getExtensionUrl().indexOf('#'))); + } else { + type.setProfile(nextExt.getExtensionUrl()); + } + } + } else { + StructureElement extSlice = theStruct.addElement(); + extSlice.setName(elementName); + extSlice.setPath(join(path, '.') + '.' + elementName); + extSlice.getDefinition().setIsModifier(theIsModifier); + extSlice.getDefinition().addType().setCode(DataTypeEnum.EXTENSION); + extSlice.getDefinition().setMin(0); + extSlice.getDefinition().setMax("*"); + } + } + + private void fillMinAndMaxAndDefinitions(BaseRuntimeDeclaredChildDefinition child, StructureElement elem) { + elem.getDefinition().setMin(child.getMin()); + if (child.getMax() == Child.MAX_UNLIMITED) { + elem.getDefinition().setMax("*"); + } else { + elem.getDefinition().setMax(Integer.toString(child.getMax())); + } + + if (isNotBlank(child.getShortDefinition())) { + elem.getDefinition().getShort().setValue(child.getShortDefinition()); + } + if (isNotBlank(child.getFormalDefinition())) { + elem.getDefinition().getFormal().setValue(child.getFormalDefinition()); + } + } + + private void fillName(StructureElement elem, BaseRuntimeElementDefinition nextDef) { + if (nextDef instanceof RuntimeResourceReferenceDefinition) { + RuntimeResourceReferenceDefinition rr = (RuntimeResourceReferenceDefinition) nextDef; + for (Class next : rr.getResourceTypes()) { + StructureElementDefinitionType type = elem.getDefinition().addType(); + type.getCode().setValue("ResourceReference"); + + if (next != IResource.class) { + RuntimeResourceDefinition resDef = rr.getDefinitionForResourceType(next); + type.getProfile().setValueAsString(resDef.getResourceProfile()); + } + } + + return; + } + + StructureElementDefinitionType type = elem.getDefinition().addType(); + String name = nextDef.getName(); + DataTypeEnum fromCodeString = DataTypeEnum.VALUESET_BINDER.fromCodeString(name); + if (fromCodeString == null) { + throw new ConfigurationException("Unknown type: " + name); + } + type.setCode(fromCodeString); + } + + private void fillProfile(Structure theStruct, StructureElement theElement, BaseRuntimeElementDefinition def, LinkedList path, BaseRuntimeDeclaredChildDefinition theChild) { + + fillBasics(theElement, def, path, theChild); + + String expectedPath = StringUtils.join(path, '.'); + + ourLog.info("Filling profile for: {} - Path: {}", expectedPath); + String name = def.getName(); + if (!expectedPath.equals(name)) { + path.pollLast(); + theElement.getDefinition().getNameReference().setValue(def.getName()); + return; + } + + fillExtensions(theStruct, path, def.getExtensionsNonModifier(), "extension", false); + fillExtensions(theStruct, path, def.getExtensionsModifier(), "modifierExtension", true); + + if (def.getChildType() == ChildTypeEnum.RESOURCE) { + StructureElement narrative = theStruct.addElement(); + narrative.setName("text"); + narrative.setPath(join(path, '.') + ".text"); + narrative.getDefinition().addType().setCode(DataTypeEnum.NARRATIVE); + narrative.getDefinition().setIsModifier(false); + narrative.getDefinition().setMin(0); + narrative.getDefinition().setMax("1"); + + StructureElement contained = theStruct.addElement(); + contained.setName("contained"); + contained.setPath(join(path, '.') + ".contained"); + contained.getDefinition().addType().getCode().setValue("Resource"); + contained.getDefinition().setIsModifier(false); + contained.getDefinition().setMin(0); + contained.getDefinition().setMax("1"); + } + + if (def instanceof BaseRuntimeElementCompositeDefinition) { + BaseRuntimeElementCompositeDefinition cdef = ((BaseRuntimeElementCompositeDefinition) def); + for (BaseRuntimeChildDefinition nextChild : cdef.getChildren()) { + if (nextChild instanceof RuntimeChildUndeclaredExtensionDefinition) { + continue; + } + + BaseRuntimeDeclaredChildDefinition child = (BaseRuntimeDeclaredChildDefinition) nextChild; + StructureElement elem = theStruct.addElement(); + fillMinAndMaxAndDefinitions(child, elem); + + if (child instanceof RuntimeChildResourceBlockDefinition) { + RuntimeResourceBlockDefinition nextDef = (RuntimeResourceBlockDefinition) child.getSingleChildOrThrow(); + fillProfile(theStruct, elem, nextDef, path, child); + } else if (child instanceof RuntimeChildContainedResources) { + // ignore + } else if (child instanceof RuntimeChildDeclaredExtensionDefinition) { + throw new IllegalStateException("Unexpected child type: " + child.getClass().getCanonicalName()); + } else if (child instanceof RuntimeChildCompositeDatatypeDefinition || child instanceof RuntimeChildPrimitiveDatatypeDefinition || child instanceof RuntimeChildChoiceDefinition + || child instanceof RuntimeChildResourceDefinition) { + Iterator childNamesIter = child.getValidChildNames().iterator(); + String nextName = childNamesIter.next(); + BaseRuntimeElementDefinition nextDef = child.getChildByName(nextName); + fillBasics(elem, nextDef, path, child); + fillName(elem, nextDef); + while (childNamesIter.hasNext()) { + nextDef = child.getChildByName(childNamesIter.next()); + fillName(elem, nextDef); + } + path.pollLast(); + } else { + throw new IllegalStateException("Unexpected child type: " + child.getClass().getCanonicalName()); + } + + } + } else { + throw new IllegalStateException("Unexpected child type: " + def.getClass().getCanonicalName()); + } + + path.pollLast(); + } + + @Override + public IResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition) { + Profile retVal = new Profile(); + + RuntimeResourceDefinition def = theRuntimeResourceDefinition; + + myId = def.getId(); + if (StringUtils.isBlank(myId)) { + myId = theRuntimeResourceDefinition.getName().toLowerCase(); + } + + retVal.setId(new IdDt(myId)); + + // Scan for extensions + scanForExtensions(retVal, def); + Collections.sort(retVal.getExtensionDefn(), new Comparator() { + @Override + public int compare(ExtensionDefn theO1, ExtensionDefn theO2) { + return theO1.getCode().compareTo(theO2.getCode()); + } + }); + + // Scan for children + retVal.setName(def.getName()); + Structure struct = retVal.addStructure(); + LinkedList path = new LinkedList(); + + StructureElement element = struct.addElement(); + element.getDefinition().setMin(1); + element.getDefinition().setMax("1"); + + fillProfile(struct, element, def, path, null); + + retVal.getStructure().get(0).getElement().get(0).getDefinition().addType().getCode().setValue("Resource"); + + return retVal; + } + + private void scanForExtensions(Profile theProfile, BaseRuntimeElementDefinition def) { + BaseRuntimeElementCompositeDefinition cdef = ((BaseRuntimeElementCompositeDefinition) def); + + for (RuntimeChildDeclaredExtensionDefinition nextChild : cdef.getExtensions()) { + if (myExtensionDefToCode.containsKey(nextChild)) { + continue; + } + + if (nextChild.isDefinedLocally() == false) { + continue; + } + + ExtensionDefn defn = theProfile.addExtensionDefn(); + String code = null; + if (nextChild.getExtensionUrl().contains("#") && !nextChild.getExtensionUrl().endsWith("#")) { + code = nextChild.getExtensionUrl().substring(nextChild.getExtensionUrl().indexOf('#') + 1); + } else { + throw new ConfigurationException("Locally defined extension has no '#[code]' part in extension URL: " + nextChild.getExtensionUrl()); + } + + defn.setCode(code); + if (myExtensionDefToCode.values().contains(code)) { + throw new IllegalStateException("Duplicate extension code: " + code); + } + myExtensionDefToCode.put(nextChild, code); + + if (nextChild.getChildType() != null && IPrimitiveDatatype.class.isAssignableFrom(nextChild.getChildType())) { + RuntimePrimitiveDatatypeDefinition pdef = (RuntimePrimitiveDatatypeDefinition) nextChild.getSingleChildOrThrow(); + defn.getDefinition().addType().setCode(DataTypeEnum.VALUESET_BINDER.fromCodeString(pdef.getName())); + } else if (nextChild.getChildType() != null && ICompositeDatatype.class.isAssignableFrom(nextChild.getChildType())) { + RuntimeCompositeDatatypeDefinition pdef = (RuntimeCompositeDatatypeDefinition) nextChild.getSingleChildOrThrow(); + defn.getDefinition().addType().setCode(DataTypeEnum.VALUESET_BINDER.fromCodeString(pdef.getName())); + } else { + RuntimeResourceBlockDefinition pdef = (RuntimeResourceBlockDefinition) nextChild.getSingleChildOrThrow(); + scanForExtensions(theProfile, pdef); + + for (RuntimeChildDeclaredExtensionDefinition nextChildExt : pdef.getExtensions()) { + StructureElementDefinitionType type = defn.getDefinition().addType(); + type.setCode(DataTypeEnum.EXTENSION); + type.setProfile("#" + myExtensionDefToCode.get(nextChildExt)); + } + + } + } + } + + @Override + public IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer) { + return new ServerProfileProvider(theRestfulServer.getFhirContext()); + } + +} diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/composite/AgeDt.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/composite/AgeDt.java new file mode 100644 index 00000000000..901a4f10095 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/composite/AgeDt.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.model.dstu.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +/* + * #%L + * HAPI FHIR Structures - DSTU (FHIR 0.80) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +@DatatypeDef(name="AgeDt") +public class AgeDt extends QuantityDt { + + // TODO: implement restricions + +} diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/composite/DurationDt.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/composite/DurationDt.java new file mode 100644 index 00000000000..7cf8818ad71 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/dstu/composite/DurationDt.java @@ -0,0 +1,33 @@ +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR Structures - DSTU (FHIR 0.80) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +@DatatypeDef(name = "Duration") +public class DurationDt extends QuantityDt { + + // TODO: implement restricions + + // There SHALL be a code if there is a value and it SHALL be an expression of length. If system is present, it SHALL be UCUM. + // (f:code or not(f:value)) and (not(exists(f:system)) or f:system/@value='http://unitsofmeasure.org') + +} diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/primitive/BoundCodeableConceptDt.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/primitive/BoundCodeableConceptDt.java new file mode 100644 index 00000000000..58cad302068 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/model/primitive/BoundCodeableConceptDt.java @@ -0,0 +1,125 @@ +package ca.uhn.fhir.model.primitive; + +/* + * #%L + * HAPI FHIR Structures - DSTU (FHIR 0.80) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import static org.apache.commons.lang3.StringUtils.defaultString; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import ca.uhn.fhir.model.api.IBoundCodeableConcept; +import ca.uhn.fhir.model.api.IValueSetEnumBinder; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt; +import ca.uhn.fhir.model.dstu.composite.CodingDt; + +@DatatypeDef(name = "CodeableConcept", isSpecialization = true) +public class BoundCodeableConceptDt> extends CodeableConceptDt implements IBoundCodeableConcept { + + private IValueSetEnumBinder myBinder; + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder) { + myBinder = theBinder; + } + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder, T theValue) { + myBinder = theBinder; + setValueAsEnum(theValue); + } + + /** + * Constructor + */ + public BoundCodeableConceptDt(IValueSetEnumBinder theBinder, Collection theValues) { + myBinder = theBinder; + setValueAsEnum(theValues); + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated types, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValue + * The value to add, or null + */ + public void setValueAsEnum(Collection theValues) { + getCoding().clear(); + if (theValues != null) { + for (T next : theValues) { + getCoding().add(new CodingDt(myBinder.toSystemString(next), myBinder.toCodeString(next))); + } + } + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated type, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValue + * The value to add, or null + */ + public void setValueAsEnum(T theValue) { + getCoding().clear(); + if (theValue == null) { + return; + } + getCoding().add(new CodingDt(myBinder.toSystemString(theValue), myBinder.toCodeString(theValue))); + } + + /** + * Loops through the {@link #getCoding() codings} in this codeable concept + * and returns the first bound enumerated type that matches. Use + * caution using this method, see the return description for more + * information. + * + * @return Returns the bound enumerated type, or null if none + * are found. Note that a null return value doesn't neccesarily + * imply that this Codeable Concept has no codes, only that it has + * no codes that match the enum. + */ + public Set getValueAsEnum() { + Set retVal = new HashSet(); + for (CodingDt next : getCoding()) { + if (next == null) { + continue; + } + T nextT = myBinder.fromCodeString(defaultString(next.getCode().getValue()), defaultString(next.getSystem().getValueAsString())); + if (nextT != null) { + retVal.add(nextT); + } else { + // TODO: throw special exception type? + } + } + return retVal; + } + +} diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java new file mode 100644 index 00000000000..99e917cf8ea --- /dev/null +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerConformanceProvider.java @@ -0,0 +1,358 @@ +package ca.uhn.fhir.rest.server.provider; + +/* + * #%L + * HAPI FHIR Structures - DSTU (FHIR 0.80) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.commons.lang3.StringUtils; + +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.context.RuntimeSearchParam; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Conformance.Rest; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestQuery; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceOperation; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam; +import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.RestfulConformanceModeEnum; +import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; +import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; +import ca.uhn.fhir.model.primitive.BooleanDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.annotation.Metadata; +import ca.uhn.fhir.rest.method.BaseMethodBinding; +import ca.uhn.fhir.rest.method.DynamicSearchMethodBinding; +import ca.uhn.fhir.rest.method.IParameter; +import ca.uhn.fhir.rest.method.SearchMethodBinding; +import ca.uhn.fhir.rest.method.SearchParameter; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.ResourceBinding; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.util.ExtensionConstants; + +/** + * Server FHIR Provider which serves the conformance statement for a RESTful server implementation + * + *

+ * Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is + * always returned unless {@link #setCache(boolean)} is called with a value of false. This means that if + * you are adding anything to the returned conformance instance on each call you should call + * setCache(false) in your provider constructor. + *

+ */ +public class ServerConformanceProvider { + + private boolean myCache = true; + private volatile Conformance myConformance; + private String myPublisher = "Not provided"; + private final RestfulServer myRestfulServer; + + public ServerConformanceProvider(RestfulServer theRestfulServer) { + myRestfulServer = theRestfulServer; + } + + /** + * Gets the value of the "publisher" that will be placed in the generated conformance statement. As this + * is a mandatory element, the value should not be null (although this is not enforced). The value defaults + * to "Not provided" but may be set to null, which will cause this element to be omitted. + */ + public String getPublisher() { + return myPublisher; + } + + /** + * Actually create and return the conformance statement + * + * See the class documentation for an important note if you are extending this class + */ + @Metadata + public Conformance getServerConformance() { + if (myConformance != null && myCache) { + return myConformance; + } + + Conformance retVal = new Conformance(); + + retVal.setPublisher(myPublisher); + retVal.setDate(DateTimeDt.withCurrentTime()); + retVal.setFhirVersion("0.80"); // TODO: pull from model + retVal.setAcceptUnknown(false); // TODO: make this configurable - this is a fairly big effort since the parser needs to be modified to actually allow it + + retVal.getImplementation().setDescription(myRestfulServer.getImplementationDescription()); + retVal.getSoftware().setName(myRestfulServer.getServerName()); + retVal.getSoftware().setVersion(myRestfulServer.getServerVersion()); + retVal.addFormat(Constants.CT_FHIR_XML); + retVal.addFormat(Constants.CT_FHIR_JSON); + + Rest rest = retVal.addRest(); + rest.setMode(RestfulConformanceModeEnum.SERVER); + + Set systemOps = new HashSet(); + + List bindings = new ArrayList(myRestfulServer.getResourceBindings()); + Collections.sort(bindings, new Comparator() { + @Override + public int compare(ResourceBinding theArg0, ResourceBinding theArg1) { + return theArg0.getResourceName().compareToIgnoreCase(theArg1.getResourceName()); + } + }); + + for (ResourceBinding next : bindings) { + + Set resourceOps = new HashSet(); + RestResource resource = rest.addResource(); + + String resourceName = next.getResourceName(); + RuntimeResourceDefinition def = myRestfulServer.getFhirContext().getResourceDefinition(resourceName); + resource.getType().setValue(def.getName()); + resource.getProfile().setReference(new IdDt(def.getResourceProfile())); + + TreeSet includes = new TreeSet(); + + // Map nameToSearchParam = new HashMap(); + for (BaseMethodBinding nextMethodBinding : next.getMethodBindings()) { + RestfulOperationTypeEnum resOp = nextMethodBinding.getResourceOperationType(); + if (resOp != null) { + if (resourceOps.contains(resOp) == false) { + resourceOps.add(resOp); + resource.addOperation().setCode(resOp); + } + } + + RestfulOperationSystemEnum sysOp = nextMethodBinding.getSystemOperationType(); + if (sysOp != null) { + if (systemOps.contains(sysOp) == false) { + systemOps.add(sysOp); + rest.addOperation().setCode(sysOp); + } + } + + if (nextMethodBinding instanceof SearchMethodBinding) { + handleSearchMethodBinding(rest, resource, resourceName, def, includes, (SearchMethodBinding) nextMethodBinding); + } else if (nextMethodBinding instanceof DynamicSearchMethodBinding) { + handleDynamicSearchMethodBinding(resource, def, includes, (DynamicSearchMethodBinding) nextMethodBinding); + } + + Collections.sort(resource.getOperation(), new Comparator() { + @Override + public int compare(RestResourceOperation theO1, RestResourceOperation theO2) { + RestfulOperationTypeEnum o1 = theO1.getCode().getValueAsEnum(); + RestfulOperationTypeEnum o2 = theO2.getCode().getValueAsEnum(); + if (o1 == null && o2 == null) { + return 0; + } + if (o1 == null) { + return 1; + } + if (o2 == null) { + return -1; + } + return o1.ordinal() - o2.ordinal(); + } + }); + + } + + for (String nextInclude : includes) { + resource.addSearchInclude(nextInclude); + } + + } + + myConformance = retVal; + return retVal; + } + + private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet includes, DynamicSearchMethodBinding searchMethodBinding) { + includes.addAll(searchMethodBinding.getIncludes()); + + List searchParameters = new ArrayList(); + searchParameters.addAll(searchMethodBinding.getSearchParams()); + sortRuntimeSearchParameters(searchParameters); + + if (!searchParameters.isEmpty()) { + + for (RuntimeSearchParam nextParameter : searchParameters) { + + String nextParamName = nextParameter.getName(); + + // String chain = null; + String nextParamUnchainedName = nextParamName; + if (nextParamName.contains(".")) { + // chain = nextParamName.substring(nextParamName.indexOf('.') + 1); + nextParamUnchainedName = nextParamName.substring(0, nextParamName.indexOf('.')); + } + + String nextParamDescription = nextParameter.getDescription(); + + /* + * If the parameter has no description, default to the one from the resource + */ + if (StringUtils.isBlank(nextParamDescription)) { + RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName); + if (paramDef != null) { + nextParamDescription = paramDef.getDescription(); + } + } + + RestResourceSearchParam param; + param = resource.addSearchParam(); + + param.setName(nextParamName); + // if (StringUtils.isNotBlank(chain)) { + // param.addChain(chain); + // } + param.setDocumentation(nextParamDescription); + param.setType(nextParameter.getParamType()); + } + } + } + + private void handleSearchMethodBinding(Rest rest, RestResource resource, String resourceName, RuntimeResourceDefinition def, TreeSet includes, SearchMethodBinding searchMethodBinding) { + includes.addAll(searchMethodBinding.getIncludes()); + + List params = searchMethodBinding.getParameters(); + List searchParameters = new ArrayList(); + for (IParameter nextParameter : params) { + if ((nextParameter instanceof SearchParameter)) { + searchParameters.add((SearchParameter) nextParameter); + } + } + sortSearchParameters(searchParameters); + if (!searchParameters.isEmpty()) { + boolean allOptional = searchParameters.get(0).isRequired() == false; + + RestQuery query = null; + if (!allOptional) { + query = rest.addQuery(); + query.getDocumentation().setValue(searchMethodBinding.getDescription()); + query.addUndeclaredExtension(false, ExtensionConstants.QUERY_RETURN_TYPE, new CodeDt(resourceName)); + for (String nextInclude : searchMethodBinding.getIncludes()) { + query.addUndeclaredExtension(false, ExtensionConstants.QUERY_ALLOWED_INCLUDE, new StringDt(nextInclude)); + } + } + + for (SearchParameter nextParameter : searchParameters) { + + String nextParamName = nextParameter.getName(); + + // String chain = null; + String nextParamUnchainedName = nextParamName; + if (nextParamName.contains(".")) { + // chain = nextParamName.substring(nextParamName.indexOf('.') + 1); + nextParamUnchainedName = nextParamName.substring(0, nextParamName.indexOf('.')); + } + + String nextParamDescription = nextParameter.getDescription(); + + /* + * If the parameter has no description, default to the one from the resource + */ + if (StringUtils.isBlank(nextParamDescription)) { + RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName); + if (paramDef != null) { + nextParamDescription = paramDef.getDescription(); + } + } + + RestResourceSearchParam param; + if (query == null) { + param = resource.addSearchParam(); + } else { + param = query.addParameter(); + param.addUndeclaredExtension(false, ExtensionConstants.PARAM_IS_REQUIRED, new BooleanDt(nextParameter.isRequired())); + } + + param.setName(nextParamName); + // if (StringUtils.isNotBlank(chain)) { + // param.addChain(chain); + // } + param.setDocumentation(nextParamDescription); + param.setType(nextParameter.getParamType()); + for (Class nextTarget : nextParameter.getDeclaredTypes()) { + RuntimeResourceDefinition targetDef = myRestfulServer.getFhirContext().getResourceDefinition(nextTarget); + if (targetDef != null) { + ResourceTypeEnum code = ResourceTypeEnum.VALUESET_BINDER.fromCodeString(targetDef.getName()); + if (code != null) { + param.addTarget(code); + } + } + } + } + } + } + + /** + * Sets the cache property (default is true). If set to true, the same response will be returned for each + * invocation. + *

+ * See the class documentation for an important note if you are extending this class + *

+ */ + public void setCache(boolean theCache) { + myCache = theCache; + } + + /** + * Sets the value of the "publisher" that will be placed in the generated conformance statement. As this + * is a mandatory element, the value should not be null (although this is not enforced). The value defaults + * to "Not provided" but may be set to null, which will cause this element to be omitted. + */ + public void setPublisher(String thePublisher) { + myPublisher = thePublisher; + } + + private void sortRuntimeSearchParameters(List searchParameters) { + Collections.sort(searchParameters, new Comparator() { + @Override + public int compare(RuntimeSearchParam theO1, RuntimeSearchParam theO2) { + return theO1.getName().compareTo(theO2.getName()); + } + }); + } + + private void sortSearchParameters(List searchParameters) { + Collections.sort(searchParameters, new Comparator() { + @Override + public int compare(SearchParameter theO1, SearchParameter theO2) { + if (theO1.isRequired() == theO2.isRequired()) { + return theO1.getName().compareTo(theO2.getName()); + } + if (theO1.isRequired()) { + return -1; + } + return 1; + } + }); + } +} diff --git a/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerProfileProvider.java b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerProfileProvider.java new file mode 100644 index 00000000000..0bfaf1d1d22 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/main/java/ca/uhn/fhir/rest/server/provider/ServerProfileProvider.java @@ -0,0 +1,79 @@ +package ca.uhn.fhir.rest.server.provider; + +/* + * #%L + * HAPI FHIR Structures - DSTU (FHIR 0.80) + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Profile; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.server.IResourceProvider; + +public class ServerProfileProvider implements IResourceProvider { + + private FhirContext myContext; + + public ServerProfileProvider(FhirContext theCtx) { + myContext = theCtx; + } + + @Override + public Class getResourceType() { + return Profile.class; + } + + @Read() + public Profile getProfileById(@IdParam IdDt theId) { + RuntimeResourceDefinition retVal = myContext.getResourceDefinitionById(theId.getIdPart()); + if (retVal==null) { + return null; + } + return (Profile) retVal.toProfile(); + } + + @Search() + public List getAllProfiles() { + List defs = new ArrayList(myContext.getResourceDefinitions()); + Collections.sort(defs, new Comparator() { + @Override + public int compare(RuntimeResourceDefinition theO1, RuntimeResourceDefinition theO2) { + int cmp = theO1.getName().compareTo(theO2.getName()); + if (cmp==0) { + cmp=theO1.getResourceProfile().compareTo(theO2.getResourceProfile()); + } + return cmp; + }}); + ArrayList retVal = new ArrayList(); + for (RuntimeResourceDefinition next : defs) { + retVal.add((Profile) next.toProfile()); + } + return retVal; + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/CustomObservation.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/CustomObservation.java new file mode 100644 index 00000000000..0ff66e9d594 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/CustomObservation.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.context; + +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.dstu.resource.Observation; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * Created by Bill de Beaubien on 10/31/2014. + */ +@ResourceDef(name="Observation", id="customobservation") +public class CustomObservation extends Observation { + @Child(name = "valueUnits", order = 3) + @Extension(url = "http://hapi.test.com/profile/customobservation#valueUnits", definedLocally = true, isModifier = false) + @Description(shortDefinition = "Units on an observation whose type is of valueString") + private StringDt myValueUnits; + + public StringDt getValueUnits() { + if (myValueUnits == null) { + myValueUnits = new StringDt(); + } + return myValueUnits; + } + + public void setValueUnits(StringDt theValueUnits) { + myValueUnits = theValueUnits; + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/DummyPatientWithExtensions.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/DummyPatientWithExtensions.java new file mode 100644 index 00000000000..859391ce0dd --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/DummyPatientWithExtensions.java @@ -0,0 +1,92 @@ +package ca.uhn.fhir.context; + +//START SNIPPET: patientDef +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 ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.util.ElementUtil; + +/** + * Definition class for adding extensions to the built-in + * Patient resource type. + */ +@ResourceDef(name="Patient") +public class DummyPatientWithExtensions extends Patient { + + + /** + * Each extension is defined in a field. Any valid HAPI Data Type + * can be used for the field type. Note that the [name=""] attribute + * in the @Child annotation needs to match the name for the bean accessor + * and mutator methods. + */ + @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 StringDt myPetName; + + /** + * The second example extension uses a List type to provide + * repeatable values. Note that a [max=] value has been placed in + * the @Child annotation. + * + * Note also that this extension is a modifier extension + */ + @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 this patient") + private List myImportantDates; + + /** + * It is important to override the isEmpty() method, adding a check for any + * newly added fields. + */ + @Override + public boolean isEmpty() { + return super.isEmpty() && ElementUtil.isEmpty(myPetName, myImportantDates); + } + + /******** + * Accessors and mutators follow + * + * IMPORTANT: + * Each extension is required to have an getter/accessor and a stter/mutator. + * You are highly recommended to create getters which create instances if they + * do not already exist, since this is how the rest of the HAPI FHIR API works. + ********/ + + /** Getter for important dates */ + public List getImportantDates() { + if (myImportantDates==null) { + myImportantDates = new ArrayList(); + } + return myImportantDates; + } + + /** Getter for pet name */ + public StringDt getPetName() { + if (myPetName == null) { + myPetName = new StringDt(); + } + return myPetName; + } + + /** Setter for important dates */ + public void setImportantDates(List theImportantDates) { + myImportantDates = theImportantDates; + } + + /** Setter for pet name */ + public void setPetName(StringDt thePetName) { + myPetName = thePetName; + } + +} +//END SNIPPET: patientDef diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ExtensionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ExtensionTest.java new file mode 100644 index 00000000000..afd83146fd6 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ExtensionTest.java @@ -0,0 +1,87 @@ +package ca.uhn.fhir.context; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.io.IOException; + +import org.junit.Test; + +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.parser.MyPatient; + +public class ExtensionTest { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExtensionTest.class); + + private static FhirContext ourCtx = new FhirContext(); + + @Test + public void testExtensionType() { + + DummyPatientWithExtensions patient = new DummyPatientWithExtensions(); + patient.setPetName(new StringDt("Fido")); + patient.getImportantDates().add(new DateTimeDt("2010-01-02")); + patient.getImportantDates().add(new DateTimeDt("2014-01-26T11:11:11")); + + patient.addName().addFamily("Smith").addGiven("John").addGiven("Quincy").addSuffix("Jr"); + + String messageString = ourCtx.newXmlParser().encodeResourceToString(patient); + ourLog.info(messageString); + assertThat(messageString, containsString("")); + } + + @Test + public void testEmptyExtensionType() { + DummyPatientWithExtensions patient = new DummyPatientWithExtensions(); + patient.addName().addFamily("Smith").addGiven("John").addGiven("Quincy").addSuffix("Jr"); + String messageString = ourCtx.newXmlParser().encodeResourceToString(patient); + ourLog.info(messageString); + + assertThat(messageString, not(containsString("xtension"))); + + } + + + @Test + public void testEmptyExtensionTypeJson() { + DummyPatientWithExtensions patient = new DummyPatientWithExtensions(); + patient.addName().addFamily("Smith").addGiven("John").addGiven("Quincy").addSuffix("Jr"); + String messageString = ourCtx.newJsonParser().encodeResourceToString(patient); + ourLog.info(messageString); + + assertThat(messageString, not(containsString("xtension"))); + + } + + @SuppressWarnings("unused") + public static void main(String[] args) throws DataFormatException, IOException { + // START SNIPPET: patientUse + MyPatient patient = new MyPatient(); + patient.setPetName(new StringDt("Fido")); + patient.getImportantDates().add(new DateTimeDt("2010-01-02")); + patient.getImportantDates().add(new DateTimeDt("2014-01-26T11:11:11")); + + patient.addName().addFamily("Smith").addGiven("John").addGiven("Quincy").addSuffix("Jr"); + + IParser p = new FhirContext().newXmlParser().setPrettyPrint(true); + String messageString = p.encodeResourceToString(patient); + + System.out.println(messageString); + // END SNIPPET: patientUse + + // START SNIPPET: patientParse + IParser parser = new FhirContext().newXmlParser(); + MyPatient newPatient = parser.parseResource(MyPatient.class, messageString); + // END SNIPPET: patientParse + + { + FhirContext ctx2 = new FhirContext(); + RuntimeResourceDefinition def = ctx2.getResourceDefinition(patient); + System.out.println(ctx2.newXmlParser().setPrettyPrint(true).encodeResourceToString(def.toProfile())); + } + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/FhirContextTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/FhirContextTest.java new file mode 100644 index 00000000000..2df0eefba6a --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/FhirContextTest.java @@ -0,0 +1,18 @@ +package ca.uhn.fhir.context; + +import org.junit.Test; + +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.resource.ValueSet; + +public class FhirContextTest { + + @Test + public void testIncrementalScan() { + + FhirContext ctx = new FhirContext(); + ctx.getResourceDefinition(ValueSet.class); + ctx.getResourceDefinition(Patient.class); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelExtensionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelExtensionTest.java new file mode 100644 index 00000000000..c45d3f1d51a --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelExtensionTest.java @@ -0,0 +1,38 @@ +package ca.uhn.fhir.context; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.parser.MyOrganization; +import ca.uhn.fhir.parser.MyPatient; + +public class ModelExtensionTest { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ModelExtensionTest.class); + private FhirContext ourCtx = new FhirContext(); + + @Test + public void testModelExtension() throws DataFormatException { + MyOrganization org = new MyOrganization(); + org.getName().setValue("org0"); + + MyPatient patient = new MyPatient(); + patient.addIdentifier("foo", "bar"); + patient.getManagingOrganization().setResource(org); + + IParser p = ourCtx.newXmlParser().setPrettyPrint(true); + String str = p.encodeResourceToString(patient); + + ourLog.info(str); + + MyPatient parsed = ourCtx.newXmlParser().parseResource(MyPatient.class, str); + assertEquals("foo", parsed.getIdentifierFirstRep().getSystem().getValueAsString()); + +// assertEquals(MyOrganization.class, parsed.getManagingOrganization().getResource().getClass()); +// MyOrganization parsedOrg = (MyOrganization) parsed.getManagingOrganization().getResource(); +// assertEquals("arg0", parsedOrg.getName().getValue()); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelScannerTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelScannerTest.java new file mode 100644 index 00000000000..bd19fad8660 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ModelScannerTest.java @@ -0,0 +1,69 @@ +package ca.uhn.fhir.context; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.model.dstu.resource.CarePlan; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.parser.MyPatient; + +public class ModelScannerTest { + + /** This failed at one point */ + @Test + public void testCarePlan() throws DataFormatException { + new ModelScanner(new FhirContext(), CarePlan.class); + } + + @Test + public void testExtendedClass() { + FhirContext ctx = new FhirContext(); + ctx.getResourceDefinition(MyPatient.class); + + RuntimeResourceDefinition patient = ctx.getResourceDefinition("Patient"); + assertEquals(Patient.class, patient.getImplementingClass()); + + RuntimeResourceDefinition def = ctx.getResourceDefinition(MyPatient.class); + RuntimeResourceDefinition baseDef = def.getBaseDefinition(); + assertEquals(Patient.class,baseDef.getImplementingClass()); + } + + + @Test + public void testScanExtensionTypes() throws DataFormatException { + + ModelScanner scanner = new ModelScanner(new FhirContext(),ResourceWithExtensionsA.class); + RuntimeResourceDefinition def = (RuntimeResourceDefinition) scanner.getClassToElementDefinitions().get(ResourceWithExtensionsA.class); + + assertEquals(RuntimeChildCompositeDatatypeDefinition.class, def.getChildByNameOrThrowDataFormatException("identifier").getClass()); + + RuntimeChildDeclaredExtensionDefinition ext = def.getDeclaredExtension("http://foo/#f1"); + assertNotNull(ext); + BaseRuntimeElementDefinition valueString = ext.getChildByName("valueString"); + assertNotNull(valueString); + + ext = def.getDeclaredExtension("http://foo/#f2"); + assertNotNull(ext); + valueString = ext.getChildByName("valueString"); + assertNotNull(valueString); + + ext = def.getDeclaredExtension("http://bar/#b1"); + assertNotNull(ext); + RuntimeChildDeclaredExtensionDefinition childExt = ext.getChildExtensionForUrl("http://bar/#b1/1"); + assertNotNull(childExt); + BaseRuntimeElementDefinition valueDate = childExt.getChildByName("valueDate"); + assertNotNull(valueDate); + childExt = ext.getChildExtensionForUrl("http://bar/#b1/2"); + assertNotNull(childExt); + childExt = childExt.getChildExtensionForUrl("http://bar/#b1/2/1"); + assertNotNull(childExt); + valueDate = childExt.getChildByName("valueDate"); + assertNotNull(valueDate); + + } + + + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/NameChanges.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/NameChanges.java new file mode 100644 index 00000000000..3ec0ba71aab --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/NameChanges.java @@ -0,0 +1,81 @@ +package ca.uhn.fhir.context; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; + +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum; + +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.ClassPath; +import com.google.common.reflect.ClassPath.ClassInfo; + +public class NameChanges { + + @SuppressWarnings("unchecked") + @Test + public void testNameChanges() throws IOException, ClassNotFoundException { + FhirContext ctx = new FhirContext(); + ImmutableSet names = ClassPath.from(getClass().getClassLoader()).getTopLevelClasses(Patient.class.getPackage().getName()); + List changes = new ArrayList(); + + for (ClassInfo classInfo : names) { + + RuntimeResourceDefinition def = ctx.getResourceDefinition((Class) Class.forName(classInfo.getName())); + for (RuntimeSearchParam nextParam : def.getSearchParams()) { + if (nextParam.getParamType() == SearchParamTypeEnum.COMPOSITE) { + continue; + } + + String name = nextParam.getName(); + if (name.contains("[x]")) { + continue; + } + + if (name.startsWith("_")) { + continue; // _id and _language + } + + String path = nextParam.getPath(); + + if (path.contains(" | ")) { + changes.add(def.getName() + ": " + name + " has multiple paths so there is no obvious name (" + nextParam.getDescription() + ")"); + continue; + } + + path = path.substring(path.indexOf('.') + 1); + + StringBuilder b = new StringBuilder(); + for (int i = 0; i < path.length(); i++) { + char nextChar = path.charAt(i); + if (Character.isUpperCase(nextChar)) { + b.append('-'); + }else if (nextChar == '.') { + b.append('-'); + continue; + } + b.append(Character.toLowerCase(nextChar)); + } + + if (name.equals(b.toString())==false) { + changes.add(def.getName() + "," + name + "," + b + "," + nextParam.getDescription()); + } + } + + + } + + System.out.println("Resource,old name,new name,description"); + + for (String next : changes) { + System.out.println(next); + } + + } + +} + diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ResourceWithExtensionsA.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ResourceWithExtensionsA.java new file mode 100644 index 00000000000..c623741af8e --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/ResourceWithExtensionsA.java @@ -0,0 +1,205 @@ +package ca.uhn.fhir.context; + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.BaseResource; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IExtension; +import ca.uhn.fhir.model.api.annotation.*; +import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.primitive.DateDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.StringDt; + +@ResourceDef(name = "ResourceWithExtensionsA", id="0001") +public class ResourceWithExtensionsA extends BaseResource { + + /* + * NB: several unit tests depend on the structure here + * so check the unit tests immediately after any changes + */ + + @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 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 = "foo1", type = StringDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED) + @Extension(url = "http://foo/#f1", definedLocally=true, isModifier=false) + private List myFoo1; + + @Child(name = "foo2", type = StringDt.class, order = 1, min = 0, max = 1) + @Extension(url = "http://foo/#f2", definedLocally=true, isModifier=true) + private StringDt myFoo2; + + @Child(name="baz", type = CodeableConceptDt.class, order = 4) + @Extension(url= "http://baz/#baz", definedLocally=true, isModifier=false) + @Description(shortDefinition = "Contains a codeable concept") + private CodeableConceptDt myBaz; + + @Child(name = "identifier", type = IdentifierDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED) + private List myIdentifier; + + public List getBar1() { + return myBar1; + } + + public Bar1 getBar2() { + return myBar2; + } + + public List getFoo1() { + return myFoo1; + } + + public StringDt getFoo2() { + return myFoo2; + } + + public CodeableConceptDt getBaz() { return myBaz; } + + public List getIdentifier() { + return myIdentifier; + } + + public void setBar1(List theBar1) { + myBar1 = theBar1; + } + + public void setBar2(Bar1 theBar2) { + myBar2 = theBar2; + } + + public void setFoo1(List theFoo1) { + myFoo1 = theFoo1; + } + + public void setFoo2(StringDt theFoo2) { + myFoo2 = theFoo2; + } + + public void setBaz(CodeableConceptDt myBaz) { this.myBaz = myBaz; } + + public void setIdentifier(List theValue) { + myIdentifier = theValue; + } + + @Block(name = "Bar1") + public static class Bar1 extends BaseIdentifiableElement implements IExtension { + + public Bar1() { + super(); + } + + @Child(name = "bar11", type = DateDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED) + @Extension(url = "http://bar/#b1/1", definedLocally=true, isModifier=false) + private List myBar11; + + @Child(name = "bar12", type = DateDt.class, order = 1, min = 0, max = Child.MAX_UNLIMITED) + @Extension(url = "http://bar/#b1/2", definedLocally=true, isModifier=false) + private List myBar12; + + private IdDt myId; + + @Override + public boolean isEmpty() { + return false; // not implemented + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType ); // not implemented + } + + + public List getBar11() { + return myBar11; + } + + public List getBar12() { + return myBar12; + } + + public void setBar11(List theBar11) { + myBar11 = theBar11; + } + + public void setBar12(List theBar12) { + myBar12 = theBar12; + } + + @Override + public void setId(IdDt theId) { + myId=theId; + } + + @Override + public IdDt getId() { + return myId; + } + + + + } + + @Block(name = "Bar2") + public static class Bar2 extends BaseIdentifiableElement implements IExtension { + + @Child(name = "bar121", type = DateDt.class, order = 0, min = 0, max = Child.MAX_UNLIMITED) + @Extension(url = "http://bar/#b1/2/1", definedLocally=true, isModifier=false) + private List myBar121; + + @Child(name = "bar122", type = DateDt.class, order = 1, min = 0, max = Child.MAX_UNLIMITED) + @Extension(url = "http://bar/#b1/2/2", definedLocally=true, isModifier=false) + private List myBar122; + + @Override + public boolean isEmpty() { + return false; // not implemented + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType ); // not implemented + } + + + public List getBar121() { + return myBar121; + } + + public List getBar122() { + return myBar122; + } + + public void setBar121(List theBar121) { + myBar121 = theBar121; + } + + public void setBar122(List theBar122) { + myBar122 = theBar122; + } + + + + } + + @Override + public boolean isEmpty() { + return false; // not implemented + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType ); // not implemented + } + + + + +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/RuntimeResourceDefinitionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/RuntimeResourceDefinitionTest.java new file mode 100644 index 00000000000..bf470e20bca --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/context/RuntimeResourceDefinitionTest.java @@ -0,0 +1,105 @@ +package ca.uhn.fhir.context; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.resource.Profile; +import ca.uhn.fhir.model.dstu.resource.Profile.ExtensionDefn; +import ca.uhn.fhir.model.dstu.resource.Profile.Structure; +import ca.uhn.fhir.model.dstu.resource.Profile.StructureElement; +import ca.uhn.fhir.model.dstu.resource.ValueSet; +import ca.uhn.fhir.model.dstu.valueset.DataTypeEnum; + +public class RuntimeResourceDefinitionTest { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(RuntimeResourceDefinitionTest.class); + + @Test + public void testToProfileStandard() throws Exception { + FhirContext ctx = new FhirContext(Patient.class, Profile.class); + RuntimeResourceDefinition def = ctx.getResourceDefinition(Patient.class); + + Profile profile = (Profile) def.toProfile(); + + ourLog.info(ctx.newXmlParser().encodeResourceToString(profile)); + + Structure struct = profile.getStructure().get(0); + assertEquals("Patient", struct.getElement().get(0).getPath().getValue()); + assertEquals("Patient.extension", struct.getElement().get(1).getPath().getValue()); + assertEquals("Patient.modifierExtension", struct.getElement().get(2).getPath().getValue()); + assertEquals("Patient.text", struct.getElement().get(3).getPath().getValue()); + assertEquals("Patient.contained", struct.getElement().get(4).getPath().getValue()); + assertEquals("Patient.language", struct.getElement().get(5).getPath().getValue()); + + } + + @Test + public void testToProfileValueSet() throws Exception { + FhirContext ctx = new FhirContext(ValueSet.class, Profile.class); + RuntimeResourceDefinition def = ctx.getResourceDefinition(ValueSet.class); + + Profile profile = (Profile) def.toProfile(); + + String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(profile); + ourLog.info(encoded); + + assertTrue(encoded.contains("")); + + } + + + @Test + public void testToProfileExtensions() throws Exception { + FhirContext ctx = new FhirContext(ResourceWithExtensionsA.class, Profile.class); + RuntimeResourceDefinition def = ctx.getResourceDefinition(ResourceWithExtensionsA.class); + + Profile profile = (Profile) def.toProfile(); + + ourLog.info(ctx.newXmlParser().encodeResourceToString(profile)); + + List element = profile.getStructure().get(0).getElement(); + assertEquals(1, element.get(0).getDefinition().getType().size()); + assertEquals("Resource", element.get(0).getDefinition().getType().get(0).getCode().getValue()); + + ExtensionDefn ext = profile.getExtensionDefn().get(1); + assertEquals("b1/1", ext.getCode().getValue()); + assertEquals(DataTypeEnum.DATE.getCode(), ext.getDefinition().getType().get(0).getCode().getValue()); + + ext = profile.getExtensionDefn().get(2); + assertEquals("b1/2", ext.getCode().getValue()); + assertEquals(DataTypeEnum.EXTENSION, ext.getDefinition().getType().get(0).getCode().getValueAsEnum()); + assertEquals("#b1/2/1", ext.getDefinition().getType().get(0).getProfile().getValueAsString()); + assertEquals(DataTypeEnum.EXTENSION, ext.getDefinition().getType().get(1).getCode().getValueAsEnum()); + assertEquals("#b1/2/2", ext.getDefinition().getType().get(1).getProfile().getValueAsString()); + + assertEquals("ResourceWithExtensionsA.extension", element.get(1).getPath().getValue()); + assertEquals("ResourceWithExtensionsA.extension", element.get(2).getPath().getValue()); + assertEquals("ResourceWithExtensionsA.extension", element.get(3).getPath().getValue()); + assertEquals("ResourceWithExtensionsA.extension", element.get(4).getPath().getValue()); + assertEquals("ResourceWithExtensionsA.extension", element.get(5).getPath().getValue()); + assertEquals("ResourceWithExtensionsA.modifierExtension", element.get(6).getPath().getValue()); + + assertEquals(DataTypeEnum.EXTENSION, element.get(1).getDefinition().getType().get(0).getCode().getValueAsEnum()); + assertEquals("url", element.get(1).getSlicing().getDiscriminator().getValue()); + + assertEquals(DataTypeEnum.EXTENSION, element.get(2).getDefinition().getType().get(0).getCode().getValueAsEnum()); + assertEquals("#f1", element.get(2).getDefinition().getType().get(0).getProfile().getValueAsString()); + + assertEquals("ResourceWithExtensionsA.identifier", element.get(13).getPath().getValue()); + + } + + @Test + public void testProfileIdIsActualResourceName() { + FhirContext ctx = new FhirContext(CustomObservation.class); + RuntimeResourceDefinition def = ctx.getResourceDefinition(CustomObservation.class); + + Profile profile = (Profile) def.toProfile(); + + assertEquals("customobservation", profile.getId().toString()); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/api/TagListTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/api/TagListTest.java new file mode 100644 index 00000000000..bcce42d2a6e --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/api/TagListTest.java @@ -0,0 +1,81 @@ +package ca.uhn.fhir.model.api; + +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.junit.Assert.*; + +import java.util.Arrays; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.resource.Patient; + +public class TagListTest { + + private FhirContext myCtx = new FhirContext(); + + @Test + public void testEquals() { + TagList tagList1 = new TagList(); + tagList1.addTag(null, "Dog", "Puppies"); + tagList1.addTag("http://foo", "Cat", "Kittens"); + + TagList tagList2 = new TagList(); + tagList2.addTag(null, "Dog", "Puppies"); + tagList2.addTag("http://foo", "Cat", "Kittens"); + + assertEquals(tagList1,tagList2); + } + + @Test + public void testEqualsIgnoresLabel() { + TagList tagList1 = new TagList(); + tagList1.addTag(null, "Dog", "AAAA"); + tagList1.addTag("http://foo", "Cat", "BBBB"); + + TagList tagList2 = new TagList(); + tagList2.addTag(null, "Dog", "Puppies"); + tagList2.addTag("http://foo", "Cat", "Kittens"); + + assertEquals(tagList1,tagList2); + } + + + @Test + public void testEqualsIgnoresOrder() { + TagList tagList1 = new TagList(); + tagList1.addTag(null, "Dog", "Puppies"); + tagList1.addTag("http://foo", "Cat", "Kittens"); + + TagList tagList2 = new TagList(); + tagList2.addTag("http://foo", "Cat", "Kittens"); + tagList2.addTag(null, "Dog", "Puppies"); + + assertEquals(tagList1,tagList2); + } + + @Test + public void testPreventDuplication() { + + Patient patient = new Patient(); + patient.addIdentifier("urn:system", "testTagsWithCreateAndReadAndSearch"); + patient.addName().addFamily("Tester").addGiven("Joe"); + TagList tagList = new TagList(); + tagList.addTag(null, "Dog", "Puppies"); + // Add this twice + tagList.addTag("http://foo", "Cat", "Kittens"); + tagList.addTag("http://foo", "Cat", "Kittens"); + + patient.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList); + + Bundle b = new Bundle(); + b.addResource(patient, myCtx, "http://foo"); + + String encoded = myCtx.newXmlParser().encodeBundleToString(b); + assertThat(encoded, stringContainsInOrder(Arrays.asList("Cat", "Kittens"))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("Cat", "Kittens", "Cat", "Kittens")))); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/Base64BinaryDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/Base64BinaryDtTest.java new file mode 100644 index 00000000000..ff1e3d02a52 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/Base64BinaryDtTest.java @@ -0,0 +1,13 @@ +package ca.uhn.fhir.model.primitive; + +import org.junit.Test; + + +public class Base64BinaryDtTest { + + @Test + public void testDecodeNull() { + new Base64BinaryDt().setValueAsString(null); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/BaseDateTimeDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/BaseDateTimeDtTest.java new file mode 100644 index 00000000000..37c4b5f037b --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/BaseDateTimeDtTest.java @@ -0,0 +1,148 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.*; + +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +import org.apache.commons.lang3.time.FastDateFormat; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import ca.uhn.fhir.parser.DataFormatException; + +public class BaseDateTimeDtTest { + private SimpleDateFormat myDateInstantParser; + private FastDateFormat myDateInstantZoneParser; + + @Before + public void before() { + myDateInstantParser = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS"); + myDateInstantZoneParser = FastDateFormat.getInstance("yyyy-MM-dd HH:mm:ss.SSSZ", TimeZone.getTimeZone("GMT-02:00")); + } + + @Test + public void testParseYear() throws DataFormatException { + DateTimeDt dt = new DateTimeDt(); + dt.setValueAsString("2013"); + + assertEquals("2013", myDateInstantParser.format(dt.getValue()).substring(0, 4)); + assertEquals("2013", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertNull(dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.YEAR, dt.getPrecision()); + } + + @Test() + public void testParseMalformatted() throws DataFormatException { + DateTimeDt dt = new DateTimeDt("20120102"); + assertEquals("2012-01-02",dt.getValueAsString()); + } + + @Test + public void testParseMonth() throws DataFormatException { + DateTimeDt dt = new DateTimeDt(); + dt.setValueAsString("2013-02"); + + assertEquals("2013-02", myDateInstantParser.format(dt.getValue()).substring(0, 7)); + assertEquals("2013-02", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertNull(dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.MONTH, dt.getPrecision()); + } + + @Test + public void testParseMonthNoDashes() throws DataFormatException { + DateTimeDt dt = new DateTimeDt(); + dt.setValueAsString("201302"); + + assertEquals("2013-02", myDateInstantParser.format(dt.getValue()).substring(0, 7)); + assertEquals("2013-02", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertNull(dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.MONTH, dt.getPrecision()); + } + + @Test + public void testParseDay() throws DataFormatException { + DateTimeDt dt = new DateTimeDt(); + dt.setValueAsString("2013-02-03"); + + assertEquals("2013-02-03", myDateInstantParser.format(dt.getValue()).substring(0, 10)); + assertEquals("2013-02-03", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertNull(dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.DAY, dt.getPrecision()); + } + + @Test + public void testParseSecond() throws DataFormatException { + DateTimeDt dt = new DateTimeDt(); + dt.setValueAsString("2013-02-03T11:22:33"); + + assertEquals("2013-02-03 11:22:33", myDateInstantParser.format(dt.getValue()).substring(0, 19)); + assertEquals("2013-02-03T11:22:33", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertNull(dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.SECOND, dt.getPrecision()); + } + + @Test + public void testParseSecondZone() throws DataFormatException { + DateTimeDt dt = new DateTimeDt(); + dt.setValueAsString("2013-02-03T11:22:33-02:00"); + + assertEquals("2013-02-03T11:22:33-02:00", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertEquals(TimeZone.getTimeZone("GMT-02:00"), dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.SECOND, dt.getPrecision()); + } + + @Test + public void testParseSecondulu() throws DataFormatException { + DateTimeDt dt = new DateTimeDt(); + dt.setValueAsString("2013-02-03T11:22:33Z"); + + assertEquals("2013-02-03T11:22:33Z", dt.getValueAsString()); + assertEquals(true, dt.isTimeZoneZulu()); + assertEquals(null, dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.SECOND, dt.getPrecision()); + } + + @Test + public void testParseMilli() throws DataFormatException { + InstantDt dt = new InstantDt(); + dt.setValueAsString("2013-02-03T11:22:33.234"); + + assertEquals("2013-02-03 11:22:33.234", myDateInstantParser.format(dt.getValue()).substring(0, 23)); + assertEquals("2013-02-03T11:22:33.234", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertNull(dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.MILLI, dt.getPrecision()); + } + + @Test + public void testParseMilliZone() throws DataFormatException { + InstantDt dt = new InstantDt(); + dt.setValueAsString("2013-02-03T11:22:33.234-02:00"); + + assertEquals("2013-02-03 11:22:33.234-0200", myDateInstantZoneParser.format(dt.getValue())); + assertEquals("2013-02-03T11:22:33.234-02:00", dt.getValueAsString()); + assertEquals(false, dt.isTimeZoneZulu()); + assertEquals(TimeZone.getTimeZone("GMT-02:00"), dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.MILLI, dt.getPrecision()); + } + + @Test + public void testParseMilliZulu() throws DataFormatException { + InstantDt dt = new InstantDt(); + dt.setValueAsString("2013-02-03T11:22:33.234Z"); + + assertEquals("2013-02-03 09:22:33.234-0200", myDateInstantZoneParser.format(dt.getValue())); + assertEquals("2013-02-03T11:22:33.234Z", dt.getValueAsString()); + assertEquals(true, dt.isTimeZoneZulu()); + assertNull(dt.getTimeZone()); + assertEquals(TemporalPrecisionEnum.MILLI, dt.getPrecision()); + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/CodingDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/CodingDtTest.java new file mode 100644 index 00000000000..32639296ac4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/CodingDtTest.java @@ -0,0 +1,55 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.model.dstu.composite.CodingDt; + +public class CodingDtTest { + + @Test + public void testTokenNoSystem() { + CodingDt dt = new CodingDt(); + dt.setValueAsQueryToken(null, "c"); + + assertEquals(null, dt.getSystem().getValueAsString()); + assertEquals("c", dt.getCode().getValue()); + assertEquals("c", dt.getValueAsQueryToken()); + } + + @Test + public void testTokenWithPipeInValue() { + CodingDt dt = new CodingDt(); + dt.setValueAsQueryToken(null, "a|b|c"); + + assertEquals("a", dt.getSystem().getValueAsString()); + assertEquals("b|c", dt.getCode().getValue()); + assertEquals("a|b\\|c", dt.getValueAsQueryToken()); + } + + @Test + public void testTokenWithPipeInValueAndNoSystem() { + CodingDt dt = new CodingDt(); + dt.setValueAsQueryToken(null, "|b\\|c"); + + assertEquals("", dt.getSystem().getValueAsString()); + assertEquals("b|c", dt.getCode().getValue()); + + assertEquals("|b\\|c", dt.getValueAsQueryToken()); + } + + /** + * Technically the second pipe should have been escaped.. But we should be nice about it + */ + @Test + public void testTokenWithPipeInValueAndNoSystemAndBeLenient() { + CodingDt dt = new CodingDt(); + dt.setValueAsQueryToken(null, "|b|c"); + + assertEquals("", dt.getSystem().getValueAsString()); + assertEquals("b|c", dt.getCode().getValue()); + + assertEquals("|b\\|c", dt.getValueAsQueryToken()); + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/DecimalDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/DecimalDtTest.java new file mode 100644 index 00000000000..1887c9c8fc2 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/DecimalDtTest.java @@ -0,0 +1,16 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class DecimalDtTest { + + @Test + public void testPrecision() { + DecimalDt dt = new DecimalDt(2.03); + assertEquals("2.03", dt.getValueAsString()); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/IdDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/IdDtTest.java new file mode 100644 index 00000000000..aca7aa2519d --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/IdDtTest.java @@ -0,0 +1,165 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.*; + +import java.math.BigDecimal; + +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Patient; + +public class IdDtTest { + + private static FhirContext ourCtx; + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IdDtTest.class); + + @Test + public void testDetectLocal() { + + IdDt id = new IdDt("#123"); + assertEquals("#123", id.getValue()); + assertTrue(id.isLocal()); + + } + + @Test + public void testDetermineBase() { + + IdDt rr; + + rr = new IdDt("http://foo/fhir/Organization/123"); + assertEquals("http://foo/fhir", rr.getBaseUrl()); + + rr = new IdDt("http://foo/fhir/Organization/123/_history/123"); + assertEquals("http://foo/fhir", rr.getBaseUrl()); + + rr = new IdDt("Organization/123/_history/123"); + assertEquals(null, rr.getBaseUrl()); + + } + + @Test + public void testParseValueAbsolute() { + Patient patient = new Patient(); + IdDt rr = new IdDt(); + rr.setValue("http://foo/fhir/Organization/123"); + + patient.setManagingOrganization(new ResourceReferenceDt(rr)); + + Patient actual = parseAndEncode(patient); + ResourceReferenceDt ref = actual.getManagingOrganization(); + assertEquals("Organization", ref.getReference().getResourceType()); + assertEquals("123", ref.getReference().getIdPart()); + + } + + @Test + public void testBigDecimalIds() { + + IdDt id = new IdDt(new BigDecimal("123")); + assertEquals(id.getIdPartAsBigDecimal(), new BigDecimal("123")); + + } + + @Test + public void testParseValueAbsoluteWithVersion() { + Patient patient = new Patient(); + IdDt rr = new IdDt(); + rr.setValue("http://foo/fhir/Organization/123/_history/999"); + patient.setManagingOrganization(new ResourceReferenceDt(rr)); + + Patient actual = parseAndEncode(patient); + ResourceReferenceDt ref = actual.getManagingOrganization(); + assertEquals("Organization", ref.getReference().getResourceType()); + assertEquals("123", ref.getReference().getIdPart()); + assertEquals("999", ref.getReference().getVersionIdPart()); + + } + + @Test + public void testParseValueWithVersion() { + Patient patient = new Patient(); + IdDt rr = new IdDt(); + rr.setValue("/123/_history/999"); + patient.setManagingOrganization(new ResourceReferenceDt(rr)); + + Patient actual = parseAndEncode(patient); + ResourceReferenceDt ref = actual.getManagingOrganization(); + assertEquals(null, ref.getReference().getResourceType()); + assertEquals("123", ref.getReference().getIdPart()); + assertEquals("999", ref.getReference().getVersionIdPart()); + + } + + @Test + public void testParseValueMissingType1() { + Patient patient = new Patient(); + IdDt rr = new IdDt(); + rr.setValue("/123"); + patient.setManagingOrganization(new ResourceReferenceDt(rr)); + + Patient actual = parseAndEncode(patient); + ResourceReferenceDt ref = actual.getManagingOrganization(); + assertEquals(null, ref.getReference().getResourceType()); + assertEquals("123", ref.getReference().getIdPart()); + + } + + @Test + public void testParseValueMissingType2() { + Patient patient = new Patient(); + IdDt rr = new IdDt(); + rr.setValue("123"); + patient.setManagingOrganization(new ResourceReferenceDt(rr)); + + Patient actual = parseAndEncode(patient); + ResourceReferenceDt ref = actual.getManagingOrganization(); + assertEquals(null, ref.getReference().getResourceType()); + assertEquals("123", ref.getReference().getIdPart()); + + } + + @Test + public void testParseValueRelative1() { + Patient patient = new Patient(); + IdDt rr = new IdDt(); + rr.setValue("Organization/123"); + patient.setManagingOrganization(new ResourceReferenceDt(rr)); + + Patient actual = parseAndEncode(patient); + ResourceReferenceDt ref = actual.getManagingOrganization(); + assertEquals("Organization", ref.getReference().getResourceType()); + assertEquals("123", ref.getReference().getIdPart()); + + } + + @Test + public void testParseValueRelative2() { + Patient patient = new Patient(); + IdDt rr = new IdDt(); + rr.setValue("/Organization/123"); + patient.setManagingOrganization(new ResourceReferenceDt(rr)); + + Patient actual = parseAndEncode(patient); + ResourceReferenceDt ref = actual.getManagingOrganization(); + assertEquals("Organization", ref.getReference().getResourceType()); + assertEquals("123", ref.getReference().getIdPart()); + + } + + private Patient parseAndEncode(Patient patient) { + String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); + ourLog.info("\n" + encoded); + return ourCtx.newXmlParser().parseResource(Patient.class, encoded); + } + + @BeforeClass + public static void beforeClass() { + ourCtx = new FhirContext(); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/IdentifierDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/IdentifierDtTest.java new file mode 100644 index 00000000000..5d3f8950742 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/IdentifierDtTest.java @@ -0,0 +1,57 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; + +public class IdentifierDtTest { + + @Test + public void testTokenNoSystem() { + IdentifierDt dt = new IdentifierDt(); + dt.setValueAsQueryToken(null, "c"); + + assertEquals(null, dt.getSystem().getValueAsString()); + assertEquals("c", dt.getValue().getValue()); + assertEquals("c", dt.getValueAsQueryToken()); + } + + @Test + public void testTokenWithPipeInValue() { + IdentifierDt dt = new IdentifierDt(); + dt.setValueAsQueryToken(null, "a|b|c"); + + assertEquals("a", dt.getSystem().getValueAsString()); + assertEquals("b|c", dt.getValue().getValue()); + assertEquals("a|b\\|c", dt.getValueAsQueryToken()); + } + + @Test + public void testTokenWithPipeInValueAndNoSystem() { + IdentifierDt dt = new IdentifierDt(); + dt.setValueAsQueryToken(null, "|b\\|c"); + + assertEquals("", dt.getSystem().getValueAsString()); + assertEquals("b|c", dt.getValue().getValue()); + + assertEquals("|b\\|c", dt.getValueAsQueryToken()); + } + + /** + * Technically the second pipe should have been escaped.. But we should be nice about it + */ + @Test + public void testTokenWithPipeInValueAndNoSystemAndBeLenient() { + IdentifierDt dt = new IdentifierDt(); + dt.setValueAsQueryToken(null, "|b|c"); + + assertEquals("", dt.getSystem().getValueAsString()); + assertEquals("b|c", dt.getValue().getValue()); + + assertEquals("|b\\|c", dt.getValueAsQueryToken()); + } + + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/StringDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/StringDtTest.java new file mode 100644 index 00000000000..d07ec7da750 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/StringDtTest.java @@ -0,0 +1,16 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class StringDtTest { + + @Test + public void testBlank() { + + assertTrue(new StringDt("").isEmpty()); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/UriDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/UriDtTest.java new file mode 100644 index 00000000000..dfb0fd4ee83 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/UriDtTest.java @@ -0,0 +1,19 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class UriDtTest { + @Test + public void testEquals() { + assertEquals(new UriDt("http://foo"), new UriDt("http://foo")); + } + + @Test + public void testEqualsNormalize() { + assertEquals(new UriDt("http://foo"), new UriDt("http://foo/")); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/XhtmlDtTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/XhtmlDtTest.java new file mode 100644 index 00000000000..6be6529d169 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/primitive/XhtmlDtTest.java @@ -0,0 +1,68 @@ +package ca.uhn.fhir.model.primitive; + +import static org.junit.Assert.assertEquals; + +import org.junit.Test; + +public class XhtmlDtTest { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XhtmlDtTest.class); + + @Test + public void testRoundtripTiny() { + String div = "
xmlns="http://hl7.org/fhir"
"; + + XhtmlDt x = new XhtmlDt(); + x.setValueAsString(div); + + String actual = x.getValueAsString(); + + ourLog.info("Expected {}", div.replace("\r", "").replace("\n", "\\n")); + ourLog.info("Actual {}", actual.replace("\r\n", "\\r\\n").replace("\n", "\\n")); + + assertEquals(div.replace("\r", ""), actual); + + } + + @Test + public void testRoundtrip() { + String div = "
\r\n<Alert xmlns="http://hl7.org/fhir"> \"doco\"\r\n <!-- from Resource: extension, modifierExtension, language, text, and contained -->\r\n <identifier><!-- 0..* Identifier Business identifier --></identifier>\r\n <category><!-- 0..1 CodeableConcept Clinical, administrative, etc. --></category>\r\n <status value="[code]"/><!-- 1..1 active | inactive | entered in error -->\r\n <subject><!-- 1..1 Resource(Patient) Who is alert about? --></subject>\r\n <author><!-- 0..1 Resource(Practitioner|Patient|Device) Alert creator --></author>\r\n <note value="[string]"/><!-- 1..1 Text of alert -->\r\n</Alert>\r\n
"; + + XhtmlDt x = new XhtmlDt(); + x.setValueAsString(div); + + String actual = x.getValueAsString(); + + ourLog.info("Expected {}", div.replace("\r", "").replace("\n", "\\n")); + ourLog.info("Actual {}", actual.replace("\r\n", "\\r\\n").replace("\n", "\\n")); + + assertEquals(div.replace("\r", ""), actual); + + } + + @Test + public void testBasicCharacterEntity() { + String input = "amp &"; + + XhtmlDt x = new XhtmlDt(); + x.setValueAsString(input); + + assertEquals("
amp &
", x.getValueAsString()); + } + + + @Test + public void testCharacterEntities() { + String input = "Sect: § uuml: ü Ü"; + + XhtmlDt x = new XhtmlDt(); + x.setValueAsString(input); + + //
Sect: § uuml: ü Ü
+ //
Sect: § uuml: ü Ü
+ assertEquals("
Sect: § uuml: ü Ü
", x.getValueAsString()); + + } + + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/view/ExtPatient.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/view/ExtPatient.java new file mode 100644 index 00000000000..ef399221cfb --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/view/ExtPatient.java @@ -0,0 +1,42 @@ +package ca.uhn.fhir.model.view; + +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.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IntegerDt; + +@ResourceDef(name = "Patient") +public class ExtPatient extends Patient { + + @Extension(url = "urn:ext", isModifier = false, definedLocally = false) + @Child(name = "ext") + private IntegerDt myExt; + + @Extension(url = "urn:modExt", isModifier = false, definedLocally = false) + @Child(name = "modExt") + private IntegerDt myModExt; + + public IntegerDt getExt() { + if (myExt == null) { + myExt = new IntegerDt(); + } + return myExt; + } + + public void setExt(IntegerDt theExt) { + myExt = theExt; + } + + public IntegerDt getModExt() { + if (myModExt == null) { + myModExt = new IntegerDt(); + } + return myModExt; + } + + public void setModExt(IntegerDt theModExt) { + myModExt = theModExt; + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/view/ViewGeneratorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/view/ViewGeneratorTest.java new file mode 100644 index 00000000000..3ac118379fc --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/model/view/ViewGeneratorTest.java @@ -0,0 +1,61 @@ +package ca.uhn.fhir.model.view; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.ExtensionDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.parser.IParser; + +public class ViewGeneratorTest { + + private static FhirContext ourCtx = new FhirContext(); + + @Test + public void testView() { + + ExtPatient src = new ExtPatient(); + src.addIdentifier("urn:sys", "id1"); + src.addIdentifier("urn:sys", "id2"); + src.getExt().setValue(100); + src.getModExt().setValue(200); + + String enc = ourCtx.newXmlParser().encodeResourceToString(src); + IParser parser = ourCtx.newXmlParser(); + Patient nonExt = parser.parseResource(Patient.class, enc); + + assertEquals(Patient.class, nonExt.getClass()); + assertEquals("urn:sys", nonExt.getIdentifier().get(0).getSystem().getValueAsString()); + assertEquals("id1", nonExt.getIdentifier().get(0).getValue().getValue()); + assertEquals("urn:sys", nonExt.getIdentifier().get(1).getSystem().getValueAsString()); + assertEquals("id2", nonExt.getIdentifier().get(1).getValue().getValueAsString()); + + List ext = nonExt.getUndeclaredExtensionsByUrl("urn:ext"); + assertEquals(1,ext.size()); + assertEquals("urn:ext", ext.get(0).getUrlAsString()); + assertEquals(IntegerDt.class, ext.get(0).getValueAsPrimitive().getClass()); + assertEquals("100", ext.get(0).getValueAsPrimitive().getValueAsString()); + + List modExt = nonExt.getUndeclaredExtensionsByUrl("urn:modExt"); + assertEquals(1,modExt.size()); + assertEquals("urn:modExt", modExt.get(0).getUrlAsString()); + assertEquals(IntegerDt.class, modExt.get(0).getValueAsPrimitive().getClass()); + assertEquals("200", modExt.get(0).getValueAsPrimitive().getValueAsString()); + + ExtPatient va = ourCtx.newViewGenerator().newView(nonExt, ExtPatient.class); + assertEquals("urn:sys", va.getIdentifier().get(0).getSystem().getValueAsString()); + assertEquals("id1", va.getIdentifier().get(0).getValue().getValue()); + assertEquals("urn:sys", va.getIdentifier().get(1).getSystem().getValueAsString()); + assertEquals("id2", va.getIdentifier().get(1).getValue().getValueAsString()); + assertEquals(100, va.getExt().getValue().intValue()); + assertEquals(200, va.getModExt().getValue().intValue()); + assertEquals(0, va.getAllUndeclaredExtensions().size()); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/BaseThymeleafNarrativeGeneratorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/BaseThymeleafNarrativeGeneratorTest.java new file mode 100644 index 00000000000..9a7a877929f --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/BaseThymeleafNarrativeGeneratorTest.java @@ -0,0 +1,62 @@ +package ca.uhn.fhir.narrative; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class BaseThymeleafNarrativeGeneratorTest { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseThymeleafNarrativeGeneratorTest.class); + + @Test + public void testTrimWhitespace() { + + //@formatter:off + String input = "
\n" + + "
\n" + + " \n" + + " joe \n" + + " john \n" + + " BLOW \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
Identifier123456
Address\n" + + " \n" + + " 123 Fake Street
\n" + + " \n" + + " \n" + + " Unit 1
\n" + + " \n" + + " Toronto\n" + + " ON\n" + + " Canada\n" + + "
Date of birth\n" + + " 31 March 2014\n" + + "
\n" + + "
"; + //@formatter:on + + String actual = BaseThymeleafNarrativeGenerator.cleanWhitespace(input); + String expected = "
joe john BLOW
Identifier123456
Address123 Fake Street
Unit 1
TorontoONCanada
Date of birth31 March 2014
"; + + ourLog.info(actual); + + assertEquals(expected, actual); + } + + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/CustomThymeleafNarrativeGeneratorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/CustomThymeleafNarrativeGeneratorTest.java new file mode 100644 index 00000000000..10946066b14 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/CustomThymeleafNarrativeGeneratorTest.java @@ -0,0 +1,34 @@ +package ca.uhn.fhir.narrative; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.model.dstu.composite.NarrativeDt; +import ca.uhn.fhir.model.dstu.resource.Practitioner; + +public class CustomThymeleafNarrativeGeneratorTest { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomThymeleafNarrativeGeneratorTest.class); + + @Test + public void testGenerator() { + + CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator("file:src/test/resources/narrative/customnarrative.properties"); + + Practitioner p = new Practitioner(); + p.addIdentifier("sys", "val1"); + p.addIdentifier("sys", "val2"); + p.getAddress().addLine("line1").addLine("line2"); + p.getName().addFamily("fam1").addGiven("given"); + + NarrativeDt narrative = gen.generateNarrative(p); + + String actual = narrative.getDiv().getValueAsString(); + ourLog.info(actual); + + assertThat(actual, containsString("

Name

given FAM1

Address

line1
line2
")); + + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/DefaultThymeleafNarrativeGeneratorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/DefaultThymeleafNarrativeGeneratorTest.java new file mode 100644 index 00000000000..0dc2d2a55a8 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/narrative/DefaultThymeleafNarrativeGeneratorTest.java @@ -0,0 +1,209 @@ +package ca.uhn.fhir.narrative; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.io.InputStreamReader; +import java.util.Date; + +import org.hamcrest.core.StringContains; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt; +import ca.uhn.fhir.model.dstu.composite.NarrativeDt; +import ca.uhn.fhir.model.dstu.composite.PeriodDt; +import ca.uhn.fhir.model.dstu.composite.QuantityDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.Encounter; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.DiagnosticReportStatusEnum; +import ca.uhn.fhir.model.dstu.valueset.EncounterClassEnum; +import ca.uhn.fhir.model.dstu.valueset.EncounterTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.ObservationStatusEnum; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.parser.DataFormatException; + +public class DefaultThymeleafNarrativeGeneratorTest { + private FhirContext myCtx; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DefaultThymeleafNarrativeGeneratorTest.class); + private DefaultThymeleafNarrativeGenerator gen; + + @Before + public void before() { + gen = new DefaultThymeleafNarrativeGenerator(); + gen.setUseHapiServerConformanceNarrative(true); + gen.setIgnoreFailures(false); + gen.setIgnoreMissingTemplates(false); + + myCtx = new FhirContext(); + myCtx.setNarrativeGenerator(gen); + } + + @Test + public void testGeneratePatient() throws DataFormatException { + Patient value = new Patient(); + + value.addIdentifier().setSystem("urn:names").setValue("123456"); + value.addName().addFamily("blow").addGiven("joe").addGiven(null).addGiven("john"); + value.getAddressFirstRep().addLine("123 Fake Street").addLine("Unit 1"); + value.getAddressFirstRep().setCity("Toronto").setState("ON").setCountry("Canada"); + + value.setBirthDate(new Date(), TemporalPrecisionEnum.DAY); + + String output = gen.generateNarrative(value).getDiv().getValueAsString(); + assertThat(output, StringContains.containsString("
joe john BLOW
")); + + String title = gen.generateTitle(value); + assertEquals("joe john BLOW (123456)", title); + ourLog.info(title); + + value.getIdentifierFirstRep().setLabel("FOO MRN 123"); + title = gen.generateTitle(value); + assertEquals("joe john BLOW (FOO MRN 123)", title); + ourLog.info(title); + + } + + @Test + public void testGenerateEncounter() throws DataFormatException { + Encounter enc = new Encounter(); + + enc.addIdentifier("urn:visits", "1234567"); + enc.setClassElement(EncounterClassEnum.AMBULATORY); + enc.setPeriod(new PeriodDt().setStart(new DateTimeDt("2001-01-02T11:11:00"))); + enc.setType(EncounterTypeEnum.ANNUAL_DIABETES_MELLITUS_SCREENING); + + String title = gen.generateTitle(enc); + title = title.replaceAll("00 [A-Z]+ 2001", "00 TZ 2001"); // account for whatever time zone + assertEquals("1234567 / ADMS / ambulatory / Tue Jan 02 11:11:00 TZ 2001 - ?", title); + ourLog.info(title); + + } + + @Test + public void testGenerateOrganization() throws DataFormatException { + Organization enc = new Organization(); + + enc.addIdentifier("urn:visits", "1234567"); + enc.setName("Some Test Org"); + enc.addAddress().addLine("123 Fake St").setCity("Toronto").setState("ON").setCountry("Canada").setZip("12345"); + + String title = gen.generateTitle(enc); + assertEquals("Some Test Org", title); + ourLog.info(title); + + } + + @Test + public void testGenerateServerConformance() throws DataFormatException { + Conformance value = myCtx.newXmlParser().parseResource(Conformance.class, new InputStreamReader(getClass().getResourceAsStream("/server-conformance-statement.xml"))); + + String output = gen.generateNarrative(value).getDiv().getValueAsString(); + + ourLog.info(output); + } + + @Test + public void testGenerateDiagnosticReport() throws DataFormatException { + DiagnosticReport value = new DiagnosticReport(); + value.getName().setText("Some Diagnostic Report"); + + value.addResult().setReference("Observation/1"); + value.addResult().setReference("Observation/2"); + value.addResult().setReference("Observation/3"); + + String output = gen.generateNarrative("http://hl7.org/fhir/profiles/DiagnosticReport", value).getDiv().getValueAsString(); + + ourLog.info(output); + assertThat(output, StringContains.containsString(value.getName().getText().getValue())); + } + + @Test + public void testGenerateOperationOutcome() { + //@formatter:off + String parse = "\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + "
\n" + + " \n" + + ""; + //@formatter:on + + OperationOutcome oo = myCtx.newXmlParser().parseResource(OperationOutcome.class, parse); + +// String output = gen.generateTitle(oo); +// ourLog.info(output); +// assertEquals("Operation Outcome (2 issues)", output); + + String nar = gen.generateNarrative(null, oo).getDiv().getValueAsString(); + ourLog.info(nar); + +// oo = new OperationOutcome(); +// oo.addIssue().setSeverity(IssueSeverityEnum.FATAL).setDetails("AA"); +// output = gen.generateTitle(oo); +// ourLog.info(output); +// assertEquals("Operation Outcome (fatal)", output); + + } + + @Test + public void testGenerateDiagnosticReportWithObservations() throws DataFormatException { + DiagnosticReport value = new DiagnosticReport(); + + value.getIssued().setValueAsString("2011-02-22T11:13:00"); + value.setStatus(DiagnosticReportStatusEnum.FINAL); + + value.getName().setText("Some & Diagnostic Report"); + { + Observation obs = new Observation(); + obs.getName().addCoding().setCode("1938HB").setDisplay("Hemoglobin"); + obs.setValue(new QuantityDt(null, 2.223, "mg/L")); + obs.addReferenceRange().setLow(new QuantityDt(2.20)).setHigh(new QuantityDt(2.99)); + obs.setStatus(ObservationStatusEnum.FINAL); + obs.setComments("This is a result comment"); + + ResourceReferenceDt result = value.addResult(); + result.setResource(obs); + } + { + Observation obs = new Observation(); + obs.setValue(new StringDt("HELLO!")); + value.addResult().setResource(obs); + } + { + Observation obs = new Observation(); + obs.setName(new CodeableConceptDt("AA", "BB")); + value.addResult().setResource(obs); + } + NarrativeDt generateNarrative = gen.generateNarrative("http://hl7.org/fhir/profiles/DiagnosticReport", value); + String output = generateNarrative.getDiv().getValueAsString(); + + ourLog.info(output); + assertThat(output, StringContains.containsString("
Some & Diagnostic Report
")); + + String title = gen.generateTitle(value); + // ourLog.info(title); + assertEquals("Some & Diagnostic Report - final - 3 observations", title); + + // Now try it with the parser + + output = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(value); + ourLog.info(output); + assertThat(output, StringContains.containsString("
Some & Diagnostic Report
")); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/ContainedResourceEncodingTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/ContainedResourceEncodingTest.java new file mode 100644 index 00000000000..ef0fde36220 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/ContainedResourceEncodingTest.java @@ -0,0 +1,159 @@ +package ca.uhn.fhir.parser; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Composition; +import ca.uhn.fhir.model.dstu.resource.Composition.Section; +import ca.uhn.fhir.model.dstu.resource.Condition; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.resource.Practitioner; +import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum; +import ca.uhn.fhir.model.dstu.valueset.ConditionStatusEnum; +import ca.uhn.fhir.model.dstu.valueset.NameUseEnum; +import ca.uhn.fhir.model.dstu.valueset.PractitionerRoleEnum; +import ca.uhn.fhir.model.primitive.IdDt; + +/** + * Initially contributed by Alexander Kley for bug #29 + */ +public class ContainedResourceEncodingTest { + + private static Logger logger = LoggerFactory.getLogger(ContainedResourceEncodingTest.class); + + private FhirContext ctx; + + private Composition comp; + + private Practitioner author; + + private Patient patient; + + private final String patFamName1 = "FirstFamilyName"; + + private final String patGivName1 = "FirstGivenName"; + + @Before + public void initTest() { + logger.info("[initTest]"); + + initPatient(); + initAuthor(); + initComposition(); + this.ctx = new FhirContext(); + + } + + private void initComposition() { + // new ConditionList + + final Condition c = new Condition(); + c.setId(UUID.randomUUID().toString()); + c.setNotes("This is a note"); + c.setSubject(new ResourceReferenceDt(this.patient)); + c.setCode(new CodeableConceptDt("mySystem", "theCode")); + c.setStatus(ConditionStatusEnum.CONFIRMED); + + // new General Note Section + final Section generalNoteSection = new Section(); + generalNoteSection.setElementSpecificId("Note"); + generalNoteSection.setTitle("Note"); + generalNoteSection.setContent(new ResourceReferenceDt(c)); + + // new SectionList + final List
sectionList = new ArrayList
(); + sectionList.add(generalNoteSection); + + // fill composition + this.comp = new Composition(); + this.comp.addAuthor().setResource(this.author); + this.comp.setSubject(new ResourceReferenceDt(this.patient)); + this.comp.setSection(sectionList); + } + + private void initPatient() { + this.patient = new Patient(); + this.patient.setId(new IdDt(UUID.randomUUID().toString())); + this.patient.addIdentifier().setSystem("http://example.com/fictitious-mrns").setValue("MRN001"); + this.patient.setGender(AdministrativeGenderCodesEnum.M); + this.patient.addName().setUse(NameUseEnum.OFFICIAL).addFamily(this.patFamName1).addGiven(this.patGivName1); + + } + + private void initAuthor() { + this.author = new Practitioner(); + this.author.setId(new IdDt(UUID.randomUUID().toString())); + this.author.addIdentifier().setSystem("DoctorID").setValue("4711"); + this.author.addRole(PractitionerRoleEnum.DOCTOR); + this.author.setName(new HumanNameDt().addFamily("Mueller").addGiven("Klaus").addPrefix("Prof. Dr.")); + + } + + @Test + public void testPatient() { + logger.debug("[xmlEncoding] encode resource to xml."); + + /** + * This works fine, although patient instance is modifing from encoder + */ + final String expectedPatientXml = this.ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(this.patient); + logger.debug("[xmlEncoding] first encoding: {}", expectedPatientXml); + final String actualPatientXml = this.ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(this.patient); + // second encoding - xml is corrupt - i.e.: patient content 4 times! should be the same as after first encoding! + logger.debug("[xmlEncoding] second encoding: {}", actualPatientXml); + + Assert.assertEquals(expectedPatientXml.length(), actualPatientXml.length()); + Assert.assertArrayEquals(expectedPatientXml.getBytes(), actualPatientXml.getBytes()); + + } + + @Test + public void testComposition() { + + IParser parser = this.ctx.newXmlParser().setPrettyPrint(true); + + assertEquals(0, this.comp.getContained().getContainedResources().size()); + + /** + * This doesn't works, secund encoding creates corrupt xml + */ + final String expectedCompXml = parser.encodeResourceToString(this.comp); + logger.debug("[xmlEncoding] first encoding: {}", expectedCompXml); + + assertEquals(0, this.comp.getContained().getContainedResources().size()); + + final String actualCompXml = parser.encodeResourceToString(this.comp); + + assertEquals(0, this.comp.getContained().getContainedResources().size()); + + // second encoding - xml could not be parsed back to compositon - i.e.: patient content 4 times! should be the same + // as after first encoding! + logger.debug("[xmlEncoding] second encoding: {}", actualCompXml); + + final String thirdCompXml = parser.encodeResourceToString(this.comp); + + assertEquals(0, this.comp.getContained().getContainedResources().size()); + + // third encoding - xml could not be parsed back to compositon i.e.: patient content 4 times! should be the same as + // afterfirst encoding! + logger.debug("[xmlEncoding] third encoding: {}", thirdCompXml); + + Assert.assertEquals(expectedCompXml.length(), actualCompXml.length()); + Assert.assertArrayEquals(expectedCompXml.getBytes(), actualCompXml.getBytes()); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java new file mode 100644 index 00000000000..eb5b764a97d --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/JsonParserTest.java @@ -0,0 +1,1195 @@ +package ca.uhn.fhir.parser; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.io.IOException; +import java.io.OutputStreamWriter; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import net.sf.json.JSON; +import net.sf.json.JSONSerializer; + +import org.apache.commons.io.IOUtils; +import org.hamcrest.core.IsNot; +import org.hamcrest.core.StringContains; +import org.hamcrest.text.StringContainsInOrder; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.ExtensionDt; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.TagList; +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.model.dstu.composite.AddressDt; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.NarrativeDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Binary; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.ListResource; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.resource.Profile; +import ca.uhn.fhir.model.dstu.resource.Query; +import ca.uhn.fhir.model.dstu.resource.Specimen; +import ca.uhn.fhir.model.dstu.resource.ValueSet; +import ca.uhn.fhir.model.dstu.resource.ValueSet.Define; +import ca.uhn.fhir.model.dstu.resource.ValueSet.DefineConcept; +import ca.uhn.fhir.model.dstu.valueset.AddressUseEnum; +import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum; +import ca.uhn.fhir.model.primitive.DecimalDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.XhtmlDt; +import ca.uhn.fhir.narrative.INarrativeGenerator; + +public class JsonParserTest { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JsonParserTest.class); + private static FhirContext ourCtx; + + @Test + public void testEncodeNarrativeBlockInBundle() { + Patient p = new Patient(); + p.addIdentifier("foo", "bar"); + p.getText().setStatus(NarrativeStatusEnum.GENERATED); + p.getText().setDiv("
hello
"); + + Bundle b = new Bundle(); + b.getTotalResults().setValue(123); + b.addEntry().setResource(p); + + String out = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(out); + assertThat(out, containsString("
hello
")); + + p.getText().setDiv("hello"); + out = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(out); + // Backslashes need to be escaped because they are in a JSON value + assertThat(out, containsString("hello")); + + } + + @Test + public void testEncodeNonContained() { + Organization org = new Organization(); + org.setId("Organization/65546"); + org.getName().setValue("Contained Test Organization"); + + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + patient.getManagingOrganization().setResource(org); + + Bundle b = Bundle.withResources(Collections.singletonList((IResource)patient), ourCtx, "http://foo"); + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(encoded); + assertThat(encoded, not(containsString("contained"))); + assertThat(encoded, containsString("\"reference\":\"Organization/65546\"")); + + encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, not(containsString("contained"))); + assertThat(encoded, containsString("\"reference\":\"Organization/65546\"")); + } + + + @Test + public void testEncodeIds() { + Patient pt =new Patient(); + pt.addIdentifier("sys", "val"); + + ListResource list = new ListResource(); + list.setId("listId"); + list.addEntry().setItem(new ResourceReferenceDt(pt)); + + String enc = ourCtx.newJsonParser().encodeResourceToString(list); + ourLog.info(enc); + + assertThat(enc, containsString("\"id\":\"1\"")); + + ListResource parsed = ourCtx.newJsonParser().parseResource(ListResource.class,enc); + assertEquals(Patient.class, parsed.getEntryFirstRep().getItem().getResource().getClass()); + + enc = enc.replace("\"id\"", "\"_id\""); + parsed = ourCtx.newJsonParser().parseResource(ListResource.class,enc); + assertEquals(Patient.class, parsed.getEntryFirstRep().getItem().getResource().getClass()); +} + + @Test + public void testEncodingNullExtension() { + Patient p = new Patient(); + ExtensionDt extension = new ExtensionDt(false, "http://foo#bar"); + p.addUndeclaredExtension(extension); + String str = ourCtx.newJsonParser().encodeResourceToString(p); + + assertEquals("{\"resourceType\":\"Patient\"}", str); + + extension.setValue(new StringDt()); + + str = ourCtx.newJsonParser().encodeResourceToString(p); + assertEquals("{\"resourceType\":\"Patient\"}", str); + + extension.setValue(new StringDt("")); + + str = ourCtx.newJsonParser().encodeResourceToString(p); + assertEquals("{\"resourceType\":\"Patient\"}", str); + + } + + @Test + public void testParseSingleQuotes() { + try { + ourCtx.newJsonParser().parseBundle("{ 'resourceType': 'Bundle' }"); + fail(); + } catch (DataFormatException e) { + // Should be an error message about how single quotes aren't valid JSON + assertThat(e.getMessage(), containsString("double quote")); + } + } + + @Test + public void testEncodeExtensionInCompositeElement() { + + Conformance c = new Conformance(); + c.addRest().getSecurity().addUndeclaredExtension(false, "http://foo", new StringDt("AAA")); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c); + ourLog.info(encoded); + + encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c); + ourLog.info(encoded); + assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"rest\":[{\"security\":{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}}]}"); + + } + + @Test + public void testEncodeExtensionInPrimitiveElement() { + + Conformance c = new Conformance(); + c.getAcceptUnknown().addUndeclaredExtension(false, "http://foo", new StringDt("AAA")); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c); + ourLog.info(encoded); + + encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c); + ourLog.info(encoded); + assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"_acceptUnknown\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}]}"); + + // Now with a value + ourLog.info("---------------"); + + c = new Conformance(); + c.getAcceptUnknown().setValue(true); + c.getAcceptUnknown().addUndeclaredExtension(false, "http://foo", new StringDt("AAA")); + + encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c); + ourLog.info(encoded); + + encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c); + ourLog.info(encoded); + assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"acceptUnknown\":true,\"_acceptUnknown\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}]}"); + + } + + @Test + public void testEncodeExtensionInResourceElement() { + + Conformance c = new Conformance(); + // c.addRest().getSecurity().addUndeclaredExtension(false, "http://foo", new StringDt("AAA")); + c.addUndeclaredExtension(false, "http://foo", new StringDt("AAA")); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(c); + ourLog.info(encoded); + + encoded = ourCtx.newJsonParser().setPrettyPrint(false).encodeResourceToString(c); + ourLog.info(encoded); + assertEquals(encoded, "{\"resourceType\":\"Conformance\",\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}"); + + } + + @Test + public void testEncodeBinaryResource() { + + Binary patient = new Binary(); + patient.setContentType("foo"); + patient.setContent(new byte[] { 1, 2, 3, 4 }); + + String val = ourCtx.newJsonParser().encodeResourceToString(patient); + assertEquals("{\"resourceType\":\"Binary\",\"contentType\":\"foo\",\"content\":\"AQIDBA==\"}", val); + + } + + @Test + public void testParseEmptyNarrative() throws ConfigurationException, DataFormatException, IOException { + //@formatter:off + String text = "{\n" + + " \"resourceType\" : \"Patient\",\n" + + " \"extension\" : [\n" + + " {\n" + + " \"url\" : \"http://clairol.org/colour\",\n" + + " \"valueCode\" : \"B\"\n" + + " }\n" + + " ],\n" + + " \"text\" : {\n" + + " \"div\" : \"\"\n" + + " }" + + "}"; + //@formatter:on + + Patient res = (Patient) ourCtx.newJsonParser().parseResource(text); + String value = res.getText().getDiv().getValueAsString(); + + assertNull(value); + } + + @Test + public void testNestedContainedResources() { + + Observation A = new Observation(); + A.getName().setText("A"); + + Observation B = new Observation(); + B.getName().setText("B"); + A.addRelated().setTarget(new ResourceReferenceDt(B)); + + Observation C = new Observation(); + C.getName().setText("C"); + B.addRelated().setTarget(new ResourceReferenceDt(C)); + + String str = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(A); + ourLog.info(str); + + assertThat(str, stringContainsInOrder(Arrays.asList("\"text\":\"B\"", "\"text\":\"C\"", "\"text\":\"A\""))); + + // Only one (outer) contained block + int idx0 = str.indexOf("\"contained\""); + int idx1 = str.indexOf("\"contained\"", idx0 + 1); + + assertNotEquals(-1, idx0); + assertEquals(-1, idx1); + + Observation obs = ourCtx.newJsonParser().parseResource(Observation.class, str); + assertEquals("A", obs.getName().getText().getValue()); + + Observation obsB = (Observation) obs.getRelatedFirstRep().getTarget().getResource(); + assertEquals("B", obsB.getName().getText().getValue()); + + Observation obsC = (Observation) obsB.getRelatedFirstRep().getTarget().getResource(); + assertEquals("C", obsC.getName().getText().getValue()); + + } + + @Test + public void testParseQuery() { + String msg = "{\n" + " \"resourceType\": \"Query\",\n" + " \"text\": {\n" + " \"status\": \"generated\",\n" + " \"div\": \"
[Put rendering here]
\"\n" + " },\n" + + " \"identifier\": \"urn:uuid:42b253f5-fa17-40d0-8da5-44aeb4230376\",\n" + " \"parameter\": [\n" + " {\n" + " \"url\": \"http://hl7.org/fhir/query#_query\",\n" + + " \"valueString\": \"example\"\n" + " }\n" + " ]\n" + "}"; + Query query = ourCtx.newJsonParser().parseResource(Query.class, msg); + + assertEquals("urn:uuid:42b253f5-fa17-40d0-8da5-44aeb4230376", query.getIdentifier().getValueAsString()); + assertEquals("http://hl7.org/fhir/query#_query", query.getParameterFirstRep().getUrlAsString()); + assertEquals("example", query.getParameterFirstRep().getValueAsPrimitive().getValueAsString()); + + } + + @Test + public void testEncodeQuery() { + Query q = new Query(); + ExtensionDt parameter = q.addParameter(); + parameter.setUrl("http://hl7.org/fhir/query#_query").setValue(new StringDt("example")); + + String val = new FhirContext().newJsonParser().encodeResourceToString(q); + ourLog.info(val); + + //@formatter:off + String expected = + "{" + + "\"resourceType\":\"Query\"," + + "\"parameter\":[" + + "{" + + "\"url\":\"http://hl7.org/fhir/query#_query\"," + + "\"valueString\":\"example\"" + + "}" + + "]" + + "}"; + //@formatter:on + + ourLog.info("Expect: {}", expected); + ourLog.info("Got : {}", val); + assertEquals(expected, val); + + } + + @Test + public void testParseBinaryResource() { + + Binary val = ourCtx.newJsonParser().parseResource(Binary.class, "{\"resourceType\":\"Binary\",\"contentType\":\"foo\",\"content\":\"AQIDBA==\"}"); + assertEquals("foo", val.getContentType()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, val.getContent()); + + } + + @Test + public void testTagList() { + + //@formatter:off + String tagListStr = "{\n" + + " \"resourceType\" : \"TagList\", " + + " \"category\" : [" + + " { " + + " \"term\" : \"term0\", " + + " \"label\" : \"label0\", " + + " \"scheme\" : \"scheme0\" " + + " }," + + " { " + + " \"term\" : \"term1\", " + + " \"label\" : \"label1\", " + + " \"scheme\" : null " + + " }," + + " { " + + " \"term\" : \"term2\", " + + " \"label\" : \"label2\" " + + " }" + + " ] " + + "}"; + //@formatter:on + + TagList tagList = new FhirContext().newJsonParser().parseTagList(tagListStr); + assertEquals(3, tagList.size()); + assertEquals("term0", tagList.get(0).getTerm()); + assertEquals("label0", tagList.get(0).getLabel()); + assertEquals("scheme0", tagList.get(0).getScheme()); + assertEquals("term1", tagList.get(1).getTerm()); + assertEquals("label1", tagList.get(1).getLabel()); + assertEquals(null, tagList.get(1).getScheme()); + assertEquals("term2", tagList.get(2).getTerm()); + assertEquals("label2", tagList.get(2).getLabel()); + assertEquals(null, tagList.get(2).getScheme()); + + /* + * Encode + */ + + //@formatter:off + String expected = "{" + + "\"resourceType\":\"TagList\"," + + "\"category\":[" + + "{" + + "\"term\":\"term0\"," + + "\"label\":\"label0\"," + + "\"scheme\":\"scheme0\"" + + "}," + + "{" + + "\"term\":\"term1\"," + + "\"label\":\"label1\"" + + "}," + + "{" + + "\"term\":\"term2\"," + + "\"label\":\"label2\"" + + "}" + + "]" + + "}"; + //@formatter:on + + String encoded = new FhirContext().newJsonParser().encodeTagListToString(tagList); + assertEquals(expected, encoded); + + } + + @Test + public void testEncodeBundleCategory() { + + Bundle b = new Bundle(); + BundleEntry e = b.addEntry(); + e.setResource(new Patient()); + b.addCategory("scheme", "term", "label"); + + String val = new FhirContext().newJsonParser().setPrettyPrint(false).encodeBundleToString(b); + ourLog.info(val); + + assertThat(val, StringContains.containsString("\"category\":[{\"term\":\"term\",\"label\":\"label\",\"scheme\":\"scheme\"}]")); + + b = new FhirContext().newJsonParser().parseBundle(val); + assertEquals(1, b.getEntries().size()); + assertEquals(1, b.getCategories().size()); + assertEquals("term", b.getCategories().get(0).getTerm()); + assertEquals("label", b.getCategories().get(0).getLabel()); + assertEquals("scheme", b.getCategories().get(0).getScheme()); + assertNull(b.getEntries().get(0).getResource()); + + } + + @Test + public void testEncodeBundleEntryCategory() { + + Bundle b = new Bundle(); + BundleEntry e = b.addEntry(); + e.setResource(new Patient()); + e.addCategory("scheme", "term", "label"); + + String val = ourCtx.newJsonParser().setPrettyPrint(false).encodeBundleToString(b); + ourLog.info(val); + + assertThat(val, StringContains.containsString("\"category\":[{\"term\":\"term\",\"label\":\"label\",\"scheme\":\"scheme\"}]")); + + b = ourCtx.newJsonParser().parseBundle(val); + assertEquals(1, b.getEntries().size()); + assertEquals(1, b.getEntries().get(0).getCategories().size()); + assertEquals("term", b.getEntries().get(0).getCategories().get(0).getTerm()); + assertEquals("label", b.getEntries().get(0).getCategories().get(0).getLabel()); + assertEquals("scheme", b.getEntries().get(0).getCategories().get(0).getScheme()); + assertNull(b.getEntries().get(0).getResource()); + + } + + @Test + public void testEncodeContained__() { + // Create an organization + Organization org = new Organization(); + org.getName().setValue("Contained Test Organization"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + patient.getManagingOrganization().setResource(org); + + // Create a bundle with just the patient resource + List resources = new ArrayList(); + resources.add(patient); + Bundle b = Bundle.withResources(resources, ourCtx, "http://example.com/base"); + + // Encode the buntdle + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("\"contained\"", "resourceType\":\"Organization", "id\":\"1\""))); + assertThat(encoded, containsString("reference\":\"#1\"")); + + encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("\"contained\"", "resourceType\":\"Organization", "id\":\"1\""))); + assertThat(encoded, containsString("reference\":\"#1\"")); + } + + @Test + public void testEncodeContainedWithNarrativeIsSuppresed() { + IParser parser = ourCtx.newJsonParser().setPrettyPrint(true); + + // Create an organization, note that the organization does not have an ID + Organization org = new Organization(); + org.getName().setValue("Contained Test Organization"); + org.getText().setDiv("
FOOBAR
"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + patient.getText().setDiv("
BARFOO
"); + patient.getManagingOrganization().setResource(org); + + String encoded = parser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, not(containsString("FOOBAR"))); + assertThat(encoded, (containsString("BARFOO"))); + + } + + @Test + public void testEncodeContained() { + IParser xmlParser = ourCtx.newJsonParser().setPrettyPrint(true); + + // Create an organization, note that the organization does not have an ID + Organization org = new Organization(); + org.getName().setValue("Contained Test Organization"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + + // Put the organization as a reference in the patient resource + patient.getManagingOrganization().setResource(org); + + String encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("\"contained\":[", "\"id\":\"1\"", "\"identifier\"", "\"reference\":\"#1\""))); + + // Create a bundle with just the patient resource + List resources = new ArrayList(); + resources.add(patient); + Bundle b = Bundle.withResources(resources, ourCtx, "http://example.com/base"); + + // Encode the bundle + encoded = xmlParser.encodeBundleToString(b); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("\"contained\":[", "\"id\":\"1\"", "\"identifier\"", "\"reference\":\"#1\""))); + + // Re-parse the bundle + patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient)); + assertEquals("#1", patient.getManagingOrganization().getReference().getValue()); + + assertNotNull(patient.getManagingOrganization().getResource()); + org = (Organization) patient.getManagingOrganization().getResource(); + assertEquals("#1", org.getId().getValue()); + assertEquals("Contained Test Organization", org.getName().getValue()); + + // And re-encode a second time + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("\"contained\":[", "\"id\":\"1\"", "\"identifier\"", "\"reference\":\"#1\""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("\"contained\":", "[", "\"contained\":")))); + + // And re-encode once more, with the references cleared + patient.getContained().getContainedResources().clear(); + patient.getManagingOrganization().setReference((IdDt)null); + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("\"contained\":[", "\"id\":\"1\"", "\"identifier\"", "\"reference\":\"#1\""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("\"contained\":", "[", "\"contained\":")))); + + // And re-encode once more, with the references cleared and a manually set local ID + patient.getContained().getContainedResources().clear(); + patient.getManagingOrganization().setReference((IdDt)null); + patient.getManagingOrganization().getResource().setId(new IdDt("#333")); + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("\"contained\":[", "\"id\":\"333\"", "\"identifier\"", "\"reference\":\"#333\""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("\"contained\":", "[", "\"contained\":")))); + + } + + + + + @Test + public void testEncodeContainedResources() throws IOException { + + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/contained-diagnosticreport.xml")); + IParser p = ourCtx.newXmlParser(); + DiagnosticReport res = p.parseResource(DiagnosticReport.class, msg); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res); + ourLog.info(encoded); + + } + + @Test + public void testParseJsonProfile() throws IOException { + parseAndEncode("/patient.profile.json"); + parseAndEncode("/alert.profile.json"); + } + + private void parseAndEncode(String name) throws IOException { + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream(name)); + ourLog.info(msg); + + IParser p = ourCtx.newJsonParser(); + Profile res = p.parseResource(Profile.class, msg); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(res); + ourLog.info(encoded); + + JSON expected = JSONSerializer.toJSON(msg.trim()); + JSON actual = JSONSerializer.toJSON(encoded.trim()); + + String exp = expected.toString().replace("\\r\\n", "\\n").replace("§", "§"); + String act = actual.toString().replace("\\r\\n", "\\n"); + + ourLog.info("Expected: {}", exp); + ourLog.info("Actual : {}", act); + + assertEquals(exp, act); + } + + @Test + public void testEncodeContainedResourcesMore() { + + DiagnosticReport rpt = new DiagnosticReport(); + Specimen spm = new Specimen(); + rpt.getText().setDiv("AAA"); + rpt.addSpecimen().setResource(spm); + + IParser p = new FhirContext(DiagnosticReport.class).newJsonParser().setPrettyPrint(true); + String str = p.encodeResourceToString(rpt); + + ourLog.info(str); + assertThat(str, StringContains.containsString("
AAA
")); + String substring = "\"reference\":\"#"; + assertThat(str, StringContains.containsString(substring)); + + int idx = str.indexOf(substring) + substring.length(); + int idx2 = str.indexOf('"', idx + 1); + String id = str.substring(idx, idx2); + assertThat(str, StringContains.containsString("\"id\":\"" + id + "\"")); + assertThat(str, IsNot.not(StringContains.containsString(""))); + + } + + @Test + public void testEncodeDeclaredExtensionWithAddressContent() { + IParser parser = new FhirContext().newJsonParser(); + + MyPatientWithOneDeclaredAddressExtension patient = new MyPatientWithOneDeclaredAddressExtension(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.setFoo(new AddressDt().addLine("line1")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueAddress\":{\"line\":[\"line1\"]}}]")); + + MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + AddressDt ref = actual.getFoo(); + assertEquals("line1", ref.getLineFirstRep().getValue()); + + } + + @Test + public void testEncodeDeclaredExtensionWithResourceContent() { + IParser parser = new FhirContext().newJsonParser(); + + MyPatientWithOneDeclaredExtension patient = new MyPatientWithOneDeclaredExtension(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.setFoo(new ResourceReferenceDt("Organization/123")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueResource\":{\"reference\":\"Organization/123\"}}]")); + + MyPatientWithOneDeclaredExtension actual = parser.parseResource(MyPatientWithOneDeclaredExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + ResourceReferenceDt ref = actual.getFoo(); + assertEquals("Organization/123", ref.getReference().getValue()); + + } + + @Test + public void testEncodeExtensionOnEmptyElement() throws Exception { + + ValueSet valueSet = new ValueSet(); + valueSet.addTelecom().addUndeclaredExtension(false, "http://foo", new StringDt("AAA")); + + String encoded = ourCtx.newJsonParser().encodeResourceToString(valueSet); + assertThat(encoded, containsString("\"telecom\":[{\"extension\":[{\"url\":\"http://foo\",\"valueString\":\"AAA\"}]}")); + + } + + @Test + public void testEncodeExt() throws Exception { + + ValueSet valueSet = new ValueSet(); + valueSet.setId("123456"); + + Define define = valueSet.getDefine(); + DefineConcept code = define.addConcept(); + code.setCode("someCode"); + code.setDisplay("someDisplay"); + code.addUndeclaredExtension(false, "urn:alt", new StringDt("alt name")); + + String encoded = ourCtx.newJsonParser().encodeResourceToString(valueSet); + ourLog.info(encoded); + + assertThat(encoded, not(containsString("123456"))); + assertEquals( + "{\"resourceType\":\"ValueSet\",\"define\":{\"concept\":[{\"extension\":[{\"url\":\"urn:alt\",\"valueString\":\"alt name\"}],\"code\":\"someCode\",\"display\":\"someDisplay\"}]}}", + encoded); + + } + + @Test + public void testEncodeExtensionWithResourceContent() { + IParser parser = new FhirContext().newJsonParser(); + + Patient patient = new Patient(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.addUndeclaredExtension(false, "urn:foo", new ResourceReferenceDt("Organization/123")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueResource\":{\"reference\":\"Organization/123\"}}]")); + + Patient actual = parser.parseResource(Patient.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + List ext = actual.getUndeclaredExtensionsByUrl("urn:foo"); + assertEquals(1, ext.size()); + ResourceReferenceDt ref = (ResourceReferenceDt) ext.get(0).getValue(); + assertEquals("Organization/123", ref.getReference().getValue()); + + } + + @Test + public void testEncodeInvalidChildGoodException() { + Observation obs = new Observation(); + obs.setValue(new DecimalDt(112.22)); + + IParser p = new FhirContext(Observation.class).newJsonParser(); + + try { + p.encodeResourceToString(obs); + } catch (DataFormatException e) { + assertThat(e.getMessage(), StringContains.containsString("DecimalDt")); + } + } + + @Test + public void testEncodeResourceRef() throws DataFormatException { + + Patient patient = new Patient(); + patient.setManagingOrganization(new ResourceReferenceDt()); + + IParser p = new FhirContext().newJsonParser(); + String str = p.encodeResourceToString(patient); + assertThat(str, IsNot.not(StringContains.containsString("managingOrganization"))); + + patient.setManagingOrganization(new ResourceReferenceDt("Organization/123")); + str = p.encodeResourceToString(patient); + assertThat(str, StringContains.containsString("\"managingOrganization\":{\"reference\":\"Organization/123\"}")); + + Organization org = new Organization(); + org.addIdentifier().setSystem("foo").setValue("bar"); + patient.setManagingOrganization(new ResourceReferenceDt(org)); + str = p.encodeResourceToString(patient); + assertThat(str, StringContains.containsString("\"contained\":[{\"resourceType\":\"Organization\"")); + + } + + @Test + public void testEncodeUndeclaredExtensionWithAddressContent() { + IParser parser = new FhirContext().newJsonParser(); + + Patient patient = new Patient(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.addUndeclaredExtension(false, "urn:foo", new AddressDt().addLine("line1")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("\"extension\":[{\"url\":\"urn:foo\",\"valueAddress\":{\"line\":[\"line1\"]}}]")); + + MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + AddressDt ref = actual.getFoo(); + assertEquals("line1", ref.getLineFirstRep().getValue()); + + } + + @Test + public void testExtensionOnComposite() throws Exception { + + Patient patient = new Patient(); + + HumanNameDt name = patient.addName(); + name.addFamily().setValue("Shmoe"); + HumanNameDt given = name.addGiven("Joe"); + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); + given.addUndeclaredExtension(ext2); + String enc = new FhirContext().newJsonParser().encodeResourceToString(patient); + ourLog.info(enc); + assertEquals("{\"resourceType\":\"Patient\",\"name\":[{\"extension\":[{\"url\":\"http://examples.com#givenext\",\"valueString\":\"Hello\"}],\"family\":[\"Shmoe\"],\"given\":[\"Joe\"]}]}", enc); + + IParser newJsonParser = new FhirContext().newJsonParser(); + StringReader reader = new StringReader(enc); + Patient parsed = newJsonParser.parseResource(Patient.class, reader); + + ourLog.info(new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(parsed)); + + assertEquals(1, parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); + ExtensionDt ext = parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); + assertEquals("Hello", ext.getValueAsPrimitive().getValue()); + + } + + @Test + public void testExtensionOnPrimitive() throws Exception { + + Patient patient = new Patient(); + + HumanNameDt name = patient.addName(); + StringDt family = name.addFamily(); + family.setValue("Shmoe"); + + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); + family.addUndeclaredExtension(ext2); + String enc = new FhirContext().newJsonParser().encodeResourceToString(patient); + ourLog.info(enc); + //@formatter:off + assertThat(enc, containsString(("{\n" + + " \"resourceType\":\"Patient\",\n" + + " \"name\":[\n" + + " {\n" + + " \"family\":[\n" + + " \"Shmoe\"\n" + + " ],\n" + + " \"_family\":[\n" + + " {\n" + + " \"extension\":[\n" + + " {\n" + + " \"url\":\"http://examples.com#givenext\",\n" + + " \"valueString\":\"Hello\"\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + " }\n" + + " ]\n" + + "}").replace("\n", "").replaceAll(" +", ""))); + //@formatter:on + + Patient parsed = new FhirContext().newJsonParser().parseResource(Patient.class, new StringReader(enc)); + assertEquals(1, parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); + ExtensionDt ext = parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); + assertEquals("Hello", ext.getValueAsPrimitive().getValue()); + + } + + @Test + public void testNarrativeGeneration() throws DataFormatException, IOException { + + Patient patient = new Patient(); + patient.addName().addFamily("Smith"); + Organization org = new Organization(); + patient.getManagingOrganization().setResource(org); + + INarrativeGenerator gen = mock(INarrativeGenerator.class); + XhtmlDt xhtmlDt = new XhtmlDt("
help
"); + NarrativeDt nar = new NarrativeDt(xhtmlDt, NarrativeStatusEnum.GENERATED); + when(gen.generateNarrative(eq("http://hl7.org/fhir/profiles/Patient"), eq(patient))).thenReturn(nar); + + FhirContext context = new FhirContext(); + context.setNarrativeGenerator(gen); + IParser p = context.newJsonParser(); + p.encodeResourceToWriter(patient, new OutputStreamWriter(System.out)); + String str = p.encodeResourceToString(patient); + + ourLog.info(str); + + assertThat(str, StringContains.containsString(",\"text\":{\"status\":\"generated\",\"div\":\"
help
\"},")); + } + + @Test + public void testParseBundle() throws DataFormatException, IOException { + + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/atom-document-large.json")); + IParser p = ourCtx.newJsonParser(); + Bundle bundle = p.parseBundle(msg); + + assertEquals(1, bundle.getCategories().size()); + assertEquals("http://scheme", bundle.getCategories().get(0).getScheme()); + assertEquals("http://term", bundle.getCategories().get(0).getTerm()); + assertEquals("label", bundle.getCategories().get(0).getLabel()); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle); + ourLog.info(encoded); + + assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id", bundle + .getLinkSelf().getValue()); + assertEquals("urn:uuid:0b754ff9-03cf-4322-a119-15019af8a3", bundle.getBundleId().getValue()); + + BundleEntry entry = bundle.getEntries().get(0); + assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/101", entry.getId().getValue()); + assertEquals("http://fhir.healthintersections.com.au/open/DiagnosticReport/101/_history/1", entry.getLinkSelf().getValue()); + assertEquals("2014-03-10T11:55:59Z", entry.getUpdated().getValueAsString()); + + DiagnosticReport res = (DiagnosticReport) entry.getResource(); + assertEquals("Complete Blood Count", res.getName().getText().getValue()); + + assertThat(entry.getSummary().getValueAsString(), containsString("CBC Report for Wile")); + + } + + @Test + public void testParseBundleFromHI() throws DataFormatException, IOException { + + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/bundle.json")); + IParser p = ourCtx.newJsonParser(); + Bundle bundle = p.parseBundle(msg); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle); + ourLog.info(encoded); + + BundleEntry entry = bundle.getEntries().get(0); + + Patient res = (Patient) entry.getResource(); + assertEquals("444111234", res.getIdentifierFirstRep().getValue().getValue()); + + BundleEntry deletedEntry = bundle.getEntries().get(3); + assertEquals("2014-06-20T20:15:49Z", deletedEntry.getDeletedAt().getValueAsString()); + + } + + /** + * This sample has extra elements in that are not actually a part of the spec any more.. + */ + @Test + public void testParseFuroreMetadataWithExtraElements() throws IOException { + String msg = IOUtils.toString(JsonParserTest.class.getResourceAsStream("/furore-conformance.json")); + + IParser p = ourCtx.newJsonParser(); + Conformance conf = p.parseResource(Conformance.class, msg); + RestResource res = conf.getRestFirstRep().getResourceFirstRep(); + assertEquals("_id", res.getSearchParam().get(1).getName().getValue()); + } + + @Test + public void testParseWithContained() throws DataFormatException, IOException { + + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/diagnostic-report.json")); + IParser p = ourCtx.newJsonParser(); + // ourLog.info("Reading in message: {}", msg); + DiagnosticReport res = p.parseResource(DiagnosticReport.class, msg); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res); + ourLog.info(encoded); + + ResourceReferenceDt reference = res.getResult().get(1); + Observation obs = (Observation) reference.getResource(); + + assertEquals("789-8", obs.getName().getCoding().get(0).getCode().getValue()); + } + + @BeforeClass + public static void beforeClass() { + ourCtx = new FhirContext(); + } + + @Test + public void testParseBundleDeletedEntry() { + + //@formatter:off + String bundleString = + "{" + + "\"resourceType\":\"Bundle\"," + + "\"totalResults\":\"1\"," + + "\"entry\":[" + + "{" + + "\"deleted\":\"2012-05-29T23:45:32+00:00\"," + + "\"id\":\"http://fhir.furore.com/fhir/Patient/1\"," + + "\"link\":[" + + "{" + + "\"rel\":\"self\"," + + "\"href\":\"http://fhir.furore.com/fhir/Patient/1/_history/2\"" + + "}" + + "]" + + "}" + + "]" + + "}"; + //@formatter:on + + Bundle bundle = ourCtx.newJsonParser().parseBundle(bundleString); + BundleEntry entry = bundle.getEntries().get(0); + assertEquals("2012-05-29T23:45:32+00:00", entry.getDeletedAt().getValueAsString()); + assertEquals("http://fhir.furore.com/fhir/Patient/1/_history/2", entry.getLinkSelf().getValue()); + assertEquals("1", entry.getResource().getId().getIdPart()); + assertEquals("2", entry.getResource().getId().getVersionIdPart()); + assertEquals(new InstantDt("2012-05-29T23:45:32+00:00"), entry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.DELETED_AT)); + + // Now encode + + ourLog.info(ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(bundle)); + String encoded = ourCtx.newJsonParser().encodeBundleToString(bundle); + assertEquals(bundleString, encoded); + + } + + @Test + public void testEncodeBundle() throws InterruptedException { + Bundle b = new Bundle(); + + InstantDt pub = InstantDt.withCurrentTime(); + b.setPublished(pub); + Thread.sleep(2); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + entry.getSummary().setValueAsString("this is the summary"); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setLinkAlternate(new StringDt("http://foo/bar")); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + InstantDt nowDt = InstantDt.withCurrentTime(); + deletedEntry.setDeleted(nowDt); + + String bundleString = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + List strings = new ArrayList(); + strings.addAll(Arrays.asList("\"published\":\"" + pub.getValueAsString() + "\"")); + strings.addAll(Arrays.asList("\"id\":\"1\"")); + strings.addAll(Arrays.asList("this is the summary")); + strings.addAll(Arrays.asList("\"id\":\"2\"", "\"rel\":\"alternate\"", "\"href\":\"http://foo/bar\"")); + strings.addAll(Arrays.asList("\"deleted\":\"" + nowDt.getValueAsString() + "\"", "\"id\":\"Patient/3\"")); + assertThat(bundleString, StringContainsInOrder.stringContainsInOrder(strings)); + + b.getEntries().remove(2); + bundleString = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(b); + assertThat(bundleString, not(containsString("deleted"))); + + } + + @Test + public void testSimpleBundleEncode() throws IOException { + + String xmlString = IOUtils.toString(JsonParser.class.getResourceAsStream("/atom-document-large.xml"), Charset.forName("UTF-8")); + Bundle obs = ourCtx.newXmlParser().parseBundle(xmlString); + + String encoded = ourCtx.newJsonParser().setPrettyPrint(true).encodeBundleToString(obs); + ourLog.info(encoded); + + } + + @Test + public void testSimpleParse() throws DataFormatException, IOException { + + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/example-patient-general.json")); + IParser p = ourCtx.newJsonParser(); + // ourLog.info("Reading in message: {}", msg); + Patient res = p.parseResource(Patient.class, msg); + + assertEquals(2, res.getUndeclaredExtensions().size()); + assertEquals(1, res.getUndeclaredModifierExtensions().size()); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res); + ourLog.info(encoded); + + } + + @Test + public void testSimpleResourceEncode() throws IOException { + + String xmlString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.xml"), Charset.forName("UTF-8")); + Patient obs = ourCtx.newXmlParser().parseResource(Patient.class, xmlString); + + List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); + ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + + ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToWriter(obs, new OutputStreamWriter(System.out)); + + IParser jsonParser = ourCtx.newJsonParser(); + String encoded = jsonParser.encodeResourceToString(obs); + ourLog.info(encoded); + + String jsonString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.json"), Charset.forName("UTF-8")); + + JSON expected = JSONSerializer.toJSON(jsonString); + JSON actual = JSONSerializer.toJSON(encoded.trim()); + + // The encoded escapes quote marks using XML escaping instead of JSON escaping, which is probably nicer anyhow... + String exp = expected.toString().replace("\\\"Jim\\\"", ""Jim""); + String act = actual.toString(); + + ourLog.info("Expected: {}", exp); + ourLog.info("Actual : {}", act); + assertEquals(exp, act); + + } + + /** + * HAPI FHIR < 0.6 incorrectly used "resource" instead of "reference" + */ + @Test + public void testParseWithIncorrectReference() throws IOException { + String jsonString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.json")); + jsonString = jsonString.replace("\"reference\"", "\"resource\""); + Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, jsonString); + assertEquals("Organization/1", parsed.getManagingOrganization().getReference().getValue()); + } + + @Test + public void testSimpleResourceEncodeWithCustomType() throws IOException { + + FhirContext fhirCtx = new FhirContext(MyObservationWithExtensions.class); + String xmlString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.xml"), Charset.forName("UTF-8")); + MyObservationWithExtensions obs = fhirCtx.newXmlParser().parseResource(MyObservationWithExtensions.class, xmlString); + + assertEquals(0, obs.getAllUndeclaredExtensions().size()); + assertEquals("aaaa", obs.getExtAtt().getContentType().getValue()); + assertEquals("str1", obs.getMoreExt().getStr1().getValue()); + assertEquals("2011-01-02", obs.getModExt().getValueAsString()); + + List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); + ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + + IParser jsonParser = fhirCtx.newJsonParser().setPrettyPrint(true); + String encoded = jsonParser.encodeResourceToString(obs); + ourLog.info(encoded); + + String jsonString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.json"), Charset.forName("UTF-8")); + + JSON expected = JSONSerializer.toJSON(jsonString); + JSON actual = JSONSerializer.toJSON(encoded.trim()); + + // The encoded escapes quote marks using XML escaping instead of JSON escaping, which is probably nicer anyhow... + String exp = expected.toString().replace("\\\"Jim\\\"", ""Jim""); + String act = actual.toString(); + + ourLog.info("Expected: {}", exp); + ourLog.info("Actual : {}", act); + assertEquals(exp, act); + + } + + @ResourceDef(name = "Patient") + public static class MyPatientWithOneDeclaredAddressExtension extends Patient { + + @Child(order = 0, name = "foo") + @Extension(url = "urn:foo", definedLocally = true, isModifier = false) + private AddressDt myFoo; + + public AddressDt getFoo() { + return myFoo; + } + + public void setFoo(AddressDt theFoo) { + myFoo = theFoo; + } + + } + + @ResourceDef(name = "Patient") + public static class MyPatientWithOneDeclaredExtension extends Patient { + + @Child(order = 0, name = "foo") + @Extension(url = "urn:foo", definedLocally = true, isModifier = false) + private ResourceReferenceDt myFoo; + + public ResourceReferenceDt getFoo() { + return myFoo; + } + + public void setFoo(ResourceReferenceDt theFoo) { + myFoo = theFoo; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyObservationWithExtensions.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyObservationWithExtensions.java new file mode 100644 index 00000000000..5309bf2131f --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyObservationWithExtensions.java @@ -0,0 +1,109 @@ +package ca.uhn.fhir.parser; + +import java.util.Collections; +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResourceBlock; +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.model.dstu.composite.AttachmentDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.DateDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.util.ElementUtil; + +@ResourceDef(name="Patient") +public class MyObservationWithExtensions extends Patient { + + @Extension(url = "urn:patientext:att", definedLocally = false, isModifier = false) + @Child(name = "extAtt", order = 0) + private AttachmentDt 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 DateDt myModExt; + + public AttachmentDt getExtAtt() { + return myExtAtt; + } + + public MoreExt getMoreExt() { + return myMoreExt; + } + + public void setMoreExt(MoreExt theMoreExt) { + myMoreExt = theMoreExt; + } + + public DateDt getModExt() { + return myModExt; + } + + public void setModExt(DateDt theModExt) { + myModExt = theModExt; + } + + public void setExtAtt(AttachmentDt theExtAtt) { + myExtAtt = theExtAtt; + } + + @Override + public boolean isEmpty() { + return super.isEmpty() && ElementUtil.isEmpty(myExtAtt, myModExt, myMoreExt); + } + + /** + * Block class for child element: Observation.referenceRange (Provides guide for interpretation) + * + *

+ * Definition: Guidance on how to interpret the value by comparison to a normal or recommended range + *

+ */ + @Block(name = "Observation.someExtensions") + public static class MoreExt extends BaseIdentifiableElement implements IResourceBlock { + + @Extension(url = "urn:patientext:moreext:1", definedLocally = false, isModifier = false) + @Child(name = "str1", order = 0) + private StringDt myStr1; + + @Extension(url = "urn:patientext:moreext:2", definedLocally = false, isModifier = false) + @Child(name = "str2", order = 1) + private StringDt myStr2; + + public StringDt getStr1() { + return myStr1; + } + + public void setStr1(StringDt theStr1) { + myStr1 = theStr1; + } + + public StringDt getStr2() { + return myStr2; + } + + public void setStr2(StringDt theStr2) { + myStr2 = theStr2; + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return Collections.emptyList(); + } + + @Override + public boolean isEmpty() { + return ElementUtil.isEmpty(myStr1, myStr2); + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyOrganization.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyOrganization.java new file mode 100644 index 00000000000..6e69d520ec4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyOrganization.java @@ -0,0 +1,9 @@ +package ca.uhn.fhir.parser; + +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.model.dstu.resource.Organization; + +@ResourceDef() +public class MyOrganization extends Organization { + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyPatient.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyPatient.java new file mode 100644 index 00000000000..b3c9b635b2c --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/MyPatient.java @@ -0,0 +1,62 @@ +package ca.uhn.fhir.parser; + +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 ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.StringDt; + +@ResourceDef() +public class MyPatient extends Patient { + + @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 StringDt 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 myImportantDates; + + @Child(name="managingOrganization", order=Child.REPLACE_PARENT, min=0, max=1, type={ + MyOrganization.class }) + @Description( + shortDefinition="Organization that is the custodian of the patient record", + formalDefinition="Organization that is the custodian of the patient record" + ) + private ResourceReferenceDt myManagingOrganization; + + + @Override + public boolean isEmpty() { + return super.isEmpty() && myPetName.isEmpty(); + } + + + public List getImportantDates() { + if (myImportantDates==null) { + myImportantDates = new ArrayList(); + } + return myImportantDates; + } + + public StringDt getPetName() { + return myPetName; + } + + public void setImportantDates(List theImportantDates) { + myImportantDates = theImportantDates; + } + + public void setPetName(StringDt thePetName) { + myPetName = thePetName; + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java new file mode 100644 index 00000000000..ffdfeef5cee --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/parser/XmlParserTest.java @@ -0,0 +1,1446 @@ +package ca.uhn.fhir.parser; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.stringContainsInOrder; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.UUID; + +import org.apache.commons.io.IOUtils; +import org.custommonkey.xmlunit.Diff; +import org.custommonkey.xmlunit.XMLUnit; +import org.hamcrest.core.IsNot; +import org.hamcrest.core.StringContains; +import org.hamcrest.text.StringContainsInOrder; +import org.junit.BeforeClass; +import org.junit.Test; +import org.xml.sax.SAXException; + +import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.ResourceWithExtensionsA; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.ExtensionDt; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.composite.AddressDt; +import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.NarrativeDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Binary; +import ca.uhn.fhir.model.dstu.resource.Composition; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.DocumentManifest; +import ca.uhn.fhir.model.dstu.resource.ListResource; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.resource.Profile; +import ca.uhn.fhir.model.dstu.resource.Query; +import ca.uhn.fhir.model.dstu.resource.Specimen; +import ca.uhn.fhir.model.dstu.resource.ValueSet; +import ca.uhn.fhir.model.dstu.valueset.AddressUseEnum; +import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum; +import ca.uhn.fhir.model.dstu.valueset.DocumentReferenceStatusEnum; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.DecimalDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.XhtmlDt; +import ca.uhn.fhir.narrative.INarrativeGenerator; +import ca.uhn.fhir.parser.JsonParserTest.MyPatientWithOneDeclaredAddressExtension; +import ca.uhn.fhir.parser.JsonParserTest.MyPatientWithOneDeclaredExtension; + +public class XmlParserTest { + + private static FhirContext ourCtx; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(XmlParserTest.class); + + @BeforeClass + public static void beforeClass2() { + System.setProperty("file.encoding", "ISO-8859-1"); + } + + @Test + public void testEncodeNonContained() { + // Create an organization + Organization org = new Organization(); + org.setId("Organization/65546"); + org.getName().setValue("Contained Test Organization"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + patient.getManagingOrganization().setResource(org); + + // Create a list containing both resources. In a server method, you might just + // return this list, but here we will create a bundle to encode. + List resources = new ArrayList(); + resources.add(org); + resources.add(patient); + + // Create a bundle with both + Bundle b = Bundle.withResources(resources, ourCtx, "http://example.com/base"); + + // Encode the buntdle + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(encoded); + assertThat(encoded, not(containsString(""))); + assertThat(encoded, containsString("")); + + encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, not(containsString(""))); + assertThat(encoded, containsString("")); + + + } + + @Test + public void testEncodeContainedWithNarrativeIsSuppresed() { + IParser parser = ourCtx.newXmlParser().setPrettyPrint(true); + + // Create an organization, note that the organization does not have an ID + Organization org = new Organization(); + org.getName().setValue("Contained Test Organization"); + org.getText().setDiv("
FOOBAR
"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + patient.getText().setDiv("
BARFOO
"); + patient.getManagingOrganization().setResource(org); + + String encoded = parser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, not(containsString("FOOBAR"))); + assertThat(encoded, (containsString("BARFOO"))); + + } + + + @Test + public void testEncodeContained() { + IParser xmlParser = ourCtx.newXmlParser().setPrettyPrint(true); + + // Create an organization, note that the organization does not have an ID + Organization org = new Organization(); + org.getName().setValue("Contained Test Organization"); + + // Create a patient + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + + // Put the organization as a reference in the patient resource + patient.getManagingOrganization().setResource(org); + + String encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, containsString("")); + assertThat(encoded, containsString("")); + + // Create a bundle with just the patient resource + List resources = new ArrayList(); + resources.add(patient); + Bundle b = Bundle.withResources(resources, ourCtx, "http://example.com/base"); + + // Encode the buntdle + encoded = xmlParser.encodeBundleToString(b); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("","id=\"1\"", ""))); + assertThat(encoded, containsString("")); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "", "")))); + + // Re-parse the bundle + patient = (Patient) xmlParser.parseResource(xmlParser.encodeResourceToString(patient)); + assertEquals("#1", patient.getManagingOrganization().getReference().getValue()); + + assertNotNull(patient.getManagingOrganization().getResource()); + org = (Organization) patient.getManagingOrganization().getResource(); + assertEquals("#1", org.getId().getValue()); + assertEquals("Contained Test Organization", org.getName().getValue()); + + // And re-encode a second time + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + assertThat(encoded, containsString("")); + + // And re-encode once more, with the references cleared + patient.getContained().getContainedResources().clear(); + patient.getManagingOrganization().setReference((IdDt)null); + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + assertThat(encoded, containsString("")); + + // And re-encode once more, with the references cleared and a manually set local ID + patient.getContained().getContainedResources().clear(); + patient.getManagingOrganization().setReference((IdDt)null); + patient.getManagingOrganization().getResource().setId(new IdDt("#333")); + encoded = xmlParser.encodeResourceToString(patient); + ourLog.info(encoded); + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "")))); + + } + + + /** + * Thanks to Alexander Kley! + */ + @Test + public void testParseContainedBinaryResource() { + byte[] bin = new byte[] {0,1,2,3,4}; + final Binary binary = new Binary("PatientConsent", bin); +// binary.setId(UUID.randomUUID().toString()); + DocumentManifest manifest = new DocumentManifest(); +// manifest.setId(UUID.randomUUID().toString()); + manifest.setType(new CodeableConceptDt("mySystem", "PatientDocument")); + manifest.setMasterIdentifier("mySystem", UUID.randomUUID().toString()); + manifest.addContent().setResource(binary); + manifest.setStatus(DocumentReferenceStatusEnum.CURRENT); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(manifest); + ourLog.info(encoded); + assertThat(encoded, StringContainsInOrder.stringContainsInOrder(Arrays.asList("contained>",""))); + + DocumentManifest actual = ourCtx.newXmlParser().parseResource(DocumentManifest.class, encoded); + assertEquals(1, actual.getContained().getContainedResources().size()); + assertEquals(1, actual.getContent().size()); + assertNotNull(actual.getContent().get(0).getResource()); + + } + + + @Test + public void testComposition() { + + Composition comp = new Composition(); + comp.setId("1"); + + ourCtx.newXmlParser().encodeResourceToString(comp); + ourCtx.newXmlParser().encodeResourceToString(comp); + ourCtx.newXmlParser().encodeResourceToString(comp); + ourCtx.newXmlParser().encodeResourceToString(comp); + +// comp. + + } + + + @Test + public void testEncodeProfile() { + + Profile p = new Profile(); + p.getStructureFirstRep().getElementFirstRep().getDefinition().getBinding().setReference(new ResourceReferenceDt("ValudSet/123")); + + String encoded = ourCtx.newXmlParser().encodeResourceToString(p); + ourLog.info(encoded); + } + + @Test + public void testEncodeBinaryResource() { + + Binary patient = new Binary(); + patient.setContentType("foo"); + patient.setContent(new byte[] { 1, 2, 3, 4 }); + + String val = ourCtx.newXmlParser().encodeResourceToString(patient); + assertEquals("AQIDBA==", val); + + } + + @Test + public void testEncodeBoundCode() { + + Patient patient = new Patient(); + patient.addAddress().setUse(AddressUseEnum.HOME); + + patient.getGender().setValueAsEnum(AdministrativeGenderCodesEnum.M); + + String val = ourCtx.newXmlParser().encodeResourceToString(patient); + ourLog.info(val); + + } + + @Test + public void testEncodeBundle() throws InterruptedException { + Bundle b = new Bundle(); + b.getCategories().addTag("http://hl7.org/fhir/tag", "http://hl7.org/fhir/tag/message", "Message"); + + InstantDt pub = InstantDt.withCurrentTime(); + b.setPublished(pub); + Thread.sleep(2); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + entry.getSummary().setValueAsString("this is the summary"); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setLinkAlternate(new StringDt("http://foo/bar")); + entry.setLinkSearch(new StringDt("http://foo/bar/search")); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(InstantDt.withCurrentTime()); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + List strings = new ArrayList(); + strings.addAll(Arrays.asList("", pub.getValueAsString(), "")); + strings.add(""); + strings.addAll(Arrays.asList("", "1", "", "", "")); + strings.addAll(Arrays.asList("", "2", "", "", "")); + strings.addAll(Arrays.asList("")); + assertThat(bundleString, StringContainsInOrder.stringContainsInOrder(strings)); + assertThat(bundleString, not(containsString("at:by"))); + + } + + @Test + public void testEncodeBundleCategory() { + + Bundle b = new Bundle(); + BundleEntry e = b.addEntry(); + e.setResource(new Patient()); + e.addCategory("scheme", "term", "label"); + + String val = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(val); + + assertThat(val, StringContains.containsString("")); + + b = ourCtx.newXmlParser().parseBundle(val); + assertEquals(1, b.getEntries().size()); + assertEquals(1, b.getEntries().get(0).getCategories().size()); + assertEquals("term", b.getEntries().get(0).getCategories().get(0).getTerm()); + assertEquals("label", b.getEntries().get(0).getCategories().get(0).getLabel()); + assertEquals("scheme", b.getEntries().get(0).getCategories().get(0).getScheme()); + assertNull(b.getEntries().get(0).getResource()); + + } + + @Test + public void testEncodeBundleResultCount() { + + Bundle b = new Bundle(); + b.getTotalResults().setValue(123); + + String val = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(val); + + assertThat(val, StringContains.containsString("123")); + + } + + @Test + public void testEncodeEscapedChars() { + + Patient p = new Patient(); + p.addName().addFamily("and <>&ü"); + + String enc = ourCtx.newXmlParser().encodeResourceToString(p); + ourLog.info(enc); + + p = ourCtx.newXmlParser().parseResource(Patient.class, enc); + assertEquals("and <>&ü", p.getNameFirstRep().getFamilyFirstRep().getValue()); + + p = ourCtx.newXmlParser().parseResource(Patient.class, ""); + assertEquals("quot \"", p.getNameFirstRep().getFamilyFirstRep().getValue()); + + } + + @Test + public void testEncodeEscapedExtendedChars() { + Patient p = ourCtx.newXmlParser().parseResource(Patient.class, ""); + assertEquals("uuml ü", p.getNameFirstRep().getFamilyFirstRep().getValue()); + } + + @Test + public void testEncodeContainedAndIncludedResources() { + + DiagnosticReport rpt = new DiagnosticReport(); + rpt.getName().setText("Report"); + + Specimen spm = new Specimen(); + spm.addIdentifier().setLabel("Report1ContainedSpecimen1"); + rpt.addSpecimen().setResource(spm); + + IParser p = ourCtx.newXmlParser().setPrettyPrint(true); + String str = p.encodeResourceToString(rpt); + + ourLog.info(str); + + } + + @Test + public void testEncodeContainedResources() { + + DiagnosticReport rpt = new DiagnosticReport(); + Specimen spm = new Specimen(); + spm.addIdentifier("urn", "123"); + rpt.getText().setDiv("AAA"); + rpt.addSpecimen().setResource(spm); + + IParser p = ourCtx.newXmlParser().setPrettyPrint(true); + String str = p.encodeResourceToString(rpt); + + ourLog.info(str); + assertThat(str, StringContains.containsString("
AAA
")); + assertThat(str, StringContains.containsString("reference value=\"#")); + + int idx = str.indexOf("reference value=\"#") + "reference value=\"#".length(); + int idx2 = str.indexOf('"', idx + 1); + String id = str.substring(idx, idx2); + assertThat(str, StringContains.containsString("")); + assertThat(str, IsNot.not(StringContains.containsString(""))); + + } + + @Test + public void testEncodeDeclaredExtensionWithAddressContent() { + IParser parser = ourCtx.newXmlParser(); + + MyPatientWithOneDeclaredAddressExtension patient = new MyPatientWithOneDeclaredAddressExtension(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.setFoo(new AddressDt().addLine("line1")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("")); + + MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + AddressDt ref = actual.getFoo(); + assertEquals("line1", ref.getLineFirstRep().getValue()); + + } + + @Test + public void testEncodeDeclaredExtensionWithResourceContent() { + IParser parser = ourCtx.newXmlParser(); + + MyPatientWithOneDeclaredExtension patient = new MyPatientWithOneDeclaredExtension(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.setFoo(new ResourceReferenceDt("Organization/123")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("")); + + MyPatientWithOneDeclaredExtension actual = parser.parseResource(MyPatientWithOneDeclaredExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + ResourceReferenceDt ref = actual.getFoo(); + assertEquals("Organization/123", ref.getReference().getValue()); + + } + + @Test + public void testEncodeExtensionWithResourceContent() { + IParser parser = ourCtx.newXmlParser(); + + Patient patient = new Patient(); + patient.addAddress().setUse(AddressUseEnum.HOME); + patient.addUndeclaredExtension(false, "urn:foo", new ResourceReferenceDt("Organization/123")); + + String val = parser.encodeResourceToString(patient); + ourLog.info(val); + assertThat(val, StringContains.containsString("")); + + Patient actual = parser.parseResource(Patient.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + List ext = actual.getUndeclaredExtensionsByUrl("urn:foo"); + assertEquals(1, ext.size()); + ResourceReferenceDt ref = (ResourceReferenceDt) ext.get(0).getValue(); + assertEquals("Organization/123", ref.getReference().getValue()); + + } + + @Test + public void testEncodeInvalidChildGoodException() { + Observation obs = new Observation(); + obs.setValue(new DecimalDt(112.22)); + + IParser p = ourCtx.newJsonParser(); + + try { + p.encodeResourceToString(obs); + } catch (DataFormatException e) { + assertThat(e.getMessage(), StringContains.containsString("DecimalDt")); + } + } + + @Test + public void testEncodeNarrativeBlockInBundle() { + Patient p = new Patient(); + p.addIdentifier("foo", "bar"); + p.getText().setStatus(NarrativeStatusEnum.GENERATED); + p.getText().setDiv("
hello
"); + + Bundle b = new Bundle(); + b.getTotalResults().setValue(123); + b.addEntry().setResource(p); + + String out = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(out); + assertThat(out, containsString("
hello
")); + + p.getText().setDiv("hello"); + out = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(out); + assertThat(out, containsString("hello")); + + } + + @Test + public void testEncodePrettyPrint() throws DataFormatException { + + Patient patient = new Patient(); + patient.getText().getDiv().setValueAsString("
\n hello
\n  LINE1\n  LINE2
\n\n\n\n
"); + patient.addName().addFamily("Family").addGiven("Given"); + + //@formatter:off + String encoded = ourCtx.newXmlParser().setPrettyPrint(false).encodeResourceToString(patient); + ourLog.info(encoded); + /* + * Note at least one space is placed where any whitespace was, as + * it is hard to tell what whitespace had no purpose + */ + String expected = "
" + + " hello " + + "
\n  LINE1\n  LINE2
" + + "
"; + assertEquals(expected, encoded); + + encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(encoded); + expected = "\n" + + " \n" + + "
\n" + + " hello \n" + + "
\n  LINE1\n  LINE2
\n" + + "
\n" + + "
\n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + "
"; + //@formatter:on + + // Whitespace should be preserved and not reformatted in narrative blocks + assertEquals(expected, encoded); + + } + + @Test + public void testEncodeQuery() { + Query q = new Query(); + ExtensionDt parameter = q.addParameter(); + parameter.setUrl("http://foo").setValue(new StringDt("bar")); + + String val = ourCtx.newXmlParser().encodeResourceToString(q); + ourLog.info(val); + + assertEquals("", val); + + } + + @Test + public void testEncodeResourceRef() throws DataFormatException { + + Patient patient = new Patient(); + patient.setManagingOrganization(new ResourceReferenceDt()); + + IParser p = ourCtx.newXmlParser(); + String str = p.encodeResourceToString(patient); + assertThat(str, IsNot.not(StringContains.containsString("managingOrganization"))); + + ResourceReferenceDt ref = new ResourceReferenceDt(); + ref.setReference("Organization/123"); + ref.setDisplay("DISPLAY!"); + patient.setManagingOrganization(ref); + str = p.encodeResourceToString(patient); + assertThat(str, StringContains.containsString("")); + + Organization org = new Organization(); + org.addIdentifier().setSystem("foo").setValue("bar"); + patient.setManagingOrganization(new ResourceReferenceDt(org)); + str = p.encodeResourceToString(patient); + assertThat(str, StringContains.containsString("")); + + MyPatientWithOneDeclaredAddressExtension actual = parser.parseResource(MyPatientWithOneDeclaredAddressExtension.class, val); + assertEquals(AddressUseEnum.HOME, patient.getAddressFirstRep().getUse().getValueAsEnum()); + AddressDt ref = actual.getFoo(); + assertEquals("line1", ref.getLineFirstRep().getValue()); + + } + + @Test + public void testExtensionOnComposite() throws Exception { + + Patient patient = new Patient(); + + HumanNameDt name = patient.addName(); + name.addFamily().setValue("Shmoe"); + HumanNameDt given = name.addGiven("Joe"); + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); + given.addUndeclaredExtension(ext2); + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString("")); + + Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); + assertEquals(1, parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); + ExtensionDt ext = parsed.getNameFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); + assertEquals("Hello", ext.getValueAsPrimitive().getValue()); + + } + + @Test + public void testExtensionOnPrimitive() throws Exception { + + Patient patient = new Patient(); + + HumanNameDt name = patient.addName(); + StringDt family = name.addFamily(); + family.setValue("Shmoe"); + + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("Hello")); + family.addUndeclaredExtension(ext2); + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString("")); + + Patient parsed = ourCtx.newXmlParser().parseResource(Patient.class, new StringReader(enc)); + assertEquals(1, parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").size()); + ExtensionDt ext = parsed.getNameFirstRep().getFamilyFirstRep().getUndeclaredExtensionsByUrl("http://examples.com#givenext").get(0); + assertEquals("Hello", ext.getValueAsPrimitive().getValue()); + + } + + @Test + public void testExtensions() throws DataFormatException { + + MyPatient patient = new MyPatient(); + patient.setPetName(new StringDt("Fido")); + patient.getImportantDates().add(new DateTimeDt("2010-01-02")); + patient.getImportantDates().add(new DateTimeDt("2014-01-26T11:11:11")); + + patient.addName().addFamily("Smith"); + + IParser p = ourCtx.newXmlParser(); + String str = p.encodeResourceToString(patient); + + ourLog.info(str); + + assertThat(str, StringContains.containsString("")); + assertThat(str, StringContains.containsString("")); + assertThat(str, StringContains.containsString("")); + assertThat(str, StringContains.containsString("")); + assertThat(str, StringContains.containsString("")); + + } + + @Test + public void testLoadAndAncodeMessage() throws SAXException, IOException { + + //@formatter:off + String msg = "" + + "
John Cardinal: 444333333
" + + "" + + "" + + "" + + "" + + "" + + "
" + + "
"; + //@formatter:on + + Patient patient = ourCtx.newXmlParser().parseResource(Patient.class, msg); + + assertEquals(NarrativeStatusEnum.GENERATED, patient.getText().getStatus().getValueAsEnum()); + assertEquals("
John Cardinal: 444333333
", patient.getText().getDiv().getValueAsString()); + assertEquals("PRP1660", patient.getIdentifier().get(0).getValue().getValueAsString()); + + String encoded = ourCtx.newXmlParser().encodeResourceToString(patient); + + Diff d = new Diff(new StringReader(msg), new StringReader(encoded)); + assertTrue(d.toString(), d.identical()); + + } + + @Test + public void testLoadAndEncodeDeclaredExtensions() throws ConfigurationException, DataFormatException, SAXException, IOException { + IParser p = new FhirContext(ResourceWithExtensionsA.class).newXmlParser(); + + //@formatter:off + String msg = "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + ResourceWithExtensionsA resource = (ResourceWithExtensionsA) p.parseResource(msg); + assertEquals("IdentifierLabel", resource.getIdentifier().get(0).getLabel().getValue()); + assertEquals("Foo1Value", resource.getFoo1().get(0).getValue()); + assertEquals("Foo1Value2", resource.getFoo1().get(1).getValue()); + assertEquals("Foo2Value1", resource.getFoo2().getValue()); + assertEquals("2013-01-01", resource.getBar1().get(0).getBar11().get(0).getValueAsString()); + assertEquals("2013-01-02", resource.getBar1().get(0).getBar12().get(0).getBar121().get(0).getValueAsString()); + assertEquals("2013-01-12", resource.getBar1().get(0).getBar12().get(0).getBar121().get(1).getValueAsString()); + assertEquals("2013-01-03", resource.getBar1().get(0).getBar12().get(0).getBar122().get(0).getValueAsString()); + + String encoded = p.encodeResourceToString(resource); + ourLog.info(encoded); + + Diff d = new Diff(new StringReader(msg), new StringReader(encoded)); + assertTrue(d.toString(), d.identical()); + } + + @Test + public void testLoadAndEncodeUndeclaredExtensions() throws ConfigurationException, DataFormatException, SAXException, IOException { + IParser p = ourCtx.newXmlParser(); + + //@formatter:off + String msg = "\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + Patient resource = (Patient) p.parseResource(msg); + assertEquals("IdentifierLabel", resource.getIdentifier().get(0).getLabel().getValue()); + assertEquals("Foo1Value", resource.getUndeclaredExtensions().get(0).getValueAsPrimitive().getValueAsString()); + assertEquals("Foo1Value2", resource.getUndeclaredExtensions().get(1).getValueAsPrimitive().getValueAsString()); + assertEquals("Foo2Value1", resource.getUndeclaredModifierExtensions().get(0).getValueAsPrimitive().getValueAsString()); + + assertEquals("2013-01-01", resource.getUndeclaredExtensions().get(2).getUndeclaredExtensions().get(0).getValueAsPrimitive().getValueAsString()); + assertEquals("2013-01-02", resource.getUndeclaredExtensions().get(2).getUndeclaredExtensions().get(1).getUndeclaredExtensions().get(0).getValueAsPrimitive().getValueAsString()); + + String encoded = p.encodeResourceToString(resource); + ourLog.info(encoded); + + Diff d = new Diff(new StringReader(msg), new StringReader(encoded)); + assertTrue(d.toString(), d.identical()); + } + + @Test + public void testLoadObservation() throws ConfigurationException, DataFormatException, IOException { + + IParser p = ourCtx.newXmlParser(); + + String string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/observation-example-eeg.xml"), Charset.forName("UTF-8")); + IResource resource = p.parseResource(string); + + String result = p.encodeResourceToString(resource); + ourLog.info(result); + } + + @Test + public void testParseFeedWithListResource() throws ConfigurationException, DataFormatException, IOException { + + // Use new context here to ensure List isn't already loaded + IParser p = new FhirContext().newXmlParser(); + + String string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/feed-with-list.xml"), Charset.forName("UTF-8")); + Bundle bundle = p.parseBundle(string); + + ListResource res = (ListResource) bundle.toListOfResources().get(2); + assertEquals("cid:patient@bundle", res.getSubject().getReference().getValue()); + + } + + @Test + public void testLoadPatient() throws ConfigurationException, DataFormatException, IOException { + + IParser p = ourCtx.newXmlParser(); + + String string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/patient-example-dicom.xml"), Charset.forName("UTF-8")); + IResource resource = p.parseResource(string); + + String result = p.encodeResourceToString(resource); + ourLog.info(result); + + // Nothing + + string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/patient-example-us-extensions.xml"), Charset.forName("UTF-8")); + resource = p.parseResource(string); + + result = p.encodeResourceToString(resource); + ourLog.info(result); + + } + + @Test + public void testLoadQuestionnaire() throws ConfigurationException, DataFormatException, IOException { + + IParser p = ourCtx.newXmlParser(); + + String string = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/questionnaire-example.xml"), Charset.forName("UTF-8")); + IResource resource = p.parseResource(string); + + String result = p.encodeResourceToString(resource); + ourLog.info(result); + } + + @Test + public void testMessageWithMultipleTypes() throws SAXException, IOException { + + //@formatter:off + String msg = "" + + "" + + ""; + //@formatter:on + + Patient patient1 = ourCtx.newXmlParser().parseResource(Patient.class, msg); + String encoded1 = ourCtx.newXmlParser().encodeResourceToString(patient1); + + ca.uhn.fhir.testmodel.Patient patient2 = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.testmodel.Patient.class, msg); + String encoded2 = ourCtx.newXmlParser().encodeResourceToString(patient2); + + Diff d = new Diff(new StringReader(encoded1), new StringReader(encoded2)); + assertTrue(d.toString(), d.identical()); + + } + + @Test + public void testMoreExtensions() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier(IdentifierUseEnum.OFFICIAL, "urn:example", "7000135", null); + + ExtensionDt ext = new ExtensionDt(); + ext.setModifier(false); + ext.setUrl("http://example.com/extensions#someext"); + ext.setValue(new DateTimeDt("2011-01-02T11:13:15")); + + // Add the extension to the resource + patient.addUndeclaredExtension(ext); + // END SNIPPET: resourceExtension + + // START SNIPPET: resourceStringExtension + HumanNameDt name = patient.addName(); + name.addFamily().setValue("Shmoe"); + StringDt given = name.addGiven(); + given.setValue("Joe"); + ExtensionDt ext2 = new ExtensionDt(false, "http://examples.com#givenext", new StringDt("given")); + given.addUndeclaredExtension(ext2); + // END SNIPPET: resourceStringExtension + + // START SNIPPET: subExtension + ExtensionDt parent = new ExtensionDt(false, "http://example.com#parent"); + patient.addUndeclaredExtension(parent); + + ExtensionDt child1 = new ExtensionDt(false, "http://example.com#child", new StringDt("value1")); + parent.addUndeclaredExtension(child1); + + ExtensionDt child2 = new ExtensionDt(false, "http://example.com#child", new StringDt("value1")); + parent.addUndeclaredExtension(child2); + // END SNIPPET: subExtension + + String output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); + ourLog.info(output); + + String enc = ourCtx.newXmlParser().encodeResourceToString(patient); + assertThat(enc, containsString("")); + assertThat( + enc, + containsString("")); + assertThat(enc, containsString("")); + } + + @Test + public void testNarrativeGeneration() throws DataFormatException { + + Patient patient = new Patient(); + + patient.addName().addFamily("Smith"); + + INarrativeGenerator gen = mock(INarrativeGenerator.class); + XhtmlDt xhtmlDt = new XhtmlDt("
help
"); + NarrativeDt nar = new NarrativeDt(xhtmlDt, NarrativeStatusEnum.GENERATED); + when(gen.generateNarrative(eq("http://hl7.org/fhir/profiles/Patient"), eq(patient))).thenReturn(nar); + + FhirContext context = ourCtx; + context.setNarrativeGenerator(gen); + IParser p = context.newXmlParser(); + String str = p.encodeResourceToString(patient); + + ourLog.info(str); + + assertThat(str, StringContains.containsString("")); + assertThat(str, StringContains.containsString("")); + } + + @Test + public void testDuplicateContainedResources() { + + Observation resA = new Observation(); + resA.getName().setText("A"); + + Observation resB = new Observation(); + resB.getName().setText("B"); + resB.addRelated().setTarget(new ResourceReferenceDt(resA)); + resB.addRelated().setTarget(new ResourceReferenceDt(resA)); + + String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resB); + ourLog.info(encoded); + + assertThat(encoded, stringContainsInOrder(Arrays.asList("", "", ""))); + assertThat(encoded, not(stringContainsInOrder(Arrays.asList("", "", "")))); + + } + + @Test + public void testNestedContainedResources() { + + Observation A = new Observation(); + A.getName().setText("A"); + + Observation B = new Observation(); + B.getName().setText("B"); + A.addRelated().setTarget(new ResourceReferenceDt(B)); + + Observation C = new Observation(); + C.getName().setText("C"); + B.addRelated().setTarget(new ResourceReferenceDt(C)); + + String str = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(A); + ourLog.info(str); + + assertThat(str, stringContainsInOrder(Arrays.asList("", "", ""))); + assertThat(str, stringContainsInOrder(Arrays.asList("", ""))); + + // Only one (outer) contained block + int idx0 = str.indexOf(""); + int idx1 = str.indexOf("", idx0 + 1); + assertNotEquals(-1, idx0); + assertEquals(-1, idx1); + + Observation obs = ourCtx.newXmlParser().parseResource(Observation.class, str); + assertEquals("A", obs.getName().getText().getValue()); + + Observation obsB = (Observation) obs.getRelatedFirstRep().getTarget().getResource(); + assertEquals("B", obsB.getName().getText().getValue()); + + Observation obsC = (Observation) obsB.getRelatedFirstRep().getTarget().getResource(); + assertEquals("C", obsC.getName().getText().getValue()); + + } + + @Test + public void testParseBinaryResource() { + + Binary val = ourCtx.newXmlParser().parseResource(Binary.class, "AQIDBA=="); + assertEquals("foo", val.getContentType()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, val.getContent()); + + } + + @SuppressWarnings("deprecation") + @Test + public void testParseBundle() { + + //@formatter:off + String summaryText = + "
\n" + + "

Value set \"LOINC Codes for Cholesterol\": This is an example value set that includes \n" + + " all the LOINC codes for serum cholesterol from v2.36. \n" + + " Developed by: FHIR project team (example)

"; + + String msg = "\n" + + " FHIR Core Valuesets\n" + + " http://hl7.org/fhir/profile/valuesets\n" + + " \n" + + " \n" + + " 2014-02-10T04:11:24.435-00:00\n" + + " \n" + + " Valueset "256a5231-a2bb-49bd-9fea-f349d428b70d" to support automated processing\n" + + " http://hl7.org/fhir/valueset/256a5231-a2bb-49bd-9fea-f349d428b70d\n" + + " \n" + + " \n" + + " \n" + + " 2014-02-10T04:10:46.987-00:00\n" + + " \n" + + " HL7, Inc (FHIR Project)\n" + + " http://hl7.org/fhir\n" + + " \n" + + " 2014-02-10T04:10:46.987-00:00\n" + + " \n "+ + " \n" + + " \n" + + " \n" + + " " + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " "+ + summaryText + + " \n" + + " " + + ""; + //@formatter:on + + IParser p = new FhirContext(ValueSet.class).newXmlParser(); + Bundle bundle = p.parseBundle(msg); + + assertEquals(1, bundle.getCategories().size()); + assertEquals("http://hl7.org/fhir/tag", bundle.getCategories().get(0).getScheme()); + + assertEquals("FHIR Core Valuesets", bundle.getTitle().getValue()); + assertEquals("http://hl7.org/implement/standards/fhir/valuesets.xml", bundle.getLinkSelf().getValue()); + assertEquals("2014-02-10T04:11:24.435+00:00", bundle.getUpdated().getValueAsString()); + assertEquals(1, bundle.getEntries().size()); + + BundleEntry entry = bundle.getEntries().get(0); + assertEquals("HL7, Inc (FHIR Project)", entry.getAuthorName().getValue()); + assertEquals("http://hl7.org/fhir/valueset/256a5231-a2bb-49bd-9fea-f349d428b70d", entry.getId().getValue()); + assertEquals("http://hl7.org/foo", entry.getLinkAlternate().getValue()); + assertEquals("http://hl7.org/foo/search", entry.getLinkSearch().getValue()); + assertEquals(1, entry.getCategories().size()); + assertEquals("term", entry.getCategories().get(0).getTerm()); + assertEquals("label", entry.getCategories().get(0).getLabel()); + assertEquals("http://foo", entry.getCategories().get(0).getScheme()); + + ValueSet resource = (ValueSet) entry.getResource(); + assertEquals("LOINC Codes for Cholesterol", resource.getName().getValue()); + + String exp = summaryText.trim(); + exp = exp.replace("\"LOINC", ""LOINC"); + exp = exp.replace("terol\"", "terol""); + assertEquals(exp, entry.getSummary().getValueAsString().trim()); + + TagList tl = (TagList) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST); + assertEquals(1, tl.size()); + assertEquals("term", tl.get(0).getTerm()); + assertEquals("label", tl.get(0).getLabel()); + assertEquals("http://foo", tl.get(0).getScheme()); + + assertEquals("256a5231-a2bb-49bd-9fea-f349d428b70d", resource.getId().getIdPart()); + + msg = msg.replace("", + ""); + entry = p.parseBundle(msg).getEntries().get(0); + resource = (ValueSet) entry.getResource(); + assertEquals("256a5231-a2bb-49bd-9fea-f349d428b70d", resource.getId().getIdPart()); + assertEquals("12345", resource.getId().getVersionIdPart()); + assertEquals("12345", ((IdDt) resource.getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION_ID)).getVersionIdPart()); + + assertThat(entry.getSummary().getValueAsString(), containsString("LOINC Codes for Cholesterol")); + + } + + @SuppressWarnings("deprecation") + @Test + public void testParseBundleDeletedEntry() { + + //@formatter:off + String msg = "" + + "FHIR Core Valuesets" + + "http://hl7.org/fhir/profile/valuesets" + + "" + + "2014-02-10T04:11:24.435+00:00" + + "" + + "" + + "John Doe" + + "jdoe@example.org" + + "" + + "Removed comment spam" + + "" + + "" + + ""; + //@formatter:on + + IParser p = ourCtx.newXmlParser(); + Bundle bundle = p.parseBundle(msg); + + BundleEntry entry = bundle.getEntries().get(0); + assertEquals("http://foo/Patient/1", entry.getId().getValue()); + assertEquals("2013-02-10T04:11:24.435+00:00", entry.getDeletedAt().getValueAsString()); + assertEquals("http://foo/Patient/1/_history/2", entry.getLinkSelf().getValue()); + assertEquals("1", entry.getResource().getId().getIdPart()); + assertEquals("2", entry.getResource().getId().getVersionIdPart()); + assertEquals("2", ((IdDt) entry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.VERSION_ID)).getVersionIdPart()); + assertEquals("John Doe", entry.getDeletedByName().getValue()); + assertEquals("jdoe@example.org", entry.getDeletedByEmail().getValue()); + assertEquals("Removed comment spam", entry.getDeletedComment().getValue()); + assertEquals(new InstantDt("2013-02-10T04:11:24.435+00:00"), entry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.DELETED_AT)); + + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle)); + + String encoded = ourCtx.newXmlParser().encodeBundleToString(bundle); + assertEquals(msg, encoded); + + } + + @Test + public void testParseBundleLarge() throws IOException { + + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/atom-document-large.xml")); + IParser p = ourCtx.newXmlParser(); + Bundle bundle = p.parseBundle(msg); + + assertEquals("http://spark.furore.com/fhir/_snapshot?id=327d6bb9-83b0-4929-aa91-6dd9c41e587b&start=0&_count=20", bundle.getLinkSelf().getValue()); + assertEquals("Patient resource with id 3216379", bundle.getEntries().get(0).getTitle().getValue()); + assertEquals("http://spark.furore.com/fhir/Patient/3216379", bundle.getEntries().get(0).getId().getValue()); + assertEquals("3216379", bundle.getEntries().get(0).getResource().getId().getIdPart()); + + } + + @Test + public void testParseBundleWithMixedReturnTypes() { + InputStreamReader str = new InputStreamReader(getClass().getResourceAsStream("/mixed-return-bundle.xml")); + Bundle b = ourCtx.newXmlParser().parseBundle(Patient.class, str); + assertEquals(Patient.class, b.getEntries().get(0).getResource().getClass()); + assertEquals(Patient.class, b.getEntries().get(1).getResource().getClass()); + assertEquals(Organization.class, b.getEntries().get(2).getResource().getClass()); + } + + @Test + public void testParseContainedResources() throws IOException { + + String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/contained-diagnosticreport.xml")); + IParser p = ourCtx.newXmlParser(); + DiagnosticReport bundle = p.parseResource(DiagnosticReport.class, msg); + + ResourceReferenceDt result0 = bundle.getResult().get(0); + Observation obs = (Observation) result0.getResource(); + + assertNotNull(obs); + assertEquals("718-7", obs.getName().getCoding().get(0).getCode().getValue()); + + } + + @Test + public void testParseEncodeNarrative() { + + String input = "
Donald null DUCK
Identifier7000135
Address10 Duxon Street
VICTORIA BC Can
Date of birth01 June 1980
"; + IResource res = ourCtx.newXmlParser().parseResource(input); + + String output = ourCtx.newXmlParser().encodeResourceToString(res); + + // Should occur exactly twice (once for the resource, once for the DIV + assertThat(output, (StringContainsInOrder.stringContainsInOrder(Arrays.asList("Patient xmlns", "div xmlns")))); + assertThat(output, not(StringContainsInOrder.stringContainsInOrder(Arrays.asList("b xmlns")))); + + output = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(res); + + // Should occur exactly twice (once for the resource, once for the DIV + assertThat(output, (StringContainsInOrder.stringContainsInOrder(Arrays.asList("Patient xmlns", "div xmlns")))); + assertThat(output, not(StringContainsInOrder.stringContainsInOrder(Arrays.asList("b xmlns")))); + + } + + /** + * This sample has extra elements in that are not actually a part of the spec any more.. + */ + @Test + public void testParseFuroreMetadataWithExtraElements() throws IOException { + String msg = IOUtils.toString(XmlParserTest.class.getResourceAsStream("/furore-conformance.xml")); + + IParser p = new FhirContext(ValueSet.class).newXmlParser(); + Conformance conf = p.parseResource(Conformance.class, msg); + RestResource res = conf.getRestFirstRep().getResourceFirstRep(); + assertEquals("_id", res.getSearchParam().get(1).getName().getValue()); + } + + @Test + public void testParseLanguage() { + String input = "
海生
IdentifierURNo
Address99 Houston Road
BENTLEIGH Victoria
Date of birth01 January 1997
"; + Patient pt = ourCtx.newXmlParser().parseResource(Patient.class, input); + + assertEquals("zh-CN", pt.getLanguage().getValue()); + } + + @Test + public void testParseQuery() { + String msg = "\n" + " \n" + " \n" + "
[Put rendering here]
\n" + + "
\n" + "\n" + " \n" + + " \n" + " \n" + " \n" + + " \n" + "
"; + Query query = ourCtx.newXmlParser().parseResource(Query.class, msg); + + assertEquals("urn:uuid:42b253f5-fa17-40d0-8da5-44aeb4230376", query.getIdentifier().getValueAsString()); + assertEquals("http://hl7.org/fhir/query#_query", query.getParameterFirstRep().getUrlAsString()); + assertEquals("example", query.getParameterFirstRep().getValueAsPrimitive().getValueAsString()); + + } + + @Test + public void testParseWithXmlHeader() throws ConfigurationException, DataFormatException { + IParser p = ourCtx.newXmlParser(); + + //@formatter:off + String msg = "" + + "\n" + + " \n" + + " \n" + + ""; + //@formatter:on + + Patient resource = (Patient) p.parseResource(msg); + assertEquals("IdentifierLabel", resource.getIdentifier().get(0).getLabel().getValue()); + } + + @Test + public void testSimpleResourceEncode() throws IOException, SAXException { + + String xmlString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.json"), Charset.forName("UTF-8")); + Patient obs = ourCtx.newJsonParser().parseResource(Patient.class, xmlString); + + List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); + ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + + ourCtx.newJsonParser().setPrettyPrint(true).encodeResourceToWriter(obs, new OutputStreamWriter(System.out)); + + IParser jsonParser = ourCtx.newXmlParser(); + String encoded = jsonParser.encodeResourceToString(obs); + ourLog.info(encoded); + + String jsonString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.xml"), Charset.forName("UTF-8")); + + String expected = (jsonString); + String actual = (encoded.trim()); + + Diff d = new Diff(new StringReader(expected), new StringReader(actual)); + assertTrue(d.toString(), d.identical()); + + } + + @Test + public void testSimpleResourceEncodeWithCustomType() throws IOException, SAXException { + + FhirContext fhirCtx = new FhirContext(MyObservationWithExtensions.class); + String xmlString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.json"), Charset.forName("UTF-8")); + MyObservationWithExtensions obs = fhirCtx.newJsonParser().parseResource(MyObservationWithExtensions.class, xmlString); + + assertEquals(0, obs.getAllUndeclaredExtensions().size()); + assertEquals("aaaa", obs.getExtAtt().getContentType().getValue()); + assertEquals("str1", obs.getMoreExt().getStr1().getValue()); + assertEquals("2011-01-02", obs.getModExt().getValueAsString()); + + List undeclaredExtensions = obs.getContact().get(0).getName().getFamily().get(0).getUndeclaredExtensions(); + ExtensionDt undeclaredExtension = undeclaredExtensions.get(0); + assertEquals("http://hl7.org/fhir/Profile/iso-21090#qualifier", undeclaredExtension.getUrl().getValue()); + + fhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToWriter(obs, new OutputStreamWriter(System.out)); + + IParser jsonParser = fhirCtx.newXmlParser(); + String encoded = jsonParser.encodeResourceToString(obs); + ourLog.info(encoded); + + String jsonString = IOUtils.toString(JsonParser.class.getResourceAsStream("/example-patient-general.xml"), Charset.forName("UTF-8")); + + String expected = (jsonString); + String actual = (encoded.trim()); + + Diff d = new Diff(new StringReader(expected), new StringReader(actual)); + assertTrue(d.toString(), d.identical()); + + } + + @Test + public void testTagList() { + + //@formatter:off + String tagListStr = " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + TagList tagList = ourCtx.newXmlParser().parseTagList(tagListStr); + assertEquals(3, tagList.size()); + assertEquals("term0", tagList.get(0).getTerm()); + assertEquals("label0", tagList.get(0).getLabel()); + assertEquals("scheme0", tagList.get(0).getScheme()); + assertEquals("term1", tagList.get(1).getTerm()); + assertEquals("label1", tagList.get(1).getLabel()); + assertEquals(null, tagList.get(1).getScheme()); + assertEquals("term2", tagList.get(2).getTerm()); + assertEquals("label2", tagList.get(2).getLabel()); + assertEquals(null, tagList.get(2).getScheme()); + + /* + * Encode + */ + + //@formatter:off + String expected = "" + + "" + + "" + + "" + + ""; + //@formatter:on + + String encoded = ourCtx.newXmlParser().encodeTagListToString(tagList); + assertEquals(expected, encoded); + + } + + @Test + public void testTotalResultsUsingOldNamespace() { + + //@formatter:off + String bundle = "\n" + + " Search results for Patient\n" + + " urn:uuid:374f2876-0da7-4441-87da-526e2fc624f8\n" + + " 15\n" + + " 2014-05-04T13:19:47.027-04:00\n" + + " \n" + + " AEGIS Wildfhir Server\n" + + " " + + ""; + //@formatter:off + + Bundle bundleR = ourCtx.newXmlParser().parseBundle(bundle); + assertEquals(15, bundleR.getTotalResults().getValue().intValue()); + } + + @BeforeClass + public static void beforeClass() { + XMLUnit.setIgnoreAttributeOrder(true); + XMLUnit.setIgnoreComments(true); + XMLUnit.setIgnoreWhitespace(true); + ourCtx = new FhirContext(); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BasicAuthInterceptorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BasicAuthInterceptorTest.java new file mode 100644 index 00000000000..73efe686a28 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BasicAuthInterceptorTest.java @@ -0,0 +1,87 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.StringReader; +import java.nio.charset.Charset; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; +import ca.uhn.fhir.rest.server.Constants; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class BasicAuthInterceptorTest { + + private static FhirContext ourCtx; + private HttpClient myHttpClient; + private HttpResponse myHttpResponse; + + @Before + public void before() { + myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient); + + myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + private String crerateMsg() { + //@formatter:off + String msg = "" + + "
John Cardinal: 444333333
" + + "" + + "" + + "" + + "" + + "" + + "
" + + "
"; + //@formatter:on + return msg; + } + + @Test + public void testRequest() throws Exception { + String msg = crerateMsg(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + Header[] headers = new Header[] {}; + + when(myHttpResponse.getAllHeaders()).thenReturn(headers); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo"); + client.registerInterceptor(new BasicAuthInterceptor("myuser", "mypass")); + client.getPatientById(new IdDt("111")); + + HttpUriRequest req = capt.getValue(); + assertEquals("Basic bXl1c2VyOm15cGFzcw==", req.getFirstHeader("Authorization").getValue()); + } + + @BeforeClass + public static void beforeClass() { + ourCtx = new FhirContext(); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BearerTokenAuthInterceptorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BearerTokenAuthInterceptorTest.java new file mode 100644 index 00000000000..f6a60526fed --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BearerTokenAuthInterceptorTest.java @@ -0,0 +1,87 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.StringReader; +import java.nio.charset.Charset; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor; +import ca.uhn.fhir.rest.server.Constants; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class BearerTokenAuthInterceptorTest { + + private static FhirContext ourCtx; + private HttpClient myHttpClient; + private HttpResponse myHttpResponse; + + @Before + public void before() { + myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient); + + myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + private String crerateMsg() { + //@formatter:off + String msg = "" + + "
John Cardinal: 444333333
" + + "" + + "" + + "" + + "" + + "" + + "
" + + "
"; + //@formatter:on + return msg; + } + + @Test + public void testRequest() throws Exception { + String msg = crerateMsg(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + Header[] headers = new Header[] {}; + + when(myHttpResponse.getAllHeaders()).thenReturn(headers); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ourCtx.newRestfulClient(ITestClient.class, "http://foo"); + client.registerInterceptor(new BearerTokenAuthInterceptor("mytoken")); + client.getPatientById(new IdDt("111")); + + HttpUriRequest req = capt.getValue(); + assertEquals("Bearer mytoken", req.getFirstHeader("Authorization").getValue()); + } + + @BeforeClass + public static void beforeClass() { + ourCtx = new FhirContext(); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java new file mode 100644 index 00000000000..20853b60e4c --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/BinaryClientTest.java @@ -0,0 +1,113 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.ByteArrayInputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.resource.Binary; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.server.Constants; + +public class BinaryClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + // atom-document-large.xml + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + @Test + public void testRead() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", "foo/bar")); + when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {1,2,3,4})); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + Binary resp = client.read(new IdDt("http://foo/Patient/123")); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Binary/123", get.getURI().toString()); + + assertEquals("foo/bar", resp.getContentType()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, resp.getContent()); + } + + @Test + public void testCreate() throws Exception { + Binary res = new Binary(); + res.setContent(new byte[] { 1, 2, 3, 4 }); + res.setContentType("text/plain"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML)); + when(httpResponse.getEntity().getContent()).thenReturn(new ByteArrayInputStream(new byte[] {})); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + MethodOutcome resp = client.create(res); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/Binary", post.getURI().toString()); + + assertEquals("text/plain", post.getEntity().getContentType().getValue()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, IOUtils.toByteArray(post.getEntity().getContent())); + + } + + + private String createBundle() { + return ctx.newXmlParser().encodeBundleToString(new Bundle()); + } + + + private interface IClient extends IBasicClient { + + @Read(type=Binary.class) + public Binary read(@IdParam IdDt theBinary); + + @Create(type=Binary.class) + public MethodOutcome create(@ResourceParam Binary theBinary); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientIntegrationTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientIntegrationTest.java new file mode 100644 index 00000000000..48cc25202ed --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientIntegrationTest.java @@ -0,0 +1,117 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.List; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.lang3.Validate; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.util.PortUtil; + +public class ClientIntegrationTest { + + private int myPort; + private Server myServer; + private MyPatientResourceProvider myPatientProvider; + + @Before + public void before() { + myPort = PortUtil.findFreePort(); + myServer = new Server(myPort); + + myPatientProvider = new MyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(myPatientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + myServer.setHandler(proxyHandler); + + } + + @Test + public void testClientSecurity() throws Exception { + + myServer.start(); + + FhirContext ctx = new FhirContext(); + + HttpClientBuilder builder = HttpClientBuilder.create(); + // PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + // builder.setConnectionManager(connectionManager); + builder.addInterceptorFirst(new HttpBasicAuthInterceptor("foobar", "boobear")); + + CloseableHttpClient httpClient = builder.build(); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + PatientClient client = ctx.newRestfulClient(PatientClient.class, "http://localhost:" + myPort + "/"); + + List actualPatients = client.searchForPatients(new StringDt("AAAABBBB")); + assertEquals(1, actualPatients.size()); + assertEquals("AAAABBBB", actualPatients.get(0).getNameFirstRep().getFamilyAsSingleString()); + + assertEquals("Basic Zm9vYmFyOmJvb2JlYXI=", myPatientProvider.getAuthorizationHeader()); + } + + @After + public void after() throws Exception { + myServer.stop(); + } + + public static class MyPatientResourceProvider implements IResourceProvider { + private String myAuthorizationHeader; + + public String getAuthorizationHeader() { + return myAuthorizationHeader; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Search + public List searchForPatients(@RequiredParam(name = "fooParam") StringDt theFooParam, HttpServletRequest theRequest, HttpServletResponse theResponse) { + Validate.notNull(theRequest); + Validate.notNull(theResponse); + + myAuthorizationHeader = theRequest.getHeader("authorization"); + + Patient retVal = new Patient(); + retVal.setId("1"); + retVal.addName().addFamily(theFooParam.getValue()); + return Collections.singletonList(retVal); + } + + } + + private static interface PatientClient extends IBasicClient { + + @Search + public List searchForPatients(@RequiredParam(name = "fooParam") StringDt theFooParam); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java new file mode 100644 index 00000000000..9e0c8e06914 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ClientTest.java @@ -0,0 +1,1206 @@ +package ca.uhn.fhir.rest.client; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +import java.io.InputStream; +import java.io.StringReader; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.Date; +import java.util.List; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.hamcrest.core.StringContains; +import org.hamcrest.core.StringEndsWith; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.api.annotation.ResourceDef; +import ca.uhn.fhir.model.base.resource.BaseConformance; +import ca.uhn.fhir.model.dstu.composite.CodingDt; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.IncludeParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor; +import ca.uhn.fhir.rest.param.CompositeParam; +import ca.uhn.fhir.rest.param.DateParam; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.QuantityParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; +import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.EncodingEnum; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException; + +public class ClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + // atom-document-large.xml + + private String getPatientFeedWithOneResult() { + //@formatter:off + String msg = "\n" + + "\n" + + "<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" + + "<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" + + "<published>2014-03-11T16:35:07-04:00</published>\n" + + "<author>\n" + + "<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" + + "</author>\n" + + "<entry>\n" + + "<content type=\"text/xml\">" + + "<Patient xmlns=\"http://hl7.org/fhir\">" + + "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>" + + "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>" + + "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>" + + "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>" + + "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>" + + "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>" + + "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />" + + "</Patient>" + + "</content>\n" + + " </entry>\n" + + "</feed>"; + //@formatter:on + return msg; + } + + @Test + public void testCreate() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier("urn:foo", "123"); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + CapturingInterceptor interceptor = new CapturingInterceptor(); + client.registerInterceptor(interceptor); + + MethodOutcome response = client.createPatient(patient); + + assertEquals(interceptor.getLastRequest().getURI().toASCIIString(), "http://foo/Patient"); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString("<Patient")); + assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue()); + assertEquals("200", response.getId().getVersionIdPart()); + } + + @Test + public void testCreateBad() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier("urn:foo", "123"); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 400, "foobar")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("foobar"), Charset.forName("UTF-8"))); + + try { + ctx.newRestfulClient(ITestClient.class, "http://foo").createPatient(patient); + fail(); + } catch (InvalidRequestException e) { + assertThat(e.getMessage(), StringContains.containsString("foobar")); + } + } + + /** + * Some servers (older ones?) return the resourcde you created instead of an OperationOutcome. We just need to + * ignore it. + */ + @Test + public void testCreateWithResourceResponse() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier("urn:foo", "123"); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ctx.newXmlParser().encodeResourceToString(patient)), Charset.forName("UTF-8"))); + when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + MethodOutcome response = client.createPatient(patient); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString("<Patient")); + assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue()); + assertEquals("200", response.getId().getVersionIdPart()); + } + + @Test + public void testCreateWithTagList() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier("urn:foo", "123"); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + TagList tagList = new TagList(); + tagList.add(new Tag((String) null, "Dog", "DogLabel")); + tagList.add(new Tag("http://cats", "Cat", "CatLabel")); + patient.getResourceMetadata().put(ResourceMetadataKeyEnum.TAG_LIST, tagList); + + MethodOutcome response = client.createPatient(patient); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString("<Patient")); + assertEquals("http://example.com/fhir/Patient/100/_history/200", response.getId().getValue()); + assertEquals("200", response.getId().getVersionIdPart()); + + Header[] headers = post.getHeaders("Category"); + assertEquals(2, headers.length); + assertEquals("Dog; label=\"DogLabel\"", headers[0].getValue()); + assertEquals("Cat; label=\"CatLabel\"; scheme=\"http://cats\"", headers[1].getValue()); + + } + + @Test + public void testDelete() throws Exception { + + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDetails("Hello"); + String resp = new FhirContext().newXmlParser().encodeResourceToString(oo); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(resp), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + MethodOutcome response = client.deletePatient(new IdDt("1234")); + + assertEquals(HttpDelete.class, capt.getValue().getClass()); + assertEquals("http://foo/Patient/1234", capt.getValue().getURI().toString()); + assertEquals("Hello", response.getOperationOutcome().getIssueFirstRep().getDetailsElement().getValue()); + } + + @Test + public void testDeleteNoResponse() throws Exception { + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 204, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + client.deleteDiagnosticReport(new IdDt("1234")); + + assertEquals(HttpDelete.class, capt.getValue().getClass()); + assertEquals("http://foo/DiagnosticReport/1234", capt.getValue().getURI().toString()); + } + + @Test + public void testGetConformance() throws Exception { + + String msg = IOUtils.toString(ClientTest.class.getResourceAsStream("/example-metadata.xml")); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + BaseConformance response = client.getServerConformanceStatement(); + + assertEquals("http://foo/metadata", capt.getValue().getURI().toString()); + assertEquals("Health Intersections", response.getPublisherElement().getValue()); + + } + + @Test + public void testHistoryResourceInstance() throws Exception { + + InstantDt date1 = new InstantDt(new Date(20000L)); + InstantDt date2 = new InstantDt(new Date(10000L)); + InstantDt date3 = new InstantDt(new Date(30000L)); + InstantDt date4 = new InstantDt(new Date(10000L)); + + //@formatter:off + String msg = "<feed xmlns=\"http://www.w3.org/2005/Atom\"><title/><id>6c1d93be-027f-468d-9d47-f826cd15cf42</id>" + + "<link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/>" + + "<link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>" + + "<published>2014-04-13T18:24:50-04:00</published>" + + "<author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author>" + + "<entry><title>Patient 222222" + + ""+date1.getValueAsString()+"" + + ""+date2.getValueAsString()+"" + + "" + + "" + + "" + + "Patient 222222" + + ""+date3.getValueAsString()+"" + + ""+date4.getValueAsString()+"" + + ""; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + Bundle response = client.getHistoryPatientInstance(new IdDt("111")); + + assertEquals("http://foo/Patient/111/_history", capt.getValue().getURI().toString()); + + assertEquals(2, response.getEntries().size()); + + // Older resource + { + BundleEntry olderEntry = response.getEntries().get(0); + assertEquals("222", olderEntry.getId().getValue()); + assertThat(olderEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/222/_history/1")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = olderEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(20000L)); + InstantDt updActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = olderEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + // Newer resource + { + BundleEntry newerEntry = response.getEntries().get(1); + assertEquals("222", newerEntry.getId().getValue()); + assertThat(newerEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/222/_history/2")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = newerEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(30000L)); + InstantDt updActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = newerEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + } + + @Test + public void testHistoryResourceType() throws Exception { + + InstantDt date1 = new InstantDt(new Date(20000L)); + InstantDt date2 = new InstantDt(new Date(10000L)); + InstantDt date3 = new InstantDt(new Date(30000L)); + InstantDt date4 = new InstantDt(new Date(10000L)); + + //@formatter:off + String msg = "<id>6c1d93be-027f-468d-9d47-f826cd15cf42</id>" + + "<link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/>" + + "<link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>" + + "<published>2014-04-13T18:24:50-04:00</published>" + + "<author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author>" + + "<entry><title>Patient 222222" + + ""+date1.getValueAsString()+"" + + ""+date2.getValueAsString()+"" + + "" + + "" + + "" + + "Patient 222222" + + ""+date3.getValueAsString()+"" + + ""+date4.getValueAsString()+"" + + ""; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + Bundle response = client.getHistoryPatientType(); + + assertEquals("http://foo/Patient/_history", capt.getValue().getURI().toString()); + + assertEquals(2, response.getEntries().size()); + + // Older resource + { + BundleEntry olderEntry = response.getEntries().get(0); + assertEquals("222", olderEntry.getId().getValue()); + assertThat(olderEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/222/_history/1")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = olderEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(20000L)); + InstantDt updActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = olderEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + // Newer resource + { + BundleEntry newerEntry = response.getEntries().get(1); + assertEquals("222", newerEntry.getId().getValue()); + assertThat(newerEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/222/_history/2")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = newerEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(30000L)); + InstantDt updActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = newerEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + } + + @Test + public void testHistoryServer() throws Exception { + InstantDt date1 = new InstantDt(new Date(20000L)); + InstantDt date2 = new InstantDt(new Date(10000L)); + InstantDt date3 = new InstantDt(new Date(30000L)); + InstantDt date4 = new InstantDt(new Date(10000L)); + + //@formatter:off + String msg = "<id>6c1d93be-027f-468d-9d47-f826cd15cf42</id>" + + "<link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/>" + + "<link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>" + + "<published>2014-04-13T18:24:50-04:00</published>" + + "<author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author>" + + "<entry><title>Patient 222222" + + ""+date1.getValueAsString()+"" + + ""+date2.getValueAsString()+"" + + "" + + "" + + "" + + "Patient 222222" + + ""+date3.getValueAsString()+"" + + ""+date4.getValueAsString()+"" + + ""; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + Bundle response = client.getHistoryServer(); + + assertEquals("http://foo/_history", capt.getValue().getURI().toString()); + + assertEquals(2, response.getEntries().size()); + + // Older resource + { + BundleEntry olderEntry = response.getEntries().get(0); + assertEquals("222", olderEntry.getId().getValue()); + assertThat(olderEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/222/_history/1")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = olderEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(20000L)); + InstantDt updActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = olderEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + // Newer resource + { + BundleEntry newerEntry = response.getEntries().get(1); + assertEquals("222", newerEntry.getId().getValue()); + assertThat(newerEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/222/_history/2")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = newerEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(30000L)); + InstantDt updActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = newerEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + } + + @Test + public void testHistoryWithParams() throws Exception { + + //@formatter:off + final String msg = "<id>6c1d93be-027f-468d-9d47-f826cd15cf42</id><link rel=\"self\" href=\"http://localhost:51698/Patient/222/_history\"/><link rel=\"fhir-base\" href=\"http://localhost:51698\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults><published>2014-04-13T18:24:50-04:00</published><author><name>ca.uhn.fhir.rest.method.HistoryMethodBinding</name></author><entry><title>Patient 2222221969-12-31T19:00:20.000-05:001969-12-31T19:00:10.000-05:00Patient 2222221969-12-31T19:00:30.000-05:001969-12-31T19:00:10.000-05:00"; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenAnswer(new Answer() { + @Override + public InputStream answer(InvocationOnMock theInvocation) throws Throwable { + return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")); + } + }); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + + client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T00:01:02"), new IntegerDt(12)); + assertThat(capt.getAllValues().get(0).getURI().toString(), containsString("http://foo/Patient/111/_history?")); + assertThat(capt.getAllValues().get(0).getURI().toString(), containsString("_since=2012-01-02T00%3A01%3A02")); + assertThat(capt.getAllValues().get(0).getURI().toString(), containsString("_count=12")); + + String expectedDateString = new InstantDt(new InstantDt("2012-01-02T00:01:02").getValue()).getValueAsString(); // ensures + // the + // local + // timezone + expectedDateString = expectedDateString.replace(":", "%3A"); + client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T00:01:02").getValue(), new IntegerDt(12).getValue()); + assertThat(capt.getAllValues().get(1).getURI().toString(), containsString("http://foo/Patient/111/_history?")); + assertThat(capt.getAllValues().get(1).getURI().toString(), containsString("_since="+expectedDateString)); + assertThat(capt.getAllValues().get(1).getURI().toString(), containsString("_count=12")); + + client.getHistoryPatientInstance(new IdDt("111"), null, new IntegerDt(12)); + assertEquals("http://foo/Patient/111/_history?_count=12", capt.getAllValues().get(2).getURI().toString()); + + client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T00:01:02"), null); + assertEquals("http://foo/Patient/111/_history?_since=2012-01-02T00%3A01%3A02", capt.getAllValues().get(3).getURI().toString()); + + client.getHistoryPatientInstance(new IdDt("111"), new InstantDt(), new IntegerDt(12)); + assertEquals("http://foo/Patient/111/_history?_count=12", capt.getAllValues().get(4).getURI().toString()); + + client.getHistoryPatientInstance(new IdDt("111"), new InstantDt("2012-01-02T00:01:02"), new IntegerDt()); + assertEquals("http://foo/Patient/111/_history?_since=2012-01-02T00%3A01%3A02", capt.getAllValues().get(5).getURI().toString()); + + } + + @Test + public void testNonAnnotatedMethodFailsGracefully() { + + // TODO: remove the read annotation and make sure we get a sensible + // error message to tell the user why the method isn't working + ClientWithoutAnnotation client = new FhirContext().newRestfulClient(ClientWithoutAnnotation.class, "http://wildfhir.aegis.net/fhir"); + + try { + client.read(new IdDt("8")); + fail(); + } catch (UnsupportedOperationException e) { + assertThat(e.getMessage(), containsString("annotation")); + } + + } + + @Test + public void testRead() throws Exception { + + //@formatter:off + String msg = "" + + "
John Cardinal: 444333333
" + + "" + + "" + + "" + + "" + + "" + + "
" + + "
"; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), + new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") }; + + when(httpResponse.getAllHeaders()).thenReturn(headers); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + // Patient response = client.findPatientByMrn(new + // IdentifierDt("urn:foo", "123")); + Patient response = client.getPatientById(new IdDt("111")); + + assertEquals("http://foo/Patient/111", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue()); + + assertEquals("http://foo.com/Patient/123/_history/2333", response.getId().getValue()); + + InstantDt lm = (InstantDt) response.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + lm.setTimeZoneZulu(true); + assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString()); + + TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(response); + assertNotNull(tags); + assertEquals(1, tags.size()); + assertEquals("http://foo/tagdefinition.html", tags.get(0).getTerm()); + assertEquals("http://hl7.org/fhir/tag", tags.get(0).getScheme()); + assertEquals("Some tag", tags.get(0).getLabel()); + + } + + @Test + public void testReadFailureInternalError() throws Exception { + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "INTERNAL")); + Header[] headers = new Header[1]; + headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "2011-01-02T22:01:02"); + when(httpResponse.getAllHeaders()).thenReturn(headers); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT)); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Internal Failure"), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + try { + client.getPatientById(new IdDt("111")); + fail(); + } catch (InternalErrorException e) { + assertThat(e.getMessage(), containsString("INTERNAL")); + assertThat(e.getResponseBody(), containsString("Internal Failure")); + } + + } + + @Test + public void testReadFailureNoCharset() throws Exception { + + //@formatter:off + String msg = ""; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 404, "NOT FOUND")); + Header[] headers = new Header[1]; + headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "2011-01-02T22:01:02"); + when(httpResponse.getAllHeaders()).thenReturn(headers); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML)); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + try { + client.getPatientById(new IdDt("111")); + fail(); + } catch (ResourceNotFoundException e) { + // good + } + + } + + @Test + public void testReadNoCharset() throws Exception { + + //@formatter:off + String msg = "" + + "
John Cardinal: 444333333
" + + "" + + "" + + "" + + "" + + "" + + "
" + + "
"; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + Header[] headers = new Header[1]; + headers[0] = new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"); + when(httpResponse.getAllHeaders()).thenReturn(headers); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML)); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + // Patient response = client.findPatientByMrn(new + // IdentifierDt("urn:foo", "123")); + Patient response = client.getPatientById(new IdDt("111")); + + assertEquals("http://foo/Patient/111", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue()); + + InstantDt lm = (InstantDt) response.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + lm.setTimeZoneZulu(true); + assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString()); + + } + + @Test + public void testSearchByDateRange() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + DateRangeParam param = new DateRangeParam(); + param.setLowerBound(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-01")); + param.setUpperBound(new DateParam(QuantityCompararatorEnum.LESSTHAN_OR_EQUALS, "2021-01-01")); + client.getPatientByDateRange(param); + + assertEquals("http://foo/Patient?dateRange=%3E%3D2011-01-01&dateRange=%3C%3D2021-01-01", capt.getValue().getURI().toString()); + + } + + @Test + public void testSearchByDob() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + // httpResponse = new BasicHttpResponse(statusline, catalog, locale) + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + List response = client.getPatientByDob(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + + assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.get(0).getIdentifier().get(0).getValue().getValue()); + + } + + @Test + public void testSearchByCompartment() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + List response = client.getPatientByCompartmentAndDob(new IdDt("123"), new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + + assertEquals("http://foo/Patient/123/compartmentName?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.get(0).getIdentifier().get(0).getValue().getValue()); + + try { + client.getPatientByCompartmentAndDob(new IdDt(""), new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + fail(); + } catch (InvalidRequestException e) { + assertThat(e.toString(), containsString("null or empty for compartment")); + } + + } + + @Test + public void testSearchByQuantity() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + Patient response = client.findPatientQuantity(new QuantityParam(QuantityCompararatorEnum.GREATERTHAN, 123L, "foo", "bar")); + + assertEquals("http://foo/Patient?quantityParam=%3E123%7Cfoo%7Cbar", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue()); + + } + + @Test + public void testSearchByToken() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + Patient response = client.findPatientByMrn(new TokenParam("urn:foo", "123")); + + assertEquals("http://foo/Patient?identifier=urn%3Afoo%7C123", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue()); + + } + + @Test + public void testSearchOrList() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + TokenOrListParam identifiers = new TokenOrListParam(); + identifiers.add(new CodingDt("foo", "bar")); + identifiers.add(new CodingDt("baz", "boz")); + client.getPatientMultipleIdentifiers(identifiers); + + assertEquals("http://foo/Patient?ids=foo%7Cbar%2Cbaz%7Cboz", capt.getValue().getURI().toString()); + + } + + @Test + public void testSearchNamedQueryNoParams() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + client.getPatientNoParams(); + + assertEquals("http://foo/Patient?_query=someQueryNoParams", capt.getValue().getURI().toString()); + + } + + @Test + public void testSearchNamedQueryOneParam() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + client.getPatientOneParam(new StringParam("BB")); + + assertEquals("http://foo/Patient?_query=someQueryOneParam¶m1=BB", capt.getValue().getURI().toString()); + + } + + @Test + public void testSearchWithCustomType() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClientWithCustomType client = ctx.newRestfulClient(ITestClientWithCustomType.class, "http://foo"); + CustomPatient response = client.getPatientByDob(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + + assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue()); + + } + + @Test + public void testSearchWithCustomTypeList() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClientWithCustomTypeList client = ctx.newRestfulClient(ITestClientWithCustomTypeList.class, "http://foo"); + List response = client.getPatientByDob(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + + assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.get(0).getIdentifier().get(0).getValue().getValue()); + + } + + @Test + public void testSearchWithFormatAndPrettyPrint() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + // TODO: document this + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + client.getPatientByDob(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02", capt.getAllValues().get(0).getURI().toString()); + + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + client.setEncoding(EncodingEnum.JSON); // this needs to be actually + // implemented + client.getPatientByDob(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02&_format=json", capt.getAllValues().get(1).getURI().toString()); + + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + client.setPrettyPrint(true); + client.getPatientByDob(new DateParam(QuantityCompararatorEnum.GREATERTHAN_OR_EQUALS, "2011-01-02")); + assertEquals("http://foo/Patient?birthdate=%3E%3D2011-01-02&_format=json&_pretty=true", capt.getAllValues().get(2).getURI().toString()); + + } + + @Test + public void testSearchWithIncludes() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + client.getPatientWithIncludes(new StringParam("aaa"), Arrays.asList(new Include[] { new Include("inc1"), new Include("inc2") })); + + assertEquals("http://foo/Patient?withIncludes=aaa&_include=inc1&_include=inc2", capt.getValue().getURI().toString()); + + } + + @Test + public void testSearchWithOptionalParam() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + Bundle response = client.findPatientByName(new StringParam("AAA"), null); + + assertEquals("http://foo/Patient?family=AAA", capt.getValue().getURI().toString()); + Patient resource = (Patient) response.getEntries().get(0).getResource(); + assertEquals("PRP1660", resource.getIdentifier().get(0).getValue().getValue()); + + /* + * Now with a first name + */ + + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + response = client.findPatientByName(new StringParam("AAA"), new StringParam("BBB")); + + assertEquals("http://foo/Patient?family=AAA&given=BBB", capt.getValue().getURI().toString()); + resource = (Patient) response.getEntries().get(0).getResource(); + assertEquals("PRP1660", resource.getIdentifier().get(0).getValue().getValue()); + + } + + @Test + public void testSearchByCompositeParam() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + StringParam str = new StringParam("FOO$BAR"); + DateParam date = new DateParam("2001-01-01"); + client.getObservationByNameValueDate(new CompositeParam(str, date)); + + assertEquals("http://foo/Observation?" + Observation.SP_NAME_VALUE_DATE + "=" + URLEncoder.encode("FOO\\$BAR$2001-01-01", "UTF-8"), capt.getValue().getURI().toString()); + + } + + @Test + public void testSearchWithStringIncludes() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClientWithStringIncludes client = ctx.newRestfulClient(ITestClientWithStringIncludes.class, "http://foo"); + client.getPatientWithIncludes(new StringParam("aaa"), "inc1"); + + assertEquals("http://foo/Patient?withIncludes=aaa&_include=inc1", capt.getValue().getURI().toString()); + + } + + @Test + public void testUpdate() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier("urn:foo", "123"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + MethodOutcome response = client.updatePatient(new IdDt("100"), patient); + + assertEquals(HttpPut.class, capt.getValue().getClass()); + HttpPut post = (HttpPut) capt.getValue(); + assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/100")); + assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString(" capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Content-Location", "http://example.com/fhir/Patient/100/_history/200")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + client.updatePatient(new IdDt("Patient/100/_history/200"), patient); + + assertEquals(HttpPut.class, capt.getValue().getClass()); + HttpPut post = (HttpPut) capt.getValue(); + assertEquals("http://foo/Patient/100", post.getURI().toASCIIString()); + + Header h = post.getFirstHeader("content-location"); + assertEquals("Patient/100/_history/200", h.getValue()); + + } + + @Test(expected = ResourceVersionConflictException.class) + public void testUpdateWithResourceConflict() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier("urn:foo", "123"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_409_CONFLICT, "Conflict")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + client.updatePatient(new IdDt("Patient/100/_history/200"), patient); + } + + @Test + public void testUpdateWithVersion() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier("urn:foo", "123"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + MethodOutcome response = client.updatePatient(new IdDt("Patient/100/_history/200"), patient); + + assertEquals(HttpPut.class, capt.getValue().getClass()); + HttpPut post = (HttpPut) capt.getValue(); + assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/100")); + assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString(" capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + when(httpResponse.getAllHeaders()).thenReturn(toHeaderArray("Location", "http://example.com/fhir/Patient/100/_history/200")); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + MethodOutcome response = client.validatePatient(patient); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertThat(post.getURI().toASCIIString(), StringEndsWith.endsWith("/Patient/_validate")); + assertThat(IOUtils.toString(post.getEntity().getContent()), StringContains.containsString("" + + "
John Cardinal: 444333333
" + + "" + + "" + + "" + + "" + + "" + + "
" + + "
"; + //@formatter:on + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + // Patient response = client.findPatientByMrn(new + // IdentifierDt("urn:foo", "123")); + Patient response = client.getPatientById(new IdDt("Patient/111/_history/999")); + + assertEquals("http://foo/Patient/111/_history/999", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.getIdentifier().get(0).getValue().getValue()); + + } + + private Header[] toHeaderArray(String theName, String theValue) { + return new Header[] { new BasicHeader(theName, theValue) }; + } + + private interface ClientWithoutAnnotation extends IBasicClient { + Patient read(@IdParam IdDt theId); + } + + @ResourceDef(name = "Patient") + public static class CustomPatient extends Patient { + // nothing + } + + public interface ITestClientWithCustomType extends IBasicClient { + @Search() + public CustomPatient getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate); + } + + public interface ITestClientWithCustomTypeList extends IBasicClient { + @Search() + public List getPatientByDob(@RequiredParam(name = Patient.SP_BIRTHDATE) DateParam theBirthDate); + } + + public interface ITestClientWithStringIncludes extends IBasicClient { + @Search() + public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam String theInclude); + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ExceptionHandlingTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ExceptionHandlingTest.java new file mode 100644 index 00000000000..7944b32b6ab --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ExceptionHandlingTest.java @@ -0,0 +1,185 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.nio.charset.Charset; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.hamcrest.core.StringContains; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.client.api.IRestfulClient; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; + +public class ExceptionHandlingTest { + + private static FhirContext myCtx; + private HttpClient myHttpClient; + private HttpResponse myHttpResponse; + + @BeforeClass + public static void beforeClass() { + myCtx = new FhirContext(); + } + + @Before + public void before() { + + myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + myCtx.getRestfulClientFactory().setHttpClient(myHttpClient); + + myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + @Test + public void testFail500WithPlainMessage() throws Exception { + String msg = "Help I'm a bug"; + String contentType = Constants.CT_TEXT; + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.read(Patient.class, new IdDt("Patient/1234")); + fail(); + } catch (InternalErrorException e) { + assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); + assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); + } + + } + + @Test + public void testFail500WithOperationOutcomeMessage() throws Exception { + OperationOutcome oo = new OperationOutcome(); + oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug"); + String msg = myCtx.newXmlParser().encodeResourceToString(oo); + String contentType = Constants.CT_FHIR_XML; + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.read(Patient.class, new IdDt("Patient/1234")); + fail(); + } catch (InternalErrorException e) { + assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); + assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); + } + + } + + @Test + public void testFail500WithUnexpectedResource() throws Exception { + Patient patient = new Patient(); + patient.addIdentifier().setSystem("foo").setValue("bar"); + String msg = myCtx.newXmlParser().encodeResourceToString(patient); + String contentType = Constants.CT_FHIR_XML; + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.read(Patient.class, new IdDt("Patient/1234")); + fail(); + } catch (InternalErrorException e) { + assertEquals("HTTP 500 Internal Error", e.getMessage()); + assertThat(e.getResponseBody(), StringContains.containsString("value=\"foo\"")); + } + + + } + + @Test + public void testFail500WithOperationOutcomeMessageJson() throws Exception { + OperationOutcome oo = new OperationOutcome(); + oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug"); + String msg = myCtx.newJsonParser().encodeResourceToString(oo); + String contentType = Constants.CT_FHIR_JSON; + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + try { + client.read(Patient.class, new IdDt("Patient/1234")); + fail(); + } catch (InternalErrorException e) { + assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); + assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); + assertNotNull(e.getOperationOutcome()); + assertEquals("Help I'm a bug",e.getOperationOutcome().getIssueFirstRep().getDetailsElement().getValue()); + } + + } + + @Test + public void testFail500WithOperationOutcomeMessageGeneric() throws Exception { + OperationOutcome oo = new OperationOutcome(); + oo.getIssueFirstRep().getDetails().setValue("Help I'm a bug"); + String msg = myCtx.newJsonParser().encodeResourceToString(oo); + String contentType = Constants.CT_FHIR_JSON; + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "Internal Error")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", contentType + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IMyClient client = myCtx.newRestfulClient(IMyClient.class,"http://example.com/fhir"); + try { + client.read(new IdDt("Patient/1234")); + fail(); + } catch (InternalErrorException e) { + assertThat(e.getMessage(), StringContains.containsString("HTTP 500 Internal Error")); + assertThat(e.getMessage(), StringContains.containsString("Help I'm a bug")); + assertNotNull(e.getOperationOutcome()); + assertEquals("Help I'm a bug",e.getOperationOutcome().getIssueFirstRep().getDetailsElement().getValue()); + } + + } + + public interface IMyClient extends IRestfulClient + { + @Read + Patient read(@IdParam IdDt theId); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java new file mode 100644 index 00000000000..e93b656375d --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/GenericClientTest.java @@ -0,0 +1,1014 @@ +package ca.uhn.fhir.rest.client; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.net.URLEncoder; +import java.nio.charset.Charset; +import java.util.Arrays; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.hamcrest.core.StringContains; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.resource.Encounter; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException; +import ca.uhn.fhir.rest.method.SearchStyleEnum; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.EncodingEnum; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; + +public class GenericClientTest { + + private static FhirContext myCtx; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClientTest.class); + private HttpClient myHttpClient; + + private HttpResponse myHttpResponse; + + @Before + public void before() { + + myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + myCtx.getRestfulClientFactory().setHttpClient(myHttpClient); + + myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + private String getPatientFeedWithOneResult() { + //@formatter:off + String msg = "\n" + + "\n" + + "<id>d039f91a-cc3c-4013-988e-af4d8d0614bd</id>\n" + + "<os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults>\n" + + "<published>2014-03-11T16:35:07-04:00</published>\n" + + "<author>\n" + + "<name>ca.uhn.fhir.rest.server.DummyRestfulServer</name>\n" + + "</author>\n" + + "<entry>\n" + + "<content type=\"text/xml\">" + + "<Patient xmlns=\"http://hl7.org/fhir\">" + + "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>" + + "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>" + + "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>" + + "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>" + + "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>" + + "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>" + + "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />" + + "</Patient>" + + "</content>\n" + + " </entry>\n" + + "</feed>"; + //@formatter:on + return msg; + } + + private String getResourceResult() { + //@formatter:off + String msg = + "<Patient xmlns=\"http://hl7.org/fhir\">" + + "<text><status value=\"generated\" /><div xmlns=\"http://www.w3.org/1999/xhtml\">John Cardinal: 444333333 </div></text>" + + "<identifier><label value=\"SSN\" /><system value=\"http://orionhealth.com/mrn\" /><value value=\"PRP1660\" /></identifier>" + + "<name><use value=\"official\" /><family value=\"Cardinal\" /><given value=\"John\" /></name>" + + "<name><family value=\"Kramer\" /><given value=\"Doe\" /></name>" + + "<telecom><system value=\"phone\" /><value value=\"555-555-2004\" /><use value=\"work\" /></telecom>" + + "<gender><coding><system value=\"http://hl7.org/fhir/v3/AdministrativeGender\" /><code value=\"M\" /></coding></gender>" + + "<address><use value=\"home\" /><line value=\"2222 Home Street\" /></address><active value=\"true\" />" + + "</Patient>"; + //@formatter:on + return msg; + } + + @Test + public void testSearchByCompartment() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + + IGenericClient client = myCtx.newRestfulGenericClient("http://foo"); + //@formatter:off + Bundle response = client + .search() + .forResource(Patient.class) + .withIdAndCompartment("123", "fooCompartment") + .where(Patient.BIRTHDATE.afterOrEquals().day("2011-01-02")) + .execute(); + //@formatter:on + + assertEquals("http://foo/Patient/123/fooCompartment?birthdate=%3E%3D2011-01-02", capt.getValue().getURI().toString()); + assertEquals("PRP1660", response.getResources(Patient.class).get(0).getIdentifier().get(0).getValue().getValue()); + + try { + //@formatter:off + client + .search() + .forResource(Patient.class) + .withIdAndCompartment("", "fooCompartment") + .where(Patient.BIRTHDATE.afterOrEquals().day("2011-01-02")) + .execute(); + //@formatter:on + fail(); + } catch (InvalidRequestException e) { + assertThat(e.toString(), containsString("null or empty for compartment")); + } + + } + + @Test + public void testCreateWithTag() throws Exception { + + Patient p1 = new Patient(); + p1.addIdentifier("foo:bar", "12345"); + p1.addName().addFamily("Smith").addGiven("John"); + TagList list = new TagList(); + list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource"); + ResourceMetadataKeyEnum.TAG_LIST.put(p1, list); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") }); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + MethodOutcome outcome = client.create().resource(p1).execute(); + assertEquals("44", outcome.getId().getIdPart()); + assertEquals("22", outcome.getId().getVersionIdPart()); + + assertEquals("http://example.com/fhir/Patient", capt.getValue().getURI().toString()); + assertEquals("POST", capt.getValue().getMethod()); + Header catH = capt.getValue().getFirstHeader("Category"); + assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH); + assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue()); + + /* + * Try fluent options + */ + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + client.create().resource(p1).withId("123").execute(); + assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(1).getURI().toString()); + + String resourceText = "<Patient xmlns=\"http://hl7.org/fhir\"> </Patient>"; + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + client.create().resource(resourceText).withId("123").execute(); + assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(2).getURI().toString()); + assertEquals(resourceText, IOUtils.toString(((HttpPost) capt.getAllValues().get(2)).getEntity().getContent())); + + } + + @Test + public void testCreateWithTagNonFluent() throws Exception { + + Patient p1 = new Patient(); + p1.addIdentifier("foo:bar", "12345"); + p1.addName().addFamily("Smith").addGiven("John"); + TagList list = new TagList(); + list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource"); + ResourceMetadataKeyEnum.TAG_LIST.put(p1, list); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") }); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + MethodOutcome outcome = client.create(p1); + assertEquals("44", outcome.getId().getIdPart()); + assertEquals("22", outcome.getId().getVersionIdPart()); + + assertEquals("http://example.com/fhir/Patient", capt.getValue().getURI().toString()); + assertEquals("POST", capt.getValue().getMethod()); + Header catH = capt.getValue().getFirstHeader("Category"); + assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH); + assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue()); + } + + @Test + public void testDelete() throws Exception { + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().addLocation().setValue("testDelete01"); + String ooStr = myCtx.newXmlParser().encodeResourceToString(oo); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") }); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ooStr), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + OperationOutcome outcome = (OperationOutcome) client.delete().resourceById("Patient", "123").execute(); + + assertEquals("http://example.com/fhir/Patient/123", capt.getValue().getURI().toString()); + assertEquals("DELETE", capt.getValue().getMethod()); + assertEquals("testDelete01", outcome.getIssueFirstRep().getLocationFirstRep().getValue()); + + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("LKJHLKJGLKJKLL"), Charset.forName("UTF-8"))); + outcome = (OperationOutcome) client.delete().resourceById(new IdDt("Location", "123", "456")).prettyPrint().encodedJson().execute(); + + assertEquals("http://example.com/fhir/Location/123?_format=json&_pretty=true", capt.getAllValues().get(1).getURI().toString()); + assertEquals("DELETE", capt.getValue().getMethod()); + assertEquals(null, outcome); + + } + + @Test + public void testGetTags() throws Exception { + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + String msg = myCtx.newXmlParser().encodeTagListToString(tagList); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + TagList response = client.getTags() + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/_tags", capt.getValue().getURI().toString()); + assertEquals(1, response.size()); + assertEquals("CCC", response.get(0).getScheme()); + + // Now for patient + + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + //@formatter:off + response = client.getTags().forResource(Patient.class) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient/_tags", capt.getValue().getURI().toString()); + assertEquals(1, response.size()); + assertEquals("CCC", response.get(0).getScheme()); + + } + + @Test + public void testRead() throws Exception { + + String msg = getResourceResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), + new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), + new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") }; + when(myHttpResponse.getAllHeaders()).thenReturn(headers); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Patient response = client.read(Patient.class, new IdDt("Patient/1234")); + //@formatter:on + + assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal")); + + assertEquals("http://foo.com/Patient/123/_history/2333", response.getId().getValue()); + + InstantDt lm = (InstantDt) response.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + lm.setTimeZoneZulu(true); + assertEquals("1995-11-15T04:58:08.000Z", lm.getValueAsString()); + + TagList tags = ResourceMetadataKeyEnum.TAG_LIST.get(response); + assertNotNull(tags); + assertEquals(1, tags.size()); + assertEquals("http://foo/tagdefinition.html", tags.get(0).getTerm()); + assertEquals("http://hl7.org/fhir/tag", tags.get(0).getScheme()); + assertEquals("Some tag", tags.get(0).getLabel()); + + } + + @Test + public void testReadWithAbsoluteUrl() throws Exception { + + String msg = getResourceResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), + new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), + new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") }; + when(myHttpResponse.getAllHeaders()).thenReturn(headers); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + Patient response = client.read(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234")); + assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal")); + assertEquals("http://somebase.com/path/to/base/Patient/1234", capt.getAllValues().get(0).getURI().toString()); + + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + response = client.read(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234/_history/2222")); + assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal")); + assertEquals("http://somebase.com/path/to/base/Patient/1234", capt.getAllValues().get(1).getURI().toString()); + + } + + @Test + public void testVReadWithAbsoluteUrl() throws Exception { + + String msg = getResourceResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), + new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"), + new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") }; + when(myHttpResponse.getAllHeaders()).thenReturn(headers); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + Patient response = client.vread(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234/_history/2222")); + assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal")); + assertEquals("http://somebase.com/path/to/base/Patient/1234/_history/2222", capt.getAllValues().get(0).getURI().toString()); + + try { + client.vread(Patient.class, new IdDt("http://somebase.com/path/to/base/Patient/1234")); + fail(); + } catch (IllegalArgumentException e) { + assertThat(e.getMessage(), containsString("No version specified in URL")); + } + + } + + @SuppressWarnings("unused") + @Test + public void testSearchAllResources() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forAllResources() + .where(Patient.NAME.matches().value("james")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/?name=james", capt.getValue().getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByComposite() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://foo"); + + //@formatter:off + Bundle response = client.search() + .forResource("Observation") + .where(Observation.NAME_VALUE_DATE + .withLeft(Observation.NAME.exactly().code("FOO$BAR")) + .withRight(Observation.VALUE_DATE.exactly().day("2001-01-01")) + ) + .execute(); + //@formatter:on + + assertEquals("http://foo/Observation?" + Observation.SP_NAME_VALUE_DATE + "=" + URLEncoder.encode("FOO\\$BAR$2001-01-01", "UTF-8"), capt.getValue().getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchWithClientEncodingAndPrettyPrintConfig() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + GenericClient client = (GenericClient) myCtx.newRestfulGenericClient("http://example.com/fhir"); + client.setPrettyPrint(true); + client.setEncoding(EncodingEnum.JSON); + + //@formatter:off + Bundle response = client.search() + .forResource(Patient.class) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?_format=json&_pretty=true", capt.getValue().getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByDate() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource(Patient.class) + .encodedJson() + .where(Patient.BIRTHDATE.beforeOrEquals().day("2012-01-22")) + .and(Patient.BIRTHDATE.after().day("2011-01-01")) + .include(Patient.INCLUDE_MANAGINGORGANIZATION) + .sort().ascending(Patient.BIRTHDATE) + .sort().descending(Patient.NAME) + .limitTo(123) + .execute(); + //@formatter:on + + assertEquals( + "http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json", + capt.getValue().getURI().toString()); + + } + + + @Test + public void testSearchWithAbsoluteUrl() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + Bundle response = client.search(new UriDt("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json")); + + assertEquals( + "http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json", + capt.getValue().getURI().toString()); + + assertEquals(1, response.size()); + } + + + @Test + public void testSearchWithAbsoluteUrlAndType() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + Bundle response = client.search(Patient.class, new UriDt("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json")); + + assertEquals( + "http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json", + capt.getValue().getURI().toString()); + + assertEquals(1, response.size()); + } + + @SuppressWarnings("unused") + @Test + public void testSearchByNumberExact() throws Exception { + + String msg = new FhirContext().newXmlParser().encodeBundleToString(new Bundle()); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource(Observation.class) + .where(Observation.VALUE_QUANTITY.greaterThan().number(123).andUnits("foo", "bar")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Observation?value-quantity=%3E123%7Cfoo%7Cbar", capt.getValue().getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByQuantity() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource(Patient.class) + .where(Encounter.LENGTH.exactly().number(123)) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?length=123", capt.getValue().getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByReferenceProperty() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + //@formatter:off + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + Bundle response = client.search() + .forResource(Patient.class) + .where(Patient.PROVIDER.hasChainedProperty(Organization.NAME.matches().value("ORG0"))) + .execute(); + + assertEquals("http://example.com/fhir/Patient?provider.name=ORG0", capt.getValue().getURI().toString()); + //@formatter:on + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByReferenceSimple() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.PROVIDER.hasId("123")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?provider=123", capt.getValue().getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByString() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?name=james", capt.getValue().getURI().toString()); + + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + //@formatter:off + response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().values("AAA", "BBB", "C,C")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?name=" + URLEncoder.encode("AAA,BBB,C\\,C", "UTF-8"), capt.getAllValues().get(1).getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByStringExact() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matchesExactly().value("james")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?name%3Aexact=james", capt.getValue().getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchByToken() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.IDENTIFIER.exactly().systemAndCode("http://example.com/fhir", "ZZZ")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?identifier=http%3A%2F%2Fexample.com%2Ffhir%7CZZZ", capt.getValue().getURI().toString()); + + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + //@formatter:off + response = client.search() + .forResource("Patient") + .where(Patient.IDENTIFIER.exactly().code("ZZZ")) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?identifier=ZZZ", capt.getAllValues().get(1).getURI().toString()); + + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + //@formatter:off + response = client.search() + .forResource("Patient") + .where(Patient.IDENTIFIER.exactly().identifiers(new ca.uhn.fhir.model.dstu.composite.IdentifierDt("A", "B"), new ca.uhn.fhir.model.dstu.composite.IdentifierDt("C", "D"))) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient?identifier=" + URLEncoder.encode("A|B,C|D", "UTF-8"), capt.getAllValues().get(2).getURI().toString()); + + } + + @SuppressWarnings("unused") + @Test + public void testSearchUsingPost() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .usingStyle(SearchStyleEnum.POST) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient/_search", capt.getValue().getURI().toString()); + + HttpEntityEnclosingRequestBase enc = (HttpEntityEnclosingRequestBase) capt.getValue(); + UrlEncodedFormEntity ent = (UrlEncodedFormEntity) enc.getEntity(); + String string = IOUtils.toString(ent.getContent()); + ourLog.info(string); + assertEquals("name=james", string); + } + + @SuppressWarnings("unused") + @Test + public void testSearchAutomaticallyUsesPost() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + String longValue = StringUtils.leftPad("", 20000, 'B'); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value(longValue)) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient/_search", capt.getValue().getURI().toString()); + + HttpEntityEnclosingRequestBase enc = (HttpEntityEnclosingRequestBase) capt.getValue(); + UrlEncodedFormEntity ent = (UrlEncodedFormEntity) enc.getEntity(); + String string = IOUtils.toString(ent.getContent()); + ourLog.info(string); + assertEquals("name=" + longValue, string); + } + + @SuppressWarnings("unused") + @Test + public void testSearchUsingGetSearch() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.search() + .forResource("Patient") + .where(Patient.NAME.matches().value("james")) + .usingStyle(SearchStyleEnum.GET_WITH_SEARCH) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir/Patient/_search?name=james", capt.getValue().getURI().toString()); + } + + @SuppressWarnings("unused") + @Test + public void testSearchWithInternalServerError() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 500, "INTERNAL ERRORS")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.search().forResource(Patient.class).execute(); + fail(); + } catch (InternalErrorException e) { + assertEquals(e.getMessage(), "HTTP 500 INTERNAL ERRORS: Server Issues!"); + assertEquals(e.getResponseBody(), "Server Issues!"); + } + + } + + @SuppressWarnings("unused") + @Test + public void testSearchWithNonFhirResponse() throws Exception { + + String msg = getPatientFeedWithOneResult(); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_TEXT + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("Server Issues!"), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.search().forResource(Patient.class).execute(); + fail(); + } catch (NonFhirResponseException e) { + assertThat(e.getMessage(), StringContains.containsString("Server Issues!")); + } + + } + + @Test + public void testTransaction() throws Exception { + String bundleStr = IOUtils.toString(getClass().getResourceAsStream("/bundle.json")); + Bundle bundle = myCtx.newJsonParser().parseBundle(bundleStr); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(bundleStr), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.transaction() + .withBundle(bundle) + .execute(); + //@formatter:on + + assertEquals("http://example.com/fhir", capt.getValue().getURI().toString()); + assertEquals(bundle.getEntries().get(0).getId(), response.getEntries().get(0).getId()); + } + + @Test + public void testTransactionJson() throws Exception { + String bundleStr = IOUtils.toString(getClass().getResourceAsStream("/bundle.json")); + Bundle bundle = myCtx.newJsonParser().parseBundle(bundleStr); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(bundleStr), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + //@formatter:off + Bundle response = client.transaction() + .withBundle(bundle) + .encodedJson() + .execute(); + //@formatter:on + + HttpEntityEnclosingRequestBase value = (HttpEntityEnclosingRequestBase) capt.getValue(); + + Header ct = value.getEntity().getContentType(); + assertNotNull(ct); + assertEquals(Constants.CT_FHIR_JSON + "; charset=UTF-8", ct.getValue()); + + assertEquals("http://example.com/fhir?_format=json", value.getURI().toString()); + assertThat(IOUtils.toString(value.getEntity().getContent()), StringContains.containsString("\"resourceType\"")); + assertEquals(bundle.getEntries().get(0).getId(), response.getEntries().get(0).getId()); + } + + @Test + public void testUpdate() throws Exception { + + Patient p1 = new Patient(); + p1.addIdentifier("foo:bar", "12345"); + p1.addName().addFamily("Smith").addGiven("John"); + TagList list = new TagList(); + list.addTag("http://hl7.org/fhir/tag", "urn:happytag", "This is a happy resource"); + ResourceMetadataKeyEnum.TAG_LIST.put(p1, list); + + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse); + when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 201, "OK")); + when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { new BasicHeader(Constants.HEADER_LOCATION, "/Patient/44/_history/22") }); + when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir"); + + try { + client.update().resource(p1).execute(); + fail(); + } catch (InvalidRequestException e) { + // should happen because no ID set + } + + assertEquals(0, capt.getAllValues().size()); + + p1.setId("44"); + client.update().resource(p1).execute(); + + assertEquals(1, capt.getAllValues().size()); + + MethodOutcome outcome = client.update().resource(p1).execute(); + assertEquals("44", outcome.getId().getIdPart()); + assertEquals("22", outcome.getId().getVersionIdPart()); + + assertEquals(2, capt.getAllValues().size()); + + assertEquals("http://example.com/fhir/Patient/44", capt.getValue().getURI().toString()); + assertEquals("PUT", capt.getValue().getMethod()); + Header catH = capt.getValue().getFirstHeader("Category"); + assertNotNull(Arrays.asList(capt.getValue().getAllHeaders()).toString(), catH); + assertEquals("urn:happytag; label=\"This is a happy resource\"; scheme=\"http://hl7.org/fhir/tag\"", catH.getValue()); + + /* + * Try fluent options + */ + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + client.update().resource(p1).withId("123").execute(); + assertEquals(3, capt.getAllValues().size()); + assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(2).getURI().toString()); + + String resourceText = "<Patient xmlns=\"http://hl7.org/fhir\"> </Patient>"; + when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + client.update().resource(resourceText).withId("123").execute(); + assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(3).getURI().toString()); + assertEquals(resourceText, IOUtils.toString(((HttpPut) capt.getAllValues().get(3)).getEntity().getContent())); + assertEquals(4, capt.getAllValues().size()); + + } + + @BeforeClass + public static void beforeClass() { + myCtx = new FhirContext(); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ITestClient.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ITestClient.java new file mode 100644 index 00000000000..2b674a7bd99 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ITestClient.java @@ -0,0 +1,107 @@ +package ca.uhn.fhir.rest.client; + +import java.util.Date; +import java.util.List; + +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.rest.annotation.Count; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.Delete; +import ca.uhn.fhir.rest.annotation.History; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.IncludeParam; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Since; +import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.annotation.Validate; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.param.CompositeParam; +import ca.uhn.fhir.rest.param.DateParam; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.QuantityParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; +import ca.uhn.fhir.rest.param.TokenParam; + +public interface ITestClient extends IBasicClient { + + @Create + public MethodOutcome createPatient(@ResourceParam Patient thePatient); + + @Search() + public List<Patient> getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers); + + @Search(type=Observation.class) + public Bundle getObservationByNameValueDate(@RequiredParam(name = Observation.SP_NAME_VALUE_DATE, compositeTypes= {StringParam.class,DateParam.class}) CompositeParam<StringParam, DateParam> theIdentifiers); + + @Search() + public List<Patient> getPatientByDob(@RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate); + + @Search() + public List<Patient> getPatientMultipleIdentifiers(@RequiredParam(name = "ids") TokenOrListParam theIdentifiers); + + @Search(queryName="someQueryNoParams") + public Patient getPatientNoParams(); + + @Search(queryName="someQueryOneParam") + public Patient getPatientOneParam(@RequiredParam(name="param1") StringParam theParam); + + @Search() + public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringParam theString, @IncludeParam List<Include> theIncludes); + + @Update + public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient); + + @Delete(type=DiagnosticReport.class) + void deleteDiagnosticReport(@IdParam IdDt theId); + + @Delete(type=Patient.class) + MethodOutcome deletePatient(@IdParam IdDt theId); + + @Search(type=Patient.class) + Patient findPatientByMrn(@RequiredParam(name = Patient.SP_IDENTIFIER) TokenParam theId); + + @Search(type=Patient.class) + Bundle findPatientByName(@RequiredParam(name = Patient.SP_FAMILY) StringParam theId, @OptionalParam(name=Patient.SP_GIVEN) StringParam theGiven); + + @History(type=Patient.class) + Bundle getHistoryPatientInstance(@IdParam IdDt theId); + + @History(type=Patient.class) + Bundle getHistoryPatientInstance(@IdParam IdDt theId, @Since InstantDt theSince, @Count IntegerDt theCount); + + @History(type=Patient.class) + Bundle getHistoryPatientInstance(@IdParam IdDt theId, @Since Date theSince, @Count Integer theCount); + + @History(type=Patient.class) + Bundle getHistoryPatientType(); + + @History + Bundle getHistoryServer(); + + @Read(type=Patient.class) + Patient getPatientById(@IdParam IdDt theId); + + @Validate(type=Patient.class) + MethodOutcome validatePatient(@ResourceParam Patient thePatient); + + @Search(type=Patient.class) + Patient findPatientQuantity(@RequiredParam(name="quantityParam") QuantityParam theQuantityDt); + + @Search(compartmentName="compartmentName") + public List<Patient> getPatientByCompartmentAndDob(@IdParam IdDt theIdDt, @RequiredParam(name=Patient.SP_BIRTHDATE) DateParam theBirthDate); + + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/IncludedResourceStitchingClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/IncludedResourceStitchingClientTest.java new file mode 100644 index 00000000000..a1a1ccc7056 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/IncludedResourceStitchingClientTest.java @@ -0,0 +1,249 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.List; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.ExtensionDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.server.Constants; +import ca.uhn.fhir.rest.server.IncludeTest; +import ca.uhn.fhir.rest.server.IncludeTest.ExtPatient; + +public class IncludedResourceStitchingClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + // atom-document-large.xml + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + @Test + public void testWithParam() throws Exception { + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IGenericClient client = ctx.newRestfulGenericClient( "http://foo"); + Bundle bundle = client.search().forResource("Patient").execute(); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient", get.getURI().toString()); + + assertEquals(3, bundle.size()); + + Patient p = (Patient) bundle.getEntries().get(0).getResource(); + List<ExtensionDt> exts = p.getUndeclaredExtensionsByUrl("http://foo"); + assertEquals(1,exts.size()); + ExtensionDt ext = exts.get(0); + ResourceReferenceDt ref = (ResourceReferenceDt) ext.getValue(); + assertEquals("Organization/o1", ref.getReference().getValue()); + assertNotNull(ref.getResource()); + + } + + + @Test + public void testWithDeclaredExtension() throws Exception { + ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createLinkedBundle()), Charset.forName("UTF-8"))); + + IGenericClient client = ctx.newRestfulGenericClient( "http://foo"); + Bundle bundle = client.search().forResource(IncludeTest.ExtPatient.class).execute(); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient", get.getURI().toString()); + + assertEquals(4, bundle.size()); + + ExtPatient p = (ExtPatient) bundle.getEntries().get(0).getResource(); + ResourceReferenceDt ref = (ResourceReferenceDt) p.getSecondOrg(); + assertEquals("Organization/o1", ref.getReference().getValue()); + assertNotNull(ref.getResource()); + + Organization o1 = (Organization) ref.getResource(); + assertEquals("o2", o1.getPartOf().getReference().toUnqualifiedVersionless().getIdPart()); + assertNotNull(o1.getPartOf().getResource()); + + } + + private String createLinkedBundle() { + //@formatter:off + return "<feed xmlns=\"http://www.w3.org/2005/Atom\">\n" + + " <title/>\n" + + " <id>6cfcd90e-877a-40c6-a11c-448006712979</id>\n" + + " <link rel=\"self\" href=\"http://localhost:49782/Patient?_query=declaredExtInclude&_pretty=true\"/>\n" + + " <link rel=\"fhir-base\" href=\"http://localhost:49782\"/>\n" + + " <os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>\n" + + " <published>2014-08-12T10:22:19.097-04:00</published>\n" + + " <author>\n" + + " <name>HAPI FHIR Server</name>\n" + + " </author>\n" + + " <entry>\n" + + " <title>Patient p1\n" + + " http://localhost:49782/Patient/p1\n" + + " 2014-08-12T10:22:19-04:00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Patient p2\n" + + " http://localhost:49782/Patient/p2\n" + + " 2014-08-12T10:22:19-04:00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Organization o1\n" + + " http://localhost:49782/Organization/o1\n" + + " 2014-08-12T10:22:19-04:00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Organization o2\n" + + " http://localhost:49782/Organization/o2\n" + + " 2014-08-12T10:22:19-04:00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + } + + + private String createBundle() { + //@formatter:on + return "\n" + + " \n" + + " <id>f051fd86-4daa-48da-80f7-5a0443bf6f11</id>\n" + + " <link rel=\"self\" href=\"http://localhost:49627/Patient?_query=extInclude&_pretty=true\"/>\n" + + " <link rel=\"fhir-base\" href=\"http://localhost:49627\"/>\n" + + " <os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">2</os:totalResults>\n" + + " <published>2014-08-05T15:22:08.512-04:00</published>\n" + + " <author>\n" + + " <name>HAPI FHIR Server</name>\n" + + " </author>\n" + + " <entry>\n" + + " <title>Patient p1\n" + + " http://localhost:49627/Patient/p1\n" + + " 2014-08-05T15:22:08-04:00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Patient p2\n" + + " http://localhost:49627/Patient/p2\n" + + " 2014-08-05T15:22:08-04:00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " Organization o1\n" + + " http://localhost:49627/Organization/o1\n" + + " 2014-08-05T15:22:08-04:00\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:off + + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/LoggingInterceptorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/LoggingInterceptorTest.java new file mode 100644 index 00000000000..56c652e9eb4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/LoggingInterceptorTest.java @@ -0,0 +1,121 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.assertFalse; +import static org.mockito.Matchers.argThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentMatcher; +import org.slf4j.LoggerFactory; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.util.PortUtil; +import ch.qos.logback.classic.Logger; +import ch.qos.logback.classic.spi.ILoggingEvent; +import ch.qos.logback.classic.spi.LoggingEvent; +import ch.qos.logback.core.Appender; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class LoggingInterceptorTest { + + private static int ourPort; + private static Server ourServer; + private static FhirContext ourCtx; + + private Appender myMockAppender; + private Logger myLoggerRoot; + + @SuppressWarnings("unchecked") + @Before + public void before() { + /* + * This is a bit funky, but it's useful for verifying that the headers actually get logged + */ + myLoggerRoot = (ch.qos.logback.classic.Logger) LoggerFactory.getLogger(ch.qos.logback.classic.Logger.ROOT_LOGGER_NAME); + myMockAppender = mock(Appender.class); + when(myMockAppender.getName()).thenReturn("MOCK"); + myLoggerRoot.addAppender(myMockAppender); + } + + @After + public void after() { + myLoggerRoot.detachAppender(myMockAppender); + } + + @Test + public void testLogger() throws Exception { + IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort); + client.registerInterceptor(new LoggingInterceptor(true)); + Patient patient = client.read(Patient.class, "1"); + assertFalse(patient.getIdentifierFirstRep().isEmpty()); + + verify(myMockAppender).doAppend(argThat(new ArgumentMatcher() { + @Override + public boolean matches(final Object argument) { + return ((LoggingEvent) argument).getFormattedMessage().contains("Content-Type: application/xml+fhir; charset=UTF-8"); + } + })); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyProvider patientProvider = new DummyProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + ourCtx = servlet.getFhirContext(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyProvider implements IResourceProvider { + + @Read(version = true) + public Patient findPatient(@IdParam IdDt theId) { + Patient patient = new Patient(); + patient.addIdentifier(theId.getIdPart(), theId.getVersionIdPart()); + patient.setId("Patient/1/_history/1"); + return patient; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ReferenceClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ReferenceClientTest.java new file mode 100644 index 00000000000..ed13ea8b021 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/ReferenceClientTest.java @@ -0,0 +1,127 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.List; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.param.ReferenceParam; +import ca.uhn.fhir.rest.server.Constants; + +public class ReferenceClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + // atom-document-large.xml + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + @Test + public void testWithParam() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.search(new ReferenceParam("123")); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?provider=123", get.getURI().toString()); + } + + @Test + public void testWithParamAndChain() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.search(new ReferenceParam("chain", "123")); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?provider.chain=123", get.getURI().toString()); + } + + @Test + public void testWithParamAndTypeAndChain() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.search(new ReferenceParam("Organization", "chain", "123")); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?provider%3AOrganization.chain=123", get.getURI().toString()); + } + + @Test + public void testWithParamAndType() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.search(new ReferenceParam("Organization", null, "123")); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?provider%3AOrganization=123", get.getURI().toString()); + } + + private String createBundle() { + return ctx.newXmlParser().encodeBundleToString(new Bundle()); + } + + + private interface IClient extends IBasicClient { + + @Search(type=Patient.class) + public List search(@RequiredParam(name=Patient.SP_PROVIDER) ReferenceParam theString); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SearchTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SearchTest.java new file mode 100644 index 00000000000..65c3736012e --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SearchTest.java @@ -0,0 +1,74 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.List; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Encounter; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.server.Constants; + +public class SearchTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + @Test + public void testReturnTypedList() throws Exception { + String retVal = "<id>bc59fca7-0a8f-4caf-abef-45c8d53ece6a</id><link rel=\"self\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter?identifier=urn%3Aoid%3A1.3.6.1.4.1.12201.2%7C11410000159&_include=Encounter.participant&_include=Encounter.location.location&_include=Encounter.subject\"/><link rel=\"fhir-base\" href=\"http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2\"/><os:totalResults xmlns:os=\"http://a9.com/-/spec/opensearch/1.1/\">1</os:totalResults><published>2014-08-08T14:46:16.497-04:00</published><author><name>HAPI FHIR Server</name></author><entry><title>Encounter 5994268http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Encounter/59942682014-08-05T12:00:11.000-04:002014-08-05T11:59:21.000-04:00
No narrative template available for resource profile: http://fhir.connectinggta.ca/Profile/encounter
Patient 5993715http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Patient/59937152014-08-08T14:46:16-04:00
Person CHA
IdentifierUHN MRN 7018614
Address100 Dundas street west
Toronto ON Can
Date of birth01 January 1988
Practitioner Practitioner/5738815http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Practitioner/57388152014-08-08T13:53:52.000-04:002009-12-04T13:43:11.000-05:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Practitioner
Location Location/5994269http://uhnvesb01d.uhn.on.ca:25180/uhn-fhir-service-1.2/Location/59942692014-08-08T14:46:16-04:00
No narrative template available for resource profile: http://hl7.org/fhir/profiles/Location
"; + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML+ "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(retVal), Charset.forName("UTF-8"))); + + ITestClient client = ctx.newRestfulClient(ITestClient.class, "http://foo"); + List found = client.search(); + assertEquals(1, found.size()); + + Encounter encounter = found.get(0); + assertNotNull(encounter.getSubject().getResource()); + + } + + + private interface ITestClient extends IBasicClient + { + + @Search + List search(); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SortClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SortClientTest.java new file mode 100644 index 00000000000..24f6203f62c --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/SortClientTest.java @@ -0,0 +1,100 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.List; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Sort; +import ca.uhn.fhir.rest.api.SortOrderEnum; +import ca.uhn.fhir.rest.api.SortSpec; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.Constants; + +public class SortClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + // atom-document-large.xml + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + + + @Test + public void testSort() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.searchWithParam(new StringParam("hello"), new SortSpec("given")); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?name=hello&_sort=given", get.getURI().toString()); + } + + @Test + public void testSortWithChain() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.searchWithParam(new StringParam("hello"), new SortSpec("given", SortOrderEnum.DESC, new SortSpec("family", SortOrderEnum.ASC))); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?name=hello&_sort%3Adesc=given&_sort%3Aasc=family", get.getURI().toString()); + } + + private String createBundle() { + return ctx.newXmlParser().encodeBundleToString(new Bundle()); + } + + + private interface IClient extends IBasicClient { + + @Search(type=Patient.class) + public List searchWithParam(@RequiredParam(name=Patient.SP_NAME) StringParam theString, @Sort SortSpec theSort); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/StringClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/StringClientTest.java new file mode 100644 index 00000000000..8d72253f381 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/StringClientTest.java @@ -0,0 +1,115 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.List; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.Constants; + +public class StringClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + // atom-document-large.xml + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + @Test + public void testWithParam() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.searchWithParam(new StringParam("hello")); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?withParam=hello", get.getURI().toString()); + } + + @Test + public void testWithoutParam() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.searchWithoutParam("hello"); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?withoutParam=hello", get.getURI().toString()); + } + + @Test + public void testWithParamExact() throws Exception { + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.searchWithParam(new StringParam("hello", true)); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient?withParam%3Aexact=hello", get.getURI().toString()); + } + + + private String createBundle() { + return ctx.newXmlParser().encodeBundleToString(new Bundle()); + } + + + private interface IClient extends IBasicClient { + + @Search(type=Patient.class) + public List searchWithParam(@RequiredParam(name="withParam") StringParam theString); + + @Search(type=Patient.class) + public List searchWithoutParam(@RequiredParam(name="withoutParam") String theString); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/TagsClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/TagsClientTest.java new file mode 100644 index 00000000000..a7c322cd567 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/TagsClientTest.java @@ -0,0 +1,292 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.StringReader; +import java.nio.charset.Charset; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HeaderElement; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.AddTags; +import ca.uhn.fhir.rest.annotation.DeleteTags; +import ca.uhn.fhir.rest.annotation.GetTags; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.TagListParam; +import ca.uhn.fhir.rest.annotation.VersionIdParam; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.server.Constants; + +public class TagsClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + // atom-document-large.xml + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + @Test + public void testGetAllTags() throws Exception { + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + String ser = ctx.newXmlParser().encodeTagListToString(tagList); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ser), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + TagList response = client.getAllTags(); + assertEquals(tagList, response); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/_tags", get.getURI().toString()); + } + + @Test + public void testGetAllTagsPatient() throws Exception { + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + String ser = ctx.newXmlParser().encodeTagListToString(tagList); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ser), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + TagList response = client.getAllTagsPatient(); + assertEquals(tagList, response); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient/_tags", get.getURI().toString()); + } + + @Test + public void testDeleteTagsPatient() throws Exception { + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType().getElements()).thenReturn(new HeaderElement[0]); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.deleteTags(new IdDt("111"), tagList); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/Patient/111/_tags/_delete", post.getURI().toString()); + + String ser = IOUtils.toString(post.getEntity().getContent()); + TagList actualTagList = ctx.newXmlParser().parseTagList(ser); + assertEquals(tagList, actualTagList); + } + + @Test + public void testDeleteTagsPatientVersion() throws Exception { + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType().getElements()).thenReturn(new HeaderElement[0]); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.deleteTags(new IdDt("111"), new IdDt("222"),tagList); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/Patient/111/_history/222/_tags/_delete", post.getURI().toString()); + + String ser = IOUtils.toString(post.getEntity().getContent()); + TagList actualTagList = ctx.newXmlParser().parseTagList(ser); + assertEquals(tagList, actualTagList); + } + + @Test + public void testAddTagsPatient() throws Exception { + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType().getElements()).thenReturn(new HeaderElement[0]); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.addTags(new IdDt("111"), tagList); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/Patient/111/_tags", post.getURI().toString()); + + String ser = IOUtils.toString(post.getEntity().getContent()); + TagList actualTagList = ctx.newXmlParser().parseTagList(ser); + assertEquals(tagList, actualTagList); + } + + @Test + public void testAddTagsPatientVersion() throws Exception { + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType().getElements()).thenReturn(new HeaderElement[0]); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"))); + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + client.addTags(new IdDt("111"), new IdDt("222"),tagList); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/Patient/111/_history/222/_tags", post.getURI().toString()); + + String ser = IOUtils.toString(post.getEntity().getContent()); + TagList actualTagList = ctx.newXmlParser().parseTagList(ser); + assertEquals(tagList, actualTagList); + } + + @Test + public void testGetAllTagsPatientId() throws Exception { + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + String ser = ctx.newXmlParser().encodeTagListToString(tagList); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ser), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + TagList response = client.getAllTagsPatientId(new IdDt("111")); + assertEquals(tagList, response); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient/111/_tags", get.getURI().toString()); + } + + @Test + public void testGetAllTagsPatientIdVersion() throws Exception { + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + String ser = ctx.newXmlParser().encodeTagListToString(tagList); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ser), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + TagList response = client.getAllTagsPatientId(new IdDt("Patient", "111", "222")); + assertEquals(tagList, response); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient/111/_history/222/_tags", get.getURI().toString()); + } + + @Test + public void testGetAllTagsPatientIdVersionOld() throws Exception { + + TagList tagList = new TagList(); + tagList.add(new Tag("CCC", "AAA", "BBB")); + String ser = ctx.newXmlParser().encodeTagListToString(tagList); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ser), Charset.forName("UTF-8"))); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + TagList response = client.getAllTagsPatientIdVersion(new IdDt("111"), new IdDt("222")); + assertEquals(tagList, response); + + assertEquals(HttpGet.class, capt.getValue().getClass()); + HttpGet get = (HttpGet) capt.getValue(); + assertEquals("http://foo/Patient/111/_history/222/_tags", get.getURI().toString()); + } + + private interface IClient extends IBasicClient { + + @GetTags + public TagList getAllTags(); + + @GetTags(type = Patient.class) + public TagList getAllTagsPatient(); + + @GetTags(type = Patient.class) + public TagList getAllTagsPatientId(@IdParam IdDt theId); + + @GetTags(type = Patient.class) + public TagList getAllTagsPatientIdVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersion); + + @AddTags(type = Patient.class) + public void addTags(@IdParam IdDt theId, @TagListParam TagList theTagList); + + @AddTags(type = Patient.class) + public void addTags(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @TagListParam TagList theTagList); + + @DeleteTags(type = Patient.class) + public void deleteTags(@IdParam IdDt theId, @TagListParam TagList theTagList); + + @DeleteTags(type = Patient.class) + public void deleteTags(@IdParam IdDt theId, @VersionIdParam IdDt theVersionId, @TagListParam TagList theTagList); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/TransactionClientTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/TransactionClientTest.java new file mode 100644 index 00000000000..857d5657880 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/client/TransactionClientTest.java @@ -0,0 +1,157 @@ +package ca.uhn.fhir.rest.client; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.io.InputStreamReader; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.util.Arrays; +import java.util.List; + +import org.apache.commons.io.input.ReaderInputStream; +import org.apache.http.HttpResponse; +import org.apache.http.ProtocolVersion; +import org.apache.http.client.HttpClient; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpUriRequest; +import org.apache.http.message.BasicHeader; +import org.apache.http.message.BasicStatusLine; +import org.junit.Before; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.Transaction; +import ca.uhn.fhir.rest.annotation.TransactionParam; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.server.Constants; + +public class TransactionClientTest { + + private FhirContext ctx; + private HttpClient httpClient; + private HttpResponse httpResponse; + + // atom-document-large.xml + + @Before + public void before() { + ctx = new FhirContext(Patient.class, Conformance.class); + + httpClient = mock(HttpClient.class, new ReturnsDeepStubs()); + ctx.getRestfulClientFactory().setHttpClient(httpClient); + + httpResponse = mock(HttpResponse.class, new ReturnsDeepStubs()); + } + + + @Test + public void testSimpleTransaction() throws Exception { + Patient patient = new Patient(); + patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01")); + patient.addIdentifier("urn:system", "testPersistWithSimpleLinkP01"); + patient.addName().addFamily("Tester").addGiven("Joe"); + + Observation obs = new Observation(); + obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01"); + obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01")); + + List resources = Arrays.asList((IResource)patient, obs); + + IClient client = ctx.newRestfulClient(IClient.class, "http://foo"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + client.transaction(resources); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/", post.getURI().toString()); + + Bundle bundle = ctx.newXmlParser().parseBundle(new InputStreamReader(post.getEntity().getContent())); + ourLog.info(ctx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle)); + + assertEquals(2, bundle.size()); + assertEquals("Patient/testPersistWithSimpleLinkP01", bundle.getEntries().get(0).getId().getValue()); + assertEquals("Patient/testPersistWithSimpleLinkP01", bundle.getEntries().get(0).getLinkSelf().getValue()); + assertEquals(null, bundle.getEntries().get(0).getLinkAlternate().getValue()); + + assertTrue(bundle.getEntries().get(1).getId().isEmpty()); + + } + + + @Test + public void testSimpleTransactionWithBundleParam() throws Exception { + Patient patient = new Patient(); + patient.setId(new IdDt("Patient/testPersistWithSimpleLinkP01")); + patient.addIdentifier("urn:system", "testPersistWithSimpleLinkP01"); + patient.addName().addFamily("Tester").addGiven("Joe"); + + Observation obs = new Observation(); + obs.getName().addCoding().setSystem("urn:system").setCode("testPersistWithSimpleLinkO01"); + obs.setSubject(new ResourceReferenceDt("Patient/testPersistWithSimpleLinkP01")); + + Bundle transactionBundle = Bundle.withResources(Arrays.asList((IResource)patient, obs), ctx, "http://foo"); + + IBundleClient client = ctx.newRestfulClient(IBundleClient.class, "http://foo"); + + ArgumentCaptor capt = ArgumentCaptor.forClass(HttpUriRequest.class); + when(httpClient.execute(capt.capture())).thenReturn(httpResponse); + when(httpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK")); + when(httpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_ATOM_XML + "; charset=UTF-8")); + when(httpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(createBundle()), Charset.forName("UTF-8"))); + + client.transaction(transactionBundle); + + assertEquals(HttpPost.class, capt.getValue().getClass()); + HttpPost post = (HttpPost) capt.getValue(); + assertEquals("http://foo/", post.getURI().toString()); + + Bundle bundle = ctx.newXmlParser().parseBundle(new InputStreamReader(post.getEntity().getContent())); + ourLog.info(ctx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle)); + + assertEquals(2, bundle.size()); + assertEquals("http://foo/Patient/testPersistWithSimpleLinkP01", bundle.getEntries().get(0).getId().getValue()); + assertEquals("http://foo/Patient/testPersistWithSimpleLinkP01", bundle.getEntries().get(0).getLinkSelf().getValue()); + assertEquals(null, bundle.getEntries().get(0).getLinkAlternate().getValue()); + + assertTrue(bundle.getEntries().get(1).getId().isEmpty()); + + } + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionClientTest.class); + private String createBundle() { + return ctx.newXmlParser().encodeBundleToString(new Bundle()); + } + + private interface IClient extends IBasicClient { + + @Transaction + public List transaction(@TransactionParam List theResources); + + + } + + private interface IBundleClient extends IBasicClient { + + @Transaction + public List transaction(@TransactionParam Bundle theResources); + + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingTest.java new file mode 100644 index 00000000000..025886ab5c3 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/method/BaseOutcomeReturningMethodBindingTest.java @@ -0,0 +1,196 @@ +package ca.uhn.fhir.rest.method; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.TagList; + +public class BaseOutcomeReturningMethodBindingTest { + + @Test + public void testParseTagHeader() { + + String headerString = "http://britsystems.com/fhir/tag/4567; scheme=\"http://britsystems.com/fhir\"; label=\"Tag-4567\",http://client/scheme/tag/123; scheme=\"http://client/scheme\"; label=\"tag 123\",http://client/scheme/tag/456; scheme=\"http://client/scheme\"; label=\"tag 456\",http://fhir.healthintersections.com.au/open/Patient/1; scheme=\"http://hl7.org/fhir/tag\"; label=\"GET //\",http://hl7.fhir/example; scheme=\"http://hl7.org/fhir/tag\"; label=\"FHIR example\",http://hl7.org/fhir/sid/us-ssn; scheme=\"http://hl7.org/fhir/tag\"; label=\"POST /\",http://hl7.org/fhir/tools/tag/test; scheme=\"http://hl7.org/fhir/tag\"; label=\"Test Tag\",http://hl7.org/implement/standards/fhir/v3/ActCode/InformationSensitivityPolicy#GDIS; scheme=\"http://hl7.org/fhir/tag\"; label=\"GDIS\",http://hl7.org/implement/standards/fhir/v3/Confidentiality#N; scheme=\"http://hl7.org/fhir/tag\"; label=\"N (Normal)\",http://hl7.org/implement/standards/fhir/v3/Confidentiality#R; scheme=\"http://hl7.org/fhir/tag\"; label=\"restricted\",http://nu.nl/testname; scheme=\"http://hl7.org/fhir/tag\"; label=\"TestCreateEditDelete\",http://readtag.nu.nl; scheme=\"http://hl7.org/fhir/tag\"; label=\"readTagTest\",http://spark.furore.com/fhir; scheme=\"http://hl7.org/fhir/tag\"; label=\"GET //\",http://www.healthintersections.com.au/fhir/tags/invalid; scheme=\"http://hl7.org/fhir/tag\"; label=\"Non-conformant Resource\",urn:happytag; scheme=\"http://hl7.org/fhir/tag\"; label=\"This is a happy resource\",condition; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile condition\",device; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile device\",http://fhir.healthintersections.com.au/open/Profile/condition; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile condition\",http://fhir.healthintersections.com.au/open/Profile/device; scheme=\"http://hl7.org/fhir/tag/profile\"; label=\"Profile device\",http://hl7.org/fhir/v3/ActCode#CEL; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Celebrity / VIP\",http://hl7.org/fhir/v3/ActCode#DEMO; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Contact/Employment Confidential\",http://hl7.org/fhir/v3/ActCode#DIA; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Diagnosis is/would be Confidential\",http://hl7.org/fhir/v3/ActCode#EMP; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Employee / Staff member\",http://hl7.org/fhir/v3/ActCode#ORCON; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Author only\",http://hl7.org/fhir/v3/ActCode#TABOO; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Patient/Carer Only\",http://hl7.org/fhir/v3/Confidentiality#L; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Low\",http://hl7.org/fhir/v3/Confidentiality#M; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Moderate\",http://hl7.org/fhir/v3/Confidentiality#N; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Normal\",http://hl7.org/fhir/v3/Confidentiality#R; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Restricted\",http://hl7.org/fhir/v3/Confidentiality#U; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = none\",http://hl7.org/fhir/v3/Confidentiality#V; scheme=\"http://hl7.org/fhir/tag/security\"; label=\"Confidentiality = Very Restricted\",http://term.com; scheme=\"http://scheme.com\"; label=\"Some good ole term\""; + TagList parsedFromHeader = new TagList(); + MethodUtil.parseTagValue(parsedFromHeader, headerString); + + //@formatter:off + String resourceString = "{\n" + + " \"resourceType\" : \"TagList\",\n" + + " \"category\" : [\n" + + " {\n" + + " \"scheme\" : \"http://britsystems.com/fhir\",\n" + + " \"term\" : \"http://britsystems.com/fhir/tag/4567\",\n" + + " \"label\" : \"Tag-4567\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://client/scheme\",\n" + + " \"term\" : \"http://client/scheme/tag/123\",\n" + + " \"label\" : \"tag 123\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://client/scheme\",\n" + + " \"term\" : \"http://client/scheme/tag/456\",\n" + + " \"label\" : \"tag 456\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://fhir.healthintersections.com.au/open/Patient/1\",\n" + + " \"label\" : \"GET //\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://hl7.fhir/example\",\n" + + " \"label\" : \"FHIR example\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://hl7.org/fhir/sid/us-ssn\",\n" + + " \"label\" : \"POST /\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://hl7.org/fhir/tools/tag/test\",\n" + + " \"label\" : \"Test Tag\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://hl7.org/implement/standards/fhir/v3/ActCode/InformationSensitivityPolicy#GDIS\",\n" + + " \"label\" : \"GDIS\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://hl7.org/implement/standards/fhir/v3/Confidentiality#N\",\n" + + " \"label\" : \"N (Normal)\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://hl7.org/implement/standards/fhir/v3/Confidentiality#R\",\n" + + " \"label\" : \"restricted\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://nu.nl/testname\",\n" + + " \"label\" : \"TestCreateEditDelete\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://readtag.nu.nl\",\n" + + " \"label\" : \"readTagTest\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://spark.furore.com/fhir\",\n" + + " \"label\" : \"GET //\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"http://www.healthintersections.com.au/fhir/tags/invalid\",\n" + + " \"label\" : \"Non-conformant Resource\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag\",\n" + + " \"term\" : \"urn:happytag\",\n" + + " \"label\" : \"This is a happy resource\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/profile\",\n" + + " \"term\" : \"condition\",\n" + + " \"label\" : \"Profile condition\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/profile\",\n" + + " \"term\" : \"device\",\n" + + " \"label\" : \"Profile device\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/profile\",\n" + + " \"term\" : \"http://fhir.healthintersections.com.au/open/Profile/condition\",\n" + + " \"label\" : \"Profile condition\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/profile\",\n" + + " \"term\" : \"http://fhir.healthintersections.com.au/open/Profile/device\",\n" + + " \"label\" : \"Profile device\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/ActCode#CEL\",\n" + + " \"label\" : \"Celebrity / VIP\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/ActCode#DEMO\",\n" + + " \"label\" : \"Contact/Employment Confidential\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/ActCode#DIA\",\n" + + " \"label\" : \"Diagnosis is/would be Confidential\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/ActCode#EMP\",\n" + + " \"label\" : \"Employee / Staff member\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/ActCode#ORCON\",\n" + + " \"label\" : \"Author only\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/ActCode#TABOO\",\n" + + " \"label\" : \"Patient/Carer Only\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/Confidentiality#L\",\n" + + " \"label\" : \"Confidentiality = Low\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/Confidentiality#M\",\n" + + " \"label\" : \"Confidentiality = Moderate\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/Confidentiality#N\",\n" + + " \"label\" : \"Confidentiality = Normal\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/Confidentiality#R\",\n" + + " \"label\" : \"Confidentiality = Restricted\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/Confidentiality#U\",\n" + + " \"label\" : \"Confidentiality = none\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://hl7.org/fhir/tag/security\",\n" + + " \"term\" : \"http://hl7.org/fhir/v3/Confidentiality#V\",\n" + + " \"label\" : \"Confidentiality = Very Restricted\"\n" + + " },\n" + + " {\n" + + " \"scheme\" : \"http://scheme.com\",\n" + + " \"term\" : \"http://term.com\",\n" + + " \"label\" : \"Some good ole term\"\n" + + " }\n" + + " ]\n" + + "}"; + //@formatter:on + + TagList parsedFromResource = new FhirContext().newJsonParser().parseTagList(resourceString); + + assertEquals(parsedFromHeader.size(), parsedFromResource.size()); + + for (int i = 0; i < parsedFromHeader.size(); i++) { + assertEquals(parsedFromHeader.get(i), parsedFromResource.get(i)); + } + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/method/QualifiedParamListTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/method/QualifiedParamListTest.java new file mode 100644 index 00000000000..c71478f7e85 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/method/QualifiedParamListTest.java @@ -0,0 +1,35 @@ +package ca.uhn.fhir.rest.method; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +public class QualifiedParamListTest { + + @Test + public void testSplit1() { + List actual = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(null,"aaa"); + assertEquals(1, actual.size()); + assertEquals("aaa", actual.get(0)); + } + + @Test + public void testSplit2() { + List actual = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(null,"aaa,bbb"); + assertEquals(2, actual.size()); + assertEquals("aaa", actual.get(0)); + assertEquals("bbb", actual.get(1)); + } + + @Test + public void testSplit3() { + List actual = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(null,"aaa,b\\,bb"); + System.out.println(actual); + assertEquals(2, actual.size()); + assertEquals("aaa", actual.get(0)); + assertEquals("b,bb", actual.get(1)); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java new file mode 100644 index 00000000000..083aa17826b --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/DateRangeParamTest.java @@ -0,0 +1,100 @@ +package ca.uhn.fhir.rest.param; + +import static org.junit.Assert.*; + +import java.text.ParseException; +import java.text.SimpleDateFormat; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.rest.method.QualifiedParamList; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; + +public class DateRangeParamTest { + + private static SimpleDateFormat ourFmt; + + @Test + public void testDay() throws Exception { + assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-01-02 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getUpperBoundAsInstant()); + + assertEquals(parse("2011-01-02 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-01-03 00:00:00.0000"), create(">2011-01-01", "<=2011-01-02").getUpperBoundAsInstant()); + } + + @Test + public void testFromQualifiedDateParam() throws Exception { + assertEquals(parse("2011-01-01 00:00:00.0000"), create("2011-01-01").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-01-02 00:00:00.0000"), create("2011-01-01").getUpperBoundAsInstant()); + + assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01").getLowerBoundAsInstant()); + assertEquals(null, create(">=2011-01-01").getUpperBoundAsInstant()); + + assertEquals(null, create("<=2011-01-01").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-01-02 00:00:00.0000"), create("<=2011-01-01").getUpperBoundAsInstant()); + } + + @Test + public void testMonth() throws Exception { + assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01", "<2011-02").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-02-01 00:00:00.0000"), create(">=2011-01", "<2011-02").getUpperBoundAsInstant()); + + assertEquals(parse("2011-02-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-03-01 00:00:00.0000"), create(">2011-01", "<=2011-02").getUpperBoundAsInstant()); + } + + @Test + public void testSecond() throws Exception { + assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T01:00:00").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-01-01 02:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T02:00:00").getUpperBoundAsInstant()); + + assertEquals(parse("2011-01-01 00:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getLowerBoundAsInstant()); + assertEquals(parseM1("2011-01-01 02:00:01.0000"), create(">2011-01-01T00:00:00", "<=2011-01-01T02:00:00").getUpperBoundAsInstant()); + } + + @Test + public void testYear() throws Exception { + assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011", "<2012").getLowerBoundAsInstant()); + assertEquals(parseM1("2012-01-01 00:00:00.0000"), create(">=2011", "<2012").getUpperBoundAsInstant()); + + assertEquals(parse("2012-01-01 00:00:00.0000"), create(">2011", "<=2012").getLowerBoundAsInstant()); + assertEquals(parseM1("2014-01-01 00:00:00.0000"), create(">2011", "<=2013").getUpperBoundAsInstant()); + } + + private DateRangeParam create(String theString) { + return new DateRangeParam(new QualifiedDateParam(theString)); + } + + private Date parse(String theString) throws ParseException { + return ourFmt.parse(theString); + } + + private Date parseM1(String theString) throws ParseException { + return new Date(ourFmt.parse(theString).getTime() - 1L); + } + + private Date parseP1(String theString) throws ParseException { + return new Date(ourFmt.parse(theString).getTime() + 1L); + } + + @BeforeClass + public static void beforeClass() { + ourFmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSS"); + } + + + private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException { + DateRangeParam p = new DateRangeParam(); + List tokens=new ArrayList(); + tokens.add(QualifiedParamList.singleton(null,theLower)); + tokens.add(QualifiedParamList.singleton(null,theUpper)); + p.setValuesAsQueryTokens(tokens); + return p; + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/QuantityParamTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/QuantityParamTest.java new file mode 100644 index 00000000000..0f53123d625 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/QuantityParamTest.java @@ -0,0 +1,58 @@ +package ca.uhn.fhir.rest.param; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; + +public class QuantityParamTest { + + @Test + public void testFull() { + QuantityParam p = new QuantityParam(); + p.setValueAsQueryToken(null, "<5.4|http://unitsofmeasure.org|mg"); + assertEquals(QuantityCompararatorEnum.LESSTHAN,p.getComparator()); + assertEquals("5.4", p.getValue().getValueAsString()); + assertEquals("http://unitsofmeasure.org", p.getSystem().getValueAsString()); + assertEquals("mg", p.getUnits()); + assertEquals("<5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken()); + } + + @Test + public void testApproximate() { + QuantityParam p = new QuantityParam(); + p.setValueAsQueryToken(null, "~5.4|http://unitsofmeasure.org|mg"); + assertEquals(null,p.getComparator()); + assertEquals(true, p.isApproximate()); + assertEquals("5.4", p.getValue().getValueAsString()); + assertEquals("http://unitsofmeasure.org", p.getSystem().getValueAsString()); + assertEquals("mg", p.getUnits()); + assertEquals("~5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken()); + } + + + @Test + public void testNoQualifier() { + QuantityParam p = new QuantityParam(); + p.setValueAsQueryToken(null, "5.4|http://unitsofmeasure.org|mg"); + assertEquals(null, p.getComparator()); + assertEquals("5.4", p.getValue().getValueAsString()); + assertEquals("http://unitsofmeasure.org", p.getSystem().getValueAsString()); + assertEquals("mg", p.getUnits()); + assertEquals("5.4|http://unitsofmeasure.org|mg", p.getValueAsQueryToken()); + } + + + @Test + public void testNoUnits() { + QuantityParam p = new QuantityParam(); + p.setValueAsQueryToken(null, "5.4"); + assertEquals(null, p.getComparator()); + assertEquals("5.4", p.getValue().getValueAsString()); + assertEquals(null, p.getSystem().getValueAsString()); + assertEquals(null, p.getUnits()); + assertEquals("5.4||", p.getValueAsQueryToken()); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/ReferenceParamTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/ReferenceParamTest.java new file mode 100644 index 00000000000..8bc69c5aa12 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/param/ReferenceParamTest.java @@ -0,0 +1,29 @@ +package ca.uhn.fhir.rest.param; + +import static org.junit.Assert.*; + +import org.junit.Test; + +public class ReferenceParamTest { + + @Test + public void testWithResourceTypeAsQualifier() { + + ReferenceParam rp = new ReferenceParam(); + rp.setValueAsQueryToken(":Location", "123"); + assertEquals("Location", rp.getResourceType()); + assertEquals("123", rp.getIdPart()); + + } + + @Test + public void testWithResourceType() { + + ReferenceParam rp = new ReferenceParam(); + rp.setValueAsQueryToken(null, "Location/123"); + assertEquals("Location", rp.getResourceType()); + assertEquals("123", rp.getIdPart()); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/BinaryTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/BinaryTest.java new file mode 100644 index 00000000000..8d53a9a31d4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/BinaryTest.java @@ -0,0 +1,183 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ByteArrayEntity; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Binary; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class BinaryTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(); + private static Binary ourLast; + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BinaryTest.class); + + private static int ourPort; + + private static Server ourServer; + + @Before + public void before() { + ourLast=null; + } + + @Test + public void testRead() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Binary/foo"); + HttpResponse status = ourClient.execute(httpGet); + byte[] responseContent = IOUtils.toByteArray(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("foo", status.getFirstHeader("content-type").getValue()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, responseContent); + + } + + + @Test + public void testCreate() throws Exception { + HttpPost http = new HttpPost("http://localhost:" + ourPort + "/Binary"); + http.setEntity(new ByteArrayEntity(new byte[] {1,2,3,4}, ContentType.create("foo/bar", "UTF-8"))); + + HttpResponse status = ourClient.execute(http); + assertEquals(201, status.getStatusLine().getStatusCode()); + + assertEquals("foo/bar; charset=UTF-8", ourLast.getContentType()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, ourLast.getContent()); + + } + + public void testCreateWrongType() throws Exception { + Binary res = new Binary(); + res.setContent(new byte[] { 1, 2, 3, 4 }); + res.setContentType("text/plain"); + String stringContent = ourCtx.newJsonParser().encodeResourceToString(res); + + HttpPost http = new HttpPost("http://localhost:" + ourPort + "/Binary"); + http.setEntity(new StringEntity(stringContent, ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); + + HttpResponse status = ourClient.execute(http); + assertEquals(201, status.getStatusLine().getStatusCode()); + + assertEquals("text/plain", ourLast.getContentType()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, ourLast.getContent()); + + } + + @Test + public void testSearch() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Binary?"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(Constants.CT_ATOM_XML + "; charset=UTF-8", status.getFirstHeader("content-type").getValue()); + + ourLog.info(responseContent); + + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + Binary bin = (Binary) bundle.getEntries().get(0).getResource(); + + assertEquals("text/plain", bin.getContentType()); + assertArrayEquals(new byte[] { 1, 2, 3, 4 }, bin.getContent()); + } + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + ResourceProvider patientProvider = new ResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class ResourceProvider implements IResourceProvider { + + @Create + public MethodOutcome create(@ResourceParam Binary theBinary) { + ourLast = theBinary; + return new MethodOutcome(new IdDt("1")); + } + + @Override + public Class getResourceType() { + return Binary.class; + } + + @Read + public Binary read(@IdParam IdDt theId) { + Binary retVal = new Binary(); + retVal.setId("1"); + retVal.setContent(new byte[] { 1, 2, 3, 4 }); + retVal.setContentType(theId.getIdPart()); + return retVal; + } + + + + @Search + public List search() { + Binary retVal = new Binary(); + retVal.setId("1"); + retVal.setContent(new byte[] { 1, 2, 3, 4 }); + retVal.setContentType("text/plain"); + return Collections.singletonList(retVal); + } + +} + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompositeParameterTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompositeParameterTest.java new file mode 100644 index 00000000000..151f9135600 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompositeParameterTest.java @@ -0,0 +1,178 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.net.URLEncoder; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.CompositeAndListParam; +import ca.uhn.fhir.rest.param.CompositeOrListParam; +import ca.uhn.fhir.rest.param.CompositeParam; +import ca.uhn.fhir.rest.param.DateParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class CompositeParameterTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx; + private static int ourPort; + private static Server ourServer; + + @Test + public void testSearchWithDateValue() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_DATE + "=" + URLEncoder.encode("foo\\$bar$2001-01-01", "UTF-8")); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + List entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries(); + assertEquals(1, entries.size()); + Observation o = (Observation) entries.get(0).getResource(); + assertEquals("foo$bar", o.getName().getText().getValue()); + assertEquals("2001-01-01", ((DateTimeDt) o.getApplies()).getValueAsString().substring(0, 10)); + } + } + + @Test + public void testSearchWithMultipleValue() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?" + Observation.SP_NAME_VALUE_STRING + "=" + URLEncoder.encode("l1$r1,l2$r2", "UTF-8") + "&" + Observation.SP_NAME_VALUE_STRING + "=" + URLEncoder.encode("l3$r3,l4$r4", "UTF-8")); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + List entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries(); + assertEquals(1, entries.size()); + Observation o = (Observation) entries.get(0).getResource(); + assertEquals("AND", o.getName().getCoding().get(0).getDisplay().getValue()); + assertEquals("OR", o.getName().getCoding().get(1).getDisplay().getValue()); + assertEquals("l1", o.getName().getCoding().get(1).getSystem().getValueAsString()); + assertEquals("r1", o.getName().getCoding().get(1).getCode().getValue()); + assertEquals("OR", o.getName().getCoding().get(2).getDisplay().getValue()); + assertEquals("l2", o.getName().getCoding().get(2).getSystem().getValueAsString()); + assertEquals("r2", o.getName().getCoding().get(2).getCode().getValue()); + + assertEquals("AND", o.getName().getCoding().get(3).getDisplay().getValue()); + assertEquals("OR", o.getName().getCoding().get(4).getDisplay().getValue()); + assertEquals("l3", o.getName().getCoding().get(4).getSystem().getValueAsString()); + assertEquals("r3", o.getName().getCoding().get(4).getCode().getValue()); + assertEquals("OR", o.getName().getCoding().get(5).getDisplay().getValue()); + assertEquals("l4", o.getName().getCoding().get(5).getSystem().getValueAsString()); + assertEquals("r4", o.getName().getCoding().get(5).getCode().getValue()); + } + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyObservationResourceProvider patientProvider = new DummyObservationResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + ourCtx = servlet.getFhirContext(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + ourCtx = servlet.getFhirContext(); + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyObservationResourceProvider implements IResourceProvider { + //@formatter:off + @Search + public List findObservation( + @RequiredParam(name = Observation.SP_NAME_VALUE_DATE, compositeTypes= { StringParam.class, DateParam.class }) + CompositeParam theParam + ) { + //@formatter:on + + ArrayList retVal = new ArrayList(); + + Observation p = new Observation(); + p.setId("1"); + p.setApplies(theParam.getRightValue().getValueAsDateTimeDt()); + p.getName().setText(theParam.getLeftValue().getValueAsStringDt()); + retVal.add(p); + + return retVal; + } + + //@formatter:off + @Search + public List findObservationNVS( + @RequiredParam(name = Observation.SP_NAME_VALUE_STRING, compositeTypes= { StringParam.class, StringParam.class }) + CompositeAndListParam theParam + ) { + //@formatter:on + + ArrayList retVal = new ArrayList(); + + Observation p = new Observation(); + p.setId("1"); + for (CompositeOrListParam nextAnd : theParam.getValuesAsQueryTokens()) { + p.getName().addCoding().getDisplay().setValue("AND"); + for (CompositeParam nextOr : nextAnd.getValuesAsQueryTokens()) { + p.getName().addCoding().setDisplay("OR").setSystem(nextOr.getLeftValue().getValue()).setCode(nextOr.getRightValue().getValue()); + } + } + retVal.add(p); + + return retVal; + } + + @Override + public Class getResourceType() { + return Observation.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompressionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompressionTest.java new file mode 100644 index 00000000000..c90f86cc7bd --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CompressionTest.java @@ -0,0 +1,151 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URL; +import java.net.URLConnection; +import java.util.concurrent.TimeUnit; +import java.util.zip.GZIPInputStream; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.parser.DataFormatException; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class CompressionTest { + + private static CloseableHttpClient ourClient; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CompressionTest.class); + private static int ourPort; + private static Server ourServer; + private static FhirContext ourCtx; + + public static String decompress(byte[] theResource) { + GZIPInputStream is; + try { + is = new GZIPInputStream(new ByteArrayInputStream(theResource)); + return IOUtils.toString(is, "UTF-8"); + } catch (IOException e) { + throw new DataFormatException("Failed to decompress contents", e); + } + } + + @Test + public void testRead() throws Exception { + { + /* + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + httpGet.addHeader(Constants.HEADER_ACCEPT_ENCODING, "gzip"); + HttpResponse status = ourClient.execute(httpGet); + Header ce = status.getFirstHeader(Constants.HEADER_CONTENT_ENCODING); + */ + + URLConnection c = new URL("http://localhost:" + ourPort + "/Patient/1").openConnection(); + c.addRequestProperty(Constants.HEADER_ACCEPT_ENCODING, "gzip"); + + String enc = c.getContentEncoding(); + + assertEquals("gzip", enc); + + byte[] responseContentBytes = IOUtils.toByteArray(c.getInputStream()); + String responseContent = decompress(responseContentBytes); + + IdentifierDt dt = ourCtx.newXmlParser().parseResource(Patient.class,responseContent).getIdentifierFirstRep(); + assertEquals("1", dt.getSystem().getValueAsString()); + assertEquals(null, dt.getValue().getValueAsString()); + } + + } + + @Test + public void testVRead() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/2"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + IdentifierDt dt = ourCtx.newXmlParser().parseResource(Patient.class,responseContent).getIdentifierFirstRep(); + assertEquals("1", dt.getSystem().getValueAsString()); + assertEquals("2", dt.getValue().getValueAsString()); + } + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyProvider patientProvider = new DummyProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + ourCtx = servlet.getFhirContext(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + +// GzipHandler gh = new GzipHandler(); +// gh.setHandler(proxyHandler); +// gh.setMimeTypes(Constants.CT_ATOM_XML+','+Constants.CT_FHIR_JSON+','+Constants.CT_FHIR_XML); + + ourServer.setHandler(proxyHandler); + + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyProvider implements IResourceProvider { + + @Read(version = true) + public Patient findPatient(@IdParam IdDt theId) { + Patient patient = new Patient(); + patient.addIdentifier(theId.getIdPart(), theId.getVersionIdPart()); + patient.setId("Patient/1/_history/1"); + return patient; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CorsTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CorsTest.java new file mode 100644 index 00000000000..f2220d4039e --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CorsTest.java @@ -0,0 +1,137 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.EnumSet; +import java.util.concurrent.TimeUnit; + +import javax.servlet.DispatcherType; + +import org.apache.commons.io.IOUtils; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpOptions; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.ebaysf.web.cors.CORSFilter; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.servlet.FilterHolder; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.server.ResfulServerSelfReferenceTest.DummyPatientResourceProvider; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class CorsTest { + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CorsTest.class); + + @Test + public void testContextWithSpace() throws Exception { + int port = PortUtil.findFreePort(); + Server server = new Server(port); + + RestfulServer restServer = new RestfulServer(); + restServer.setFhirContext(ourCtx); + restServer.setResourceProviders(new DummyPatientResourceProvider()); + + // ServletHandler proxyHandler = new ServletHandler(); + ServletHolder servletHolder = new ServletHolder(restServer); + + FilterHolder fh = new FilterHolder(); + fh.setHeldClass(CORSFilter.class); + fh.setInitParameter("cors.logging.enabled", "true"); + fh.setInitParameter("cors.allowed.origins", "*"); + fh.setInitParameter("cors.allowed.headers", "x-fhir-starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers"); + fh.setInitParameter("cors.exposed.headers", "Location,Content-Location"); + fh.setInitParameter("cors.allowed.methods", "GET,POST,PUT,DELETE,OPTIONS"); + + ServletContextHandler ch = new ServletContextHandler(); + ch.setContextPath("/rootctx/rcp2"); + ch.addServlet(servletHolder, "/fhirctx/fcp2/*"); + ch.addFilter(fh, "/*", EnumSet.of(DispatcherType.INCLUDE, DispatcherType.REQUEST)); + + ContextHandlerCollection contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + + server.setHandler(ch); + server.start(); + try { + String baseUri = "http://localhost:" + port + "/rootctx/rcp2/fhirctx/fcp2"; + + { + HttpOptions httpOpt = new HttpOptions(baseUri + "/Organization/b27ed191-f62d-4128-d99d-40b5e84f2bf2"); + httpOpt.addHeader("Access-Control-Request-Method", "POST"); + httpOpt.addHeader("Origin", "http://www.fhir-starter.com"); + httpOpt.addHeader("Access-Control-Request-Headers", "accept, x-fhir-starter, content-type"); + HttpResponse status = ourClient.execute(httpOpt); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + assertEquals("POST", status.getFirstHeader(Constants.HEADER_CORS_ALLOW_METHODS).getValue()); + assertEquals("http://www.fhir-starter.com", status.getFirstHeader(Constants.HEADER_CORS_ALLOW_ORIGIN).getValue()); + } + { + String uri = baseUri + "/Patient?identifier=urn:hapitest:mrns%7C00001"; + HttpGet httpGet = new HttpGet(uri); + httpGet.addHeader("X-FHIR-Starter", "urn:fhir.starter"); + httpGet.addHeader("Origin", "http://www.fhir-starter.com"); + HttpResponse status = ourClient.execute(httpGet); + + Header origin = status.getFirstHeader(Constants.HEADER_CORS_ALLOW_ORIGIN); + assertEquals("http://www.fhir-starter.com", origin.getValue()); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + } + { + HttpPost httpOpt = new HttpPost(baseUri + "/Patient"); + httpOpt.addHeader("Access-Control-Request-Method", "POST"); + httpOpt.addHeader("Origin", "http://www.fhir-starter.com"); + httpOpt.addHeader("Access-Control-Request-Headers", "accept, x-fhir-starter, content-type"); + httpOpt.setEntity(new StringEntity(ourCtx.newXmlParser().encodeResourceToString(new Patient()))); + HttpResponse status = ourClient.execute(httpOpt); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response: {}", status); + ourLog.info("Response was:\n{}", responseContent); + assertEquals("http://www.fhir-starter.com", status.getFirstHeader(Constants.HEADER_CORS_ALLOW_ORIGIN).getValue()); + } + } finally { + server.stop(); + } + + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourCtx = new FhirContext(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CreateTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CreateTest.java new file mode 100644 index 00000000000..0b54a85be29 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CreateTest.java @@ -0,0 +1,254 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.io.StringReader; +import java.util.ArrayList; +import java.util.Collection; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.resource.AdverseReaction; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class CreateTest { + private static CloseableHttpClient ourClient; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CreateTest.class); + private static int ourPort; + private static DiagnosticReportProvider ourReportProvider; + private static Server ourServer; + + + + @Test + public void testCreate() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setValue("001"); + patient.addIdentifier().setValue("002"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue()); + + } + + + @Test + public void testCreateById() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setValue("001"); + patient.addIdentifier().setValue("002"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/1234"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertEquals("http://localhost:" + ourPort + "/Patient/1234/_history/002", status.getFirstHeader("location").getValue()); + + } + + + + @Test + public void testCreateJson() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setValue("001"); + patient.addIdentifier().setValue("002"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient"); + httpPost.setEntity(new StringEntity(new FhirContext().newJsonParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_JSON, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue()); + + } + + @Test + public void testCreateWithUnprocessableEntity() throws Exception { + + DiagnosticReport report = new DiagnosticReport(); + report.getIdentifier().setValue("001"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/DiagnosticReport"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(report), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + + OperationOutcome outcome = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, new StringReader(responseContent)); + assertEquals("FOOBAR", outcome.getIssueFirstRep().getDetails().getValue()); + + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + PatientProvider patientProvider = new PatientProvider(); + + ourReportProvider = new DiagnosticReportProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider, ourReportProvider, new DummyAdverseReactionResourceProvider()); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + public static class DiagnosticReportProvider implements IResourceProvider { + private TagList myLastTags; + + public TagList getLastTags() { + return myLastTags; + } + + @Override + public Class getResourceType() { + return DiagnosticReport.class; + } + + + @Create() + public MethodOutcome createDiagnosticReport(@ResourceParam DiagnosticReport thePatient) { + OperationOutcome outcome = new OperationOutcome(); + outcome.addIssue().setDetails("FOOBAR"); + throw new UnprocessableEntityException(outcome); + } + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyAdverseReactionResourceProvider implements IResourceProvider { + + /* + * ********************* + * NO NEW METHODS ********************* + */ + + @Create() + public MethodOutcome create(@ResourceParam AdverseReaction thePatient) { + IdDt id = new IdDt("Patient", thePatient.getIdentifier().get(0).getValue().getValue(), thePatient.getIdentifier().get(1).getValue().getValue()); + return new MethodOutcome(id); + } + + @Search() + public Collection getAllResources() { + ArrayList retVal = new ArrayList(); + + AdverseReaction ar1 = new AdverseReaction(); + ar1.setId("1"); + retVal.add(ar1); + + AdverseReaction ar2 = new AdverseReaction(); + ar2.setId("2"); + retVal.add(ar2); + + return retVal; + } + + @Override + public Class getResourceType() { + return AdverseReaction.class; + } + + } + + + + + + public static class PatientProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Create() + public MethodOutcome createPatient(@ResourceParam Patient thePatient) { + IdDt id = new IdDt(thePatient.getIdentifier().get(0).getValue().getValue()); + if (thePatient.getId().isEmpty()==false) { + id=thePatient.getId(); + } + return new MethodOutcome(id.withVersion("002")); + } + + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CustomTypeTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CustomTypeTest.java new file mode 100644 index 00000000000..9e7e92f4147 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/CustomTypeTest.java @@ -0,0 +1,243 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.Tag; +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.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.resource.Profile; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class CustomTypeTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(ExtendedPatient.class); + private static int ourPort; + private static Server ourServer; + private static RestfulServer ourServlet; + + + @Test + public void testSearchReturnsProfile() throws Exception { + ourServlet.setAddProfileTag(AddProfileTagEnum.ONLY_FOR_CUSTOM); + ourReturnExtended=true; + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + BundleEntry entry = bundle.getEntries().get(0); + List profileTags = entry.getCategories().getTagsWithScheme(Tag.HL7_ORG_PROFILE_TAG); + assertEquals(1, profileTags.size()); + assertEquals("http://foo/profiles/Profile", profileTags.get(0).getTerm()); + + Patient p = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString()); + + } + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeTest.class); + + @Test + public void testFindProfileItself() throws Exception { + ourServlet.setAddProfileTag(AddProfileTagEnum.ONLY_FOR_CUSTOM); + ourReturnExtended=true; + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Profile/prof2?_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Profile bundle = ourCtx.newXmlParser().parseResource(Profile.class, responseContent); + + } + + + @Test + public void testSearchReturnsNoProfileForNormalType() throws Exception { + ourServlet.setAddProfileTag(AddProfileTagEnum.ONLY_FOR_CUSTOM); + ourReturnExtended=false; + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + BundleEntry entry = bundle.getEntries().get(0); + List profileTags = entry.getCategories().getTagsWithScheme(Tag.HL7_ORG_PROFILE_TAG); + assertEquals(0, profileTags.size()); + } + + @Test + public void testSearchReturnsNoProfileForExtendedType() throws Exception { + ourServlet.setAddProfileTag(AddProfileTagEnum.NEVER); + ourReturnExtended=true; + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + BundleEntry entry = bundle.getEntries().get(0); + List profileTags = entry.getCategories().getTagsWithScheme(Tag.HL7_ORG_PROFILE_TAG); + assertEquals(0, profileTags.size()); + } + + + @Test + public void testSearchReturnsProfileForNormalType() throws Exception { + ourServlet.setAddProfileTag(AddProfileTagEnum.ALWAYS); + ourReturnExtended=false; + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + BundleEntry entry = bundle.getEntries().get(0); + List profileTags = entry.getCategories().getTagsWithScheme(Tag.HL7_ORG_PROFILE_TAG); + assertEquals(1, profileTags.size()); + assertEquals("http://hl7.org/fhir/profiles/Patient", profileTags.get(0).getTerm()); + + Patient p = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString()); + + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + ourServlet = new RestfulServer(); + ourServlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); + + ourServlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(ourServlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + FhirContext fhirContext = ourServlet.getFhirContext(); + fhirContext.getResourceDefinition(ExtendedPatient.class); + + } + + + @ResourceDef(name="Patient", profile="http://foo/profiles/Profile", id="prof2") + public static class ExtendedPatient extends Patient { + + /** + * Each extension is defined in a field. Any valid HAPI Data Type + * can be used for the field type. Note that the [name=""] attribute + * in the @Child annotation needs to match the name for the bean accessor + * and mutator methods. + */ + @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 StringDt myPetName; + + public StringDt getPetName() { + if (myPetName == null) { + myPetName = new StringDt(); + } + return myPetName; + } + + public void setPetName(StringDt thePetName) { + myPetName = thePetName; + } + + } + + private static boolean ourReturnExtended = false; + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Search + public List findPatient(@OptionalParam(name = "_id") StringParam theParam) { + ArrayList retVal = new ArrayList(); + + Patient patient = ourReturnExtended ? new ExtendedPatient() : new Patient(); + patient.setId("1"); + patient.addIdentifier("system", "identifier123"); + if (theParam != null) { + patient.addName().addFamily("id" + theParam.getValue()); + } + retVal.add(patient); + return retVal; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DynamicSearchTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DynamicSearchTest.java new file mode 100644 index 00000000000..f9c7229ed69 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/DynamicSearchTest.java @@ -0,0 +1,196 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.assertEquals; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.RuntimeSearchParam; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum; +import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.StringAndListParam; +import ca.uhn.fhir.rest.param.StringOrListParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class DynamicSearchTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(DynamicSearchTest.class); + private static int ourPort; + + private static Server ourServer; + + private static SearchParameterMap ourLastSearchParams; + + @Before + public void before() { + ourLastSearchParams = null; + } + + @Test + public void testSearchOneStringParam() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?param1=param1value"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + assertEquals(1, ourLastSearchParams.size()); + StringAndListParam andList =(StringAndListParam) ourLastSearchParams.get("param1"); + assertEquals(1,andList.getValuesAsQueryTokens().size()); + StringOrListParam orList = andList.getValuesAsQueryTokens().get(0); + assertEquals(1,orList.getValuesAsQueryTokens().size()); + StringParam param1 = orList.getValuesAsQueryTokens().get(0); + assertEquals("param1value", param1.getValue()); + } + + + @Test + public void testSearchOneStringParamWithOr() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?param1=param1value,param1value2"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + assertEquals(1, ourLastSearchParams.size()); + StringAndListParam andList =(StringAndListParam) ourLastSearchParams.get("param1"); + assertEquals(1,andList.getValuesAsQueryTokens().size()); + StringOrListParam orList = andList.getValuesAsQueryTokens().get(0); + assertEquals(2,orList.getValuesAsQueryTokens().size()); + StringParam param1 = orList.getValuesAsQueryTokens().get(0); + assertEquals("param1value", param1.getValue()); + StringParam param1b = orList.getValuesAsQueryTokens().get(1); + assertEquals("param1value2", param1b.getValue()); + } + + @Test + public void testSearchOneStringParamWithAnd() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?param1=param1value¶m1=param1value2"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + assertEquals(1, ourLastSearchParams.size()); + StringAndListParam andList =(StringAndListParam) ourLastSearchParams.get("param1"); + assertEquals(2,andList.getValuesAsQueryTokens().size()); + StringOrListParam orList = andList.getValuesAsQueryTokens().get(0); + assertEquals(1,orList.getValuesAsQueryTokens().size()); + StringParam param1 = orList.getValuesAsQueryTokens().get(0); + assertEquals("param1value", param1.getValue()); + + orList = andList.getValuesAsQueryTokens().get(1); + assertEquals(1,orList.getValuesAsQueryTokens().size()); + StringParam param1b = orList.getValuesAsQueryTokens().get(0); + assertEquals("param1value2", param1b.getValue()); + } + + @Test + public void testConformance() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata?_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Conformance conf = ourCtx.newXmlParser().parseResource(Conformance.class,responseContent); + + ourLog.info(responseContent); + } + + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); + + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IDynamicSearchResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Override + public List getSearchParameters() { + ArrayList retVal = new ArrayList(); + retVal.add(new RuntimeSearchParam("param1", "This is the first parameter", "Patient.param1", SearchParamTypeEnum.STRING)); + retVal.add(new RuntimeSearchParam("param2", "This is the second parameter", "Patient.param2", SearchParamTypeEnum.DATE)); + return retVal; + } + + @Search(dynamic=true) + public List search(SearchParameterMap theSearchParams) { + ourLastSearchParams = theSearchParams; + + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("Patient/1"); + patient.addIdentifier("system", "fooCompartment"); + retVal.add(patient); + return retVal; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ExceptionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ExceptionTest.java new file mode 100644 index 00000000000..799cf3b9518 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ExceptionTest.java @@ -0,0 +1,192 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.List; +import java.util.concurrent.TimeUnit; + +import junit.framework.AssertionFailedError; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hamcrest.core.StringContains; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ExceptionTest { + + private static CloseableHttpClient ourClient; + private static boolean ourGenerateOperationOutcome; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExceptionTest.class); + private static int ourPort; + private static Server ourServer; + + private static RestfulServer servlet; + + @Before + public void before() { + ourGenerateOperationOutcome = false; + ourExceptionType=null; + } + + @Test + public void testInternalError() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?throwInternalError=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(500, status.getStatusLine().getStatusCode()); + OperationOutcome oo = (OperationOutcome) servlet.getFhirContext().newXmlParser().parseResource(responseContent); + assertThat(oo.getIssueFirstRep().getDetails().getValue(), StringContains.containsString("InternalErrorException: Exception Text")); + } + } + + @Test + public void testResourceReturning() throws Exception { + // No OO + { + ourExceptionType=ResourceNotFoundException.class; + ourGenerateOperationOutcome=false; + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(404, status.getStatusLine().getStatusCode()); + OperationOutcome oo = (OperationOutcome) servlet.getFhirContext().newXmlParser().parseResource(responseContent); + assertThat(oo.getIssueFirstRep().getDetails().getValue(), StringContains.containsString("Resource Patient/123 is not known")); + } + // Yes OO + { + ourExceptionType=ResourceNotFoundException.class; + ourGenerateOperationOutcome=true; + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(404, status.getStatusLine().getStatusCode()); + OperationOutcome oo = (OperationOutcome) servlet.getFhirContext().newXmlParser().parseResource(responseContent); + assertThat(oo.getIssueFirstRep().getDetails().getValue(), StringContains.containsString(OPERATION_OUTCOME_DETAILS)); + } + } + + @Test + public void testInternalErrorFormatted() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?throwInternalError=aaa&_format=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(500, status.getStatusLine().getStatusCode()); + OperationOutcome oo = (OperationOutcome) servlet.getFhirContext().newXmlParser().parseResource(responseContent); + assertThat(oo.getIssueFirstRep().getDetails().getValue(), StringContains.containsString("InternalErrorException: Exception Text")); + } + } + + @Test + public void testInternalErrorJson() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?throwInternalError=aaa&_format=json"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(500, status.getStatusLine().getStatusCode()); + OperationOutcome oo = (OperationOutcome) servlet.getFhirContext().newJsonParser().parseResource(responseContent); + assertThat(oo.getIssueFirstRep().getDetails().getValue(), StringContains.containsString("InternalErrorException: Exception Text")); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + + private static Class ourExceptionType; + + private static final String OPERATION_OUTCOME_DETAILS = "OperationOutcomeDetails"; + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + + @Search + public List findPatient(@RequiredParam(name = "throwInternalError") StringParam theParam) { + throw new InternalErrorException("Exception Text"); + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Read + public Patient read(@IdParam IdDt theId) { + OperationOutcome oo = null; + if (ourGenerateOperationOutcome) { + oo = new OperationOutcome(); + oo.addIssue().setDetails(OPERATION_OUTCOME_DETAILS); + } + + if (ourExceptionType == ResourceNotFoundException.class) { + throw new ResourceNotFoundException(theId, oo); + }else { + throw new AssertionFailedError("Unknown exception type: " + ourExceptionType); + } + + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/HistoryTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/HistoryTest.java new file mode 100644 index 00000000000..4f847eeb106 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/HistoryTest.java @@ -0,0 +1,224 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.rest.annotation.History; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.Since; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class HistoryTest { + + private static CloseableHttpClient ourClient; + private static int ourPort; + private static Server ourServer; + + /** + * We test this here because of bug 3- At one point VRead would "steal" instance history calls and handle them + */ + @Test + public void testVread() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/_history/456"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Patient bundle = new FhirContext().newXmlParser().parseResource(Patient.class, responseContent); + assertEquals("vread", bundle.getNameFirstRep().getFamilyFirstRep().getValue()); + } + } + + @Test + public void testServerHistory() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/_history"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.getEntries().size()); + assertEquals("http://localhost:" + ourPort +"/Patient/h1/_history/1", bundle.getEntries().get(0).getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort +"/Patient/h1/_history/2", bundle.getEntries().get(1).getLinkSelf().getValue()); + + } + } + + @Test + public void testInstanceHistory() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/_history"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.getEntries().size()); + assertEquals("http://localhost:" + ourPort +"/Patient/ih1/_history/1", bundle.getEntries().get(0).getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort +"/Patient/ih1/_history/2", bundle.getEntries().get(1).getLinkSelf().getValue()); + + } + } + + @Test + public void testTypeHistory() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/_history"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.getEntries().size()); + assertEquals("http://localhost:" + ourPort +"/Patient/th1/_history/1", bundle.getEntries().get(0).getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort +"/Patient/th1/_history/2", bundle.getEntries().get(1).getLinkSelf().getValue()); + + } + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPlainProvider plainProvider = new DummyPlainProvider(); + DummyResourceProvider patientProvider = new DummyResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setPlainProviders(plainProvider); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + public static class DummyResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Read(version=true) + public Patient vread(@IdParam IdDt theId) { + Patient retVal = new Patient(); + retVal.addName().addFamily("vread"); + retVal.setId(theId); + return retVal; + } + + @History + public List instanceHistory(@IdParam IdDt theId) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("Patient/ih1/_history/1"); + patient.addName().addFamily("history"); + retVal.add(patient); + + Patient patient2 = new Patient(); + patient2.setId("Patient/ih1/_history/2"); + patient2.addName().addFamily("history"); + retVal.add(patient2); + + return retVal; + } + + @History + public List typeHistory() { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("Patient/th1/_history/1"); + patient.addName().addFamily("history"); + retVal.add(patient); + + Patient patient2 = new Patient(); + patient2.setId("Patient/th1/_history/2"); + patient2.addName().addFamily("history"); + retVal.add(patient2); + + return retVal; + } + + + } + + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPlainProvider { + + @History + public List history(@Since InstantDt theSince) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("Patient/h1/_history/1"); + patient.addName().addFamily("history"); + retVal.add(patient); + + Patient patient2 = new Patient(); + patient2.setId("Patient/h1/_history/2"); + patient2.addName().addFamily("history"); + retVal.add(patient2); + + return retVal; + } + + + + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java new file mode 100644 index 00000000000..b80f85e43c5 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncludeTest.java @@ -0,0 +1,483 @@ +package ca.uhn.fhir.rest.server; + +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.Include; +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.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.resource.Practitioner; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.annotation.IncludeParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.util.ElementUtil; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class IncludeTest { + + private static CloseableHttpClient ourClient; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(IncludeTest.class); + private static int ourPort; + private static Server ourServer; + private static FhirContext ourCtx; + + @Test + public void testNoIncludes() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(0, p.getName().size()); + assertEquals("Hello", p.getId().getIdPart()); + } + + @Test + public void testOneInclude() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(1, p.getName().size()); + assertEquals("Hello", p.getId().getIdPart()); + assertEquals("foo", p.getName().get(0).getFamilyFirstRep().getValue()); + } + + +// @Test + public void testMixedContainedAndNonContained() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/DiagnosticReport?_query=stitchedInclude&_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info(responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(4, bundle.size()); + } + + + @Test + public void testIIncludedResourcesNonContained() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=normalInclude&_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + ourLog.info(responseContent); + + assertEquals(3, bundle.size()); + assertEquals(new IdDt("Patient/p1"), bundle.toListOfResources().get(0).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless()); + + Patient p1 = (Patient) bundle.toListOfResources().get(0); + assertEquals(0,p1.getContained().getContainedResources().size()); + + Patient p2 = (Patient) bundle.toListOfResources().get(1); + assertEquals(0,p2.getContained().getContainedResources().size()); + + + } + + @Test + public void testIIncludedResourcesNonContainedInExtension() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + ourLog.info(responseContent); + + assertEquals(3, bundle.size()); + assertEquals(new IdDt("Patient/p1"), bundle.toListOfResources().get(0).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless()); + + Patient p1 = (Patient) bundle.toListOfResources().get(0); + assertEquals(0,p1.getContained().getContainedResources().size()); + + Patient p2 = (Patient) bundle.toListOfResources().get(1); + assertEquals(0,p2.getContained().getContainedResources().size()); + + + } + + + @Test + public void testIIncludedResourcesNonContainedInExtensionJson() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=extInclude&_pretty=true&_format=json"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newJsonParser().parseBundle(responseContent); + + ourLog.info(responseContent); + + assertEquals(3, bundle.size()); + assertEquals(new IdDt("Patient/p1"), bundle.toListOfResources().get(0).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless()); + + Patient p1 = (Patient) bundle.toListOfResources().get(0); + assertEquals(0,p1.getContained().getContainedResources().size()); + + Patient p2 = (Patient) bundle.toListOfResources().get(1); + assertEquals(0,p2.getContained().getContainedResources().size()); + + + } + + @Test + public void testIIncludedResourcesNonContainedInDeclaredExtension() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=declaredExtInclude&_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + ourLog.info(responseContent); + + assertEquals(4, bundle.size()); + assertEquals(new IdDt("Patient/p1"), bundle.toListOfResources().get(0).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Patient/p2"), bundle.toListOfResources().get(1).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Organization/o1"), bundle.toListOfResources().get(2).getId().toUnqualifiedVersionless()); + assertEquals(new IdDt("Organization/o2"), bundle.toListOfResources().get(3).getId().toUnqualifiedVersionless()); + + Patient p1 = (Patient) bundle.toListOfResources().get(0); + assertEquals(0,p1.getContained().getContainedResources().size()); + + Patient p2 = (Patient) bundle.toListOfResources().get(1); + assertEquals(0,p2.getContained().getContainedResources().size()); + + + } + + + + @Test + public void testTwoInclude() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=bar"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(2, p.getName().size()); + assertEquals("Hello", p.getId().getIdPart()); + + Set values = new HashSet(); + values.add( p.getName().get(0).getFamilyFirstRep().getValue()); + values.add( p.getName().get(1).getFamilyFirstRep().getValue()); + assertThat(values, containsInAnyOrder("foo", "bar")); + + } + + @Test + public void testBadInclude() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_include=foo&_include=baz"); + HttpResponse status = ourClient.execute(httpGet); + assertEquals(400, status.getStatusLine().getStatusCode()); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + + ourCtx = new FhirContext(); + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setFhirContext(ourCtx); + servlet.setResourceProviders(patientProvider, new DummyDiagnosticReportResourceProvider()); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + @ResourceDef(name="Patient") + public static class ExtPatient extends Patient + { + @Child(name="secondOrg") + @Extension(url="http://foo#secondOrg", definedLocally = false, isModifier = false) + private ResourceReferenceDt mySecondOrg; + + @Override + public boolean isEmpty() { + return super.isEmpty() && ElementUtil.isEmpty(mySecondOrg); + } + + public ResourceReferenceDt getSecondOrg() { + if (mySecondOrg==null) { + mySecondOrg= new ResourceReferenceDt(); + } + return mySecondOrg; + } + + public void setSecondOrg(ResourceReferenceDt theSecondOrg) { + mySecondOrg = theSecondOrg; + } + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyDiagnosticReportResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return DiagnosticReport.class; + } + + @Search(queryName = "stitchedInclude") + public List stitchedInclude() { + Practitioner pr1 = new Practitioner(); + pr1.setId("Practitioner/001"); + pr1.getName().addFamily("Pract1"); + + Practitioner pr2 = new Practitioner(); + pr2.setId("Practitioner/002"); + pr2.getName().addFamily("Pract2"); + + Practitioner pr3 = new Practitioner(); + pr3.setId("Practitioner/003"); + pr3.getName().addFamily("Pract3"); + + Observation o1 = new Observation(); + o1.getName().setText("Obs1"); + o1.addPerformer().setResource(pr1); + + Observation o2 = new Observation(); + o2.getName().setText("Obs2"); + o2.addPerformer().setResource(pr2); + + Observation o3 = new Observation(); + o3.getName().setText("Obs3"); + o3.addPerformer().setResource(pr3); + + DiagnosticReport rep = new DiagnosticReport(); + rep.setId("DiagnosticReport/999"); + rep.getName().setText("Rep"); + rep.addResult().setResource(o1); + rep.addResult().setResource(o2); + rep.addResult().setResource(o3); + + return Collections.singletonList(rep); + } + + + + } + + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Search(queryName = "normalInclude") + public List normalInclude() { + Organization o1 = new Organization(); + o1.getName().setValue("o1"); + o1.setId("o1"); + + Patient p1 = new Patient(); + p1.setId("p1"); + p1.addIdentifier().setLabel("p1"); + p1.getManagingOrganization().setResource(o1); + + Patient p2 = new Patient(); + p2.setId("p2"); + p2.addIdentifier().setLabel("p2"); + p2.getManagingOrganization().setResource(o1); + + return Arrays.asList(p1, p2); + } + + + @Search(queryName = "extInclude") + public List extInclude() { + Organization o1 = new Organization(); + o1.getName().setValue("o1"); + o1.setId("o1"); + + Patient p1 = new Patient(); + p1.setId("p1"); + p1.addIdentifier().setLabel("p1"); + p1.addUndeclaredExtension(false, "http://foo", new ResourceReferenceDt(o1)); + + Patient p2 = new Patient(); + p2.setId("p2"); + p2.addIdentifier().setLabel("p2"); + p2.addUndeclaredExtension(false, "http://foo", new ResourceReferenceDt(o1)); + + return Arrays.asList(p1, p2); + } + + @Search(queryName = "declaredExtInclude") + public List declaredExtInclude() { + Organization o1 = new Organization(); + o1.getName().setValue("o1"); + o1.setId("o1"); + + Organization o2 = new Organization(); + o2.getName().setValue("o2"); + o2.setId("o2"); + o1.getPartOf().setResource(o2); + + ExtPatient p1 = new ExtPatient(); + p1.setId("p1"); + p1.addIdentifier().setLabel("p1"); + p1.getSecondOrg().setResource(o1); + + ExtPatient p2 = new ExtPatient(); + p2.setId("p2"); + p2.addIdentifier().setLabel("p2"); + p2.getSecondOrg().setResource(o1); + + return Arrays.asList(p1, p2); + } + + + @Search(queryName = "containedInclude") + public List containedInclude() { + Organization o1 = new Organization(); + o1.getName().setValue("o1"); + + Patient p1 = new Patient(); + p1.setId("p1"); + p1.addIdentifier().setLabel("p1"); + p1.getManagingOrganization().setResource(o1); + + Patient p2 = new Patient(); + p2.setId("p2"); + p2.addIdentifier().setLabel("p2"); + p2.getManagingOrganization().setResource(o1); + + return Arrays.asList(p1, p2); + } + + @Search + public List findPatient(@RequiredParam(name = Patient.SP_NAME) StringDt theName, @IncludeParam(allow = { "foo", "bar" }) Set theIncludes) { + ArrayList retVal = new ArrayList(); + + Patient p = new Patient(); + p.addIdentifier("foo", "bar"); + + p.setId(theName.getValue()); + + if (theIncludes != null) { + for (Include next : theIncludes) { + p.addName().addFamily().setValue(next.getValue()); + } + } + retVal.add(p); + + return retVal; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + + + public static void main(String[] args) { + + Organization org = new Organization(); + org.setId("Organization/65546"); + org.getName().setValue("Contained Test Organization"); + + Patient patient = new Patient(); + patient.setId("Patient/1333"); + patient.addIdentifier("urn:mrns", "253345"); + patient.getManagingOrganization().setResource(patient); + + + System.out.println(new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(patient)); + + patient.getManagingOrganization().getReference(); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategyTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategyTest.java new file mode 100644 index 00000000000..9e96a5100f4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/IncomingRequestAddressStrategyTest.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import javax.servlet.http.HttpServletRequest; + +import org.junit.Test; + +public class IncomingRequestAddressStrategyTest { + + /** + * This is an incoming request from an instance of Tomcat on AWS, provided by + * Simon Ling of Systems Made Simple + */ + @Test + public void testAwsUrl() { + + HttpServletRequest req = mock(HttpServletRequest.class); + when(req.getRequestURI()).thenReturn("/FhirStorm/fhir/Patient/_search"); + when(req.getServletPath()).thenReturn("/fhir"); + when(req.getRequestURL()).thenReturn(new StringBuffer().append("http://fhirstorm.dyndns.org:8080/FhirStorm/fhir/Patient/_search")); + when(req.getContextPath()).thenReturn("/FhirStorm"); + + IncomingRequestAddressStrategy incomingRequestAddressStrategy = new IncomingRequestAddressStrategy(); + String actual = incomingRequestAddressStrategy.determineServerBase(null,req); + assertEquals("http://fhirstorm.dyndns.org:8080/FhirStorm/fhir", actual); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/InterceptorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/InterceptorTest.java new file mode 100644 index 00000000000..98fd750b3c4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/InterceptorTest.java @@ -0,0 +1,207 @@ +package ca.uhn.fhir.rest.server; + +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.InOrder; + +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.method.RequestDetails; +import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class InterceptorTest { + + private static CloseableHttpClient ourClient; + private static int ourPort; + private static Server ourServer; + private static RestfulServer servlet; + private IServerInterceptor myInterceptor1; + private IServerInterceptor myInterceptor2; + + @Test + public void testInterceptorFires() throws Exception { + when(myInterceptor1.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true); + when(myInterceptor1.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true); + when(myInterceptor1.outgoingResponse(any(RequestDetails.class), any(IResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true); + when(myInterceptor2.incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true); + when(myInterceptor2.incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true); + when(myInterceptor2.outgoingResponse(any(RequestDetails.class), any(IResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class))).thenReturn(true); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + + InOrder order = inOrder(myInterceptor1, myInterceptor2); + order.verify(myInterceptor1, times(1)).incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class)); + order.verify(myInterceptor2, times(1)).incomingRequestPreProcessed(any(HttpServletRequest.class), any(HttpServletResponse.class)); + order.verify(myInterceptor1, times(1)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); + order.verify(myInterceptor2, times(1)).incomingRequestPostProcessed(any(RequestDetails.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); + + order.verify(myInterceptor2, times(1)).outgoingResponse(any(RequestDetails.class), any(IResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); + order.verify(myInterceptor1, times(1)).outgoingResponse(any(RequestDetails.class), any(IResource.class), any(HttpServletRequest.class), any(HttpServletResponse.class)); + verifyNoMoreInteractions(myInterceptor1); + verifyNoMoreInteractions(myInterceptor2); + } + + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @Before + public void before() { + myInterceptor1 = mock(IServerInterceptor.class); + myInterceptor2 = mock(IServerInterceptor.class); + servlet.setInterceptors(myInterceptor1, myInterceptor2); + } + + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + public Map getIdToPatient() { + Map idToPatient = new HashMap(); + { + Patient patient = createPatient1(); + idToPatient.put("1", patient); + } + { + Patient patient = new Patient(); + patient.getIdentifier().add(new IdentifierDt()); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00002"); + patient.getName().add(new HumanNameDt()); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientTwo"); + patient.getGender().setText("F"); + patient.getId().setValue("2"); + idToPatient.put("2", patient); + } + return idToPatient; + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Read() + public Patient getResourceById(@IdParam IdDt theId) { + String key = theId.getIdPart(); + Patient retVal = getIdToPatient().get(key); + return retVal; + } + + + @Search(queryName="searchWithWildcardRetVal") + public List searchWithWildcardRetVal() { + Patient p = new Patient(); + p.setId("1234"); + p.addName().addFamily("searchWithWildcardRetVal"); + return Collections.singletonList(p); + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Search() + public List getResourceById(@RequiredParam(name = "_id") String theId) { + Patient patient = getIdToPatient().get(theId); + if (patient != null) { + return Collections.singletonList(patient); + } else { + return Collections.emptyList(); + } + } + + + @Override + public Class getResourceType() { + return Patient.class; + } + + private Patient createPatient1() { + Patient patient = new Patient(); + patient.addIdentifier(); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00001"); + patient.addName(); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientOne"); + patient.getGender().setText("M"); + patient.getId().setValue("1"); + return patient; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/MethodPriorityTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/MethodPriorityTest.java new file mode 100644 index 00000000000..92b5b180f51 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/MethodPriorityTest.java @@ -0,0 +1,121 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hamcrest.core.StringContains; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class MethodPriorityTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(); + private static int ourPort; + private static Server ourServer; + private static RestfulServer ourServlet; + + @Test + public void testDelegateTo_idMethod() throws Exception { + ourServlet.setResourceProviders(new DummyObservationResourceProvider()); + ourServer.start(); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?name=name"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, StringContains.containsString("01")); + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation?_id=id"); + status = ourClient.execute(httpGet); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, StringContains.containsString("02")); + } + + @After + public void after() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + ServletHandler proxyHandler = new ServletHandler(); + ourServlet = new RestfulServer(); + ourServlet.setFhirContext(ourCtx); + ourServlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); + + ServletHolder servletHolder = new ServletHolder(ourServlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + public static class DummyObservationResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Observation.class; + } + + @SuppressWarnings("unused") + @Search + public List search01(@OptionalParam(name = Observation.SP_NAME) StringParam theName) { + List retVal = new ArrayList(); + Observation o = new Observation(); + o.setId("01"); + o.getName().setText("search01"); + retVal.add(o); + return retVal; + } + + @SuppressWarnings("unused") + @Search + public List search02(@RequiredParam(name = "_id") StringParam theId) { + List retVal = new ArrayList(); + Observation o = new Observation(); + o.setId("02"); + o.getName().setText("search02"); + retVal.add(o); + return retVal; + + } + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/PagingTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/PagingTest.java new file mode 100644 index 00000000000..014cde64b33 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/PagingTest.java @@ -0,0 +1,215 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; +import static org.mockito.Matchers.*; +import static org.mockito.Mockito.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class PagingTest { + + private static CloseableHttpClient ourClient; + private static int ourPort; + private static Server ourServer; + private static FhirContext ourContext; + private static RestfulServer myRestfulServer; + private static SimpleBundleProvider ourBundleProvider; + private IPagingProvider myPagingProvider; + + @Test + public void testSearchExactMatch() throws Exception { + when(myPagingProvider.getDefaultPageSize()).thenReturn(5); + when(myPagingProvider.getMaximumPageSize()).thenReturn(9); + when(myPagingProvider.storeResultList(any(IBundleProvider.class))).thenReturn("ABCD"); + when(myPagingProvider.retrieveResultList(eq("ABCD"))).thenReturn(ourBundleProvider); + + String link; + String base = "http://localhost:" + ourPort; + { + HttpGet httpGet = new HttpGet(base + "/Patient?_format=xml&_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); + assertEquals(5, bundle.getEntries().size()); + assertEquals("0", bundle.getEntries().get(0).getId().getIdPart()); + assertEquals("4", bundle.getEntries().get(4).getId().getIdPart()); + assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=5&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkNext() + .getValue()); + assertNull(bundle.getLinkPrevious().getValue()); + link = bundle.getLinkNext().getValue(); + } + { + HttpGet httpGet = new HttpGet(link.replace("=xml", "=json")); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourContext.newJsonParser().parseBundle(responseContent); + assertEquals(5, bundle.getEntries().size()); + assertEquals("5", bundle.getEntries().get(0).getId().getIdPart()); + assertEquals("9", bundle.getEntries().get(4).getId().getIdPart()); + assertNull(bundle.getLinkNext().getValue()); + assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=5&_format=json&_pretty=true", bundle.getLinkPrevious() + .getValue()); + } + } + + @Test + public void testSearchInexactOffset() throws Exception { + when(myPagingProvider.getDefaultPageSize()).thenReturn(5); + when(myPagingProvider.getMaximumPageSize()).thenReturn(9); + when(myPagingProvider.storeResultList(any(IBundleProvider.class))).thenReturn("ABCD"); + when(myPagingProvider.retrieveResultList(eq("ABCD"))).thenReturn(ourBundleProvider); + + String base = "http://localhost:" + ourPort; + { + HttpGet httpGet = new HttpGet(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=8&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.getEntries().size()); + assertEquals("8", bundle.getEntries().get(0).getId().getIdPart()); + assertEquals("9", bundle.getEntries().get(1).getId().getIdPart()); + assertNull(bundle.getLinkNext().getValue()); + assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=3&" + Constants.PARAM_COUNT + "=5&_format=xml&_pretty=true", bundle.getLinkPrevious() + .getValue()); + } + + } + + @Test + public void testSearchSmallPages() throws Exception { + when(myPagingProvider.getDefaultPageSize()).thenReturn(5); + when(myPagingProvider.getMaximumPageSize()).thenReturn(9); + when(myPagingProvider.storeResultList(any(IBundleProvider.class))).thenReturn("ABCD"); + when(myPagingProvider.retrieveResultList(eq("ABCD"))).thenReturn(ourBundleProvider); + + String link; + String base = "http://localhost:" + ourPort; + { + HttpGet httpGet = new HttpGet(base + "/Patient?_count=2"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.getEntries().size()); + assertEquals("0", bundle.getEntries().get(0).getId().getIdPart()); + assertEquals("1", bundle.getEntries().get(1).getId().getIdPart()); + assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue()); + assertNull(bundle.getLinkPrevious().getValue()); + link = bundle.getLinkNext().getValue(); + } + { + HttpGet httpGet = new HttpGet(link); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourContext.newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.getEntries().size()); + assertEquals("2", bundle.getEntries().get(0).getId().getIdPart()); + assertEquals("3", bundle.getEntries().get(1).getId().getIdPart()); + assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=4&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkNext().getValue()); + assertEquals(base + '/' + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=2&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkSelf().getValue()); + assertEquals(base + '?' + Constants.PARAM_PAGINGACTION + "=ABCD&" + Constants.PARAM_PAGINGOFFSET + "=0&" + Constants.PARAM_COUNT + "=2&_format=xml", bundle.getLinkPrevious().getValue()); + } + + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @Before + public void before() { + myPagingProvider = mock(IPagingProvider.class); + myRestfulServer.setPagingProvider(myPagingProvider); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourContext = new FhirContext(); + + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + myRestfulServer = new RestfulServer(); + myRestfulServer.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(myRestfulServer); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + List retVal = new ArrayList(); + for (int i = 0; i < 10; i++) { + Patient patient = new Patient(); + patient.setId("" + i); + patient.addName().addFamily("" + i); + retVal.add(patient); + } + ourBundleProvider = new SimpleBundleProvider(retVal); + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Search + public IBundleProvider findPatient() { + return ourBundleProvider; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/PlainProviderTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/PlainProviderTest.java new file mode 100644 index 00000000000..26bc6116b23 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/PlainProviderTest.java @@ -0,0 +1,273 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hamcrest.core.IsEqual; +import org.hamcrest.core.StringStartsWith; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.annotation.Count; +import ca.uhn.fhir.rest.annotation.History; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Since; +import ca.uhn.fhir.util.PortUtil; + +public class PlainProviderTest { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(PlainProviderTest.class); + private int myPort; + private Server myServer; + private CloseableHttpClient myClient; + private FhirContext myCtx; + private RestfulServer myRestfulServer; + + @Before + public void before() throws Exception { + myPort = PortUtil.findFreePort(); + myServer = new Server(myPort); + myCtx = new FhirContext(Patient.class); + + ServletHandler proxyHandler = new ServletHandler(); + ServletHolder servletHolder = new ServletHolder(); + myRestfulServer = new RestfulServer(); + servletHolder.setServlet(myRestfulServer); + proxyHandler.addServletWithMapping(servletHolder, "/fhir/context/*"); + myServer.setHandler(proxyHandler); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + + builder.setConnectionManager(connectionManager); + myClient = builder.build(); + + } + + @After + public void after() throws Exception { + myServer.stop(); + } + + @Test + public void testSearchByParamIdentifier() throws Exception { + myRestfulServer.setProviders(new SearchProvider()); + myServer.start(); + + String baseUri = "http://localhost:" + myPort + "/fhir/context"; + String uri = baseUri + "/Patient?identifier=urn:hapitest:mrns%7C00001"; + HttpGet httpGet = new HttpGet(uri); + HttpResponse status = myClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = myCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + Patient patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + + assertEquals(uri, bundle.getLinkSelf().getValue()); + assertEquals(baseUri, bundle.getLinkBase().getValue()); + + httpGet.releaseConnection(); + } + + @Test + public void testGlobalHistory() throws Exception { + GlobalHistoryProvider provider = new GlobalHistoryProvider(); + myRestfulServer.setProviders(provider); + myServer.start(); + + String baseUri = "http://localhost:" + myPort + "/fhir/context"; + HttpResponse status = myClient.execute(new HttpGet(baseUri + "/_history?_since=2012-01-02T00%3A01%3A02&_count=12")); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = myCtx.newXmlParser().parseBundle(responseContent); + assertEquals(3, bundle.getEntries().size()); + + assertThat(provider.myLastSince.getValueAsString(), StringStartsWith.startsWith("2012-01-02T00:01:02")); + assertThat(provider.myLastCount.getValueAsString(), IsEqual.equalTo("12")); + + status = myClient.execute(new HttpGet(baseUri + "/_history?&_count=12")); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = myCtx.newXmlParser().parseBundle(responseContent); + assertEquals(3, bundle.getEntries().size()); + assertNull(provider.myLastSince.getValueAsString()); + assertThat(provider.myLastCount.getValueAsString(), IsEqual.equalTo("12")); + + status =myClient.execute(new HttpGet(baseUri + "/_history?_since=2012-01-02T00%3A01%3A02")); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = myCtx.newXmlParser().parseBundle(responseContent); + assertEquals(3, bundle.getEntries().size()); + assertThat(provider.myLastSince.getValueAsString(), StringStartsWith.startsWith("2012-01-02T00:01:02")); + assertNull(provider.myLastCount.getValueAsString()); + + status =myClient.execute(new HttpGet(baseUri + "/_history")); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = myCtx.newXmlParser().parseBundle(responseContent); + assertEquals(3, bundle.getEntries().size()); + assertNull(provider.myLastSince.getValueAsString()); + assertNull(provider.myLastCount.getValueAsString()); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class SearchProvider { + + public Map getIdToPatient() { + Map idToPatient = new HashMap(); + { + Patient patient = createPatient(); + idToPatient.put("1", patient); + } + { + Patient patient = new Patient(); + patient.getIdentifier().add(new IdentifierDt()); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00002"); + patient.getName().add(new HumanNameDt()); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientTwo"); + patient.getGender().setText("F"); + idToPatient.put("2", patient); + } + return idToPatient; + } + + @Search(type = Patient.class) + public Patient findPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) { + for (Patient next : getIdToPatient().values()) { + for (IdentifierDt nextId : next.getIdentifier()) { + if (nextId.matchesSystemAndValue(theIdentifier)) { + return next; + } + } + } + return null; + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Read(type = Patient.class) + public Patient getPatientById(@IdParam IdDt theId) { + return getIdToPatient().get(theId.getValue()); + } + + } + + public static class GlobalHistoryProvider { + + private InstantDt myLastSince; + private IntegerDt myLastCount; + + @History + public List getGlobalHistory(@Since InstantDt theSince, @Count IntegerDt theCount) { + myLastSince = theSince; + myLastCount = theCount; + ArrayList retVal = new ArrayList(); + + IResource p = createPatient(); + p.setId(new IdDt("1")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, new IdDt("A")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, new InstantDt("2012-01-01T00:00:01")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt("2012-01-01T01:00:01")); + retVal.add(p); + + p = createPatient(); + p.setId(new IdDt("1")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, new IdDt("B")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, new InstantDt("2012-01-01T00:00:01")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt("2012-01-01T01:00:03")); + retVal.add(p); + + p = createOrganization(); + p.setId(new IdDt("1")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, new IdDt("A")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, new InstantDt("2013-01-01T00:00:01")); + p.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt("2013-01-01T01:00:01")); + retVal.add(p); + + return retVal; + } + + } + + private static Patient createPatient() { + Patient patient = new Patient(); + patient.setId("1"); + patient.addIdentifier(); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00001"); + patient.addName(); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientOne"); + patient.getGender().setText("M"); + return patient; + } + + private static Organization createOrganization() { + Organization retVal = new Organization(); + retVal.setId("1"); + retVal.addIdentifier(); + retVal.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + retVal.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + retVal.getIdentifier().get(0).setValue("00001"); + retVal.getName().setValue("Test Org"); + return retVal; + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReadTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReadTest.java new file mode 100644 index 00000000000..a226e659d4d --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReadTest.java @@ -0,0 +1,228 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.Header; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.BaseResource; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Binary; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ReadTest { + + private static CloseableHttpClient ourClient; + private static int ourPort; + private static Server ourServer; + private static FhirContext ourCtx; + + @Test + public void testRead() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + IdentifierDt dt = ourCtx.newXmlParser().parseResource(Patient.class,responseContent).getIdentifierFirstRep(); + + assertEquals("1", dt.getSystem().getValueAsString()); + assertEquals(null, dt.getValue().getValueAsString()); + + Header cl = status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION_LC); + assertNotNull(cl); + assertEquals("http://localhost:" + ourPort + "/Patient/1/_history/1", cl.getValue()); + + } + + } + + + @Test + public void testReadForProviderWithAbstractReturnType() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization/1"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + IdentifierDt dt = ourCtx.newXmlParser().parseResource(Organization.class,responseContent).getIdentifierFirstRep(); + + assertEquals("1", dt.getSystem().getValueAsString()); + assertEquals(null, dt.getValue().getValueAsString()); + + Header cl = status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION_LC); + assertNotNull(cl); + assertEquals("http://localhost:" + ourPort + "/Organization/1/_history/1", cl.getValue()); + + } + + } + + @Test + public void testBinaryRead() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Binary/1"); + HttpResponse status = ourClient.execute(httpGet); + byte[] responseContent = IOUtils.toByteArray(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("application/x-foo", status.getEntity().getContentType().getValue()); + + Header cl = status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION_LC); + assertNotNull(cl); + assertEquals("http://localhost:" + ourPort + "/Binary/1/_history/1", cl.getValue()); + + Header cd = status.getFirstHeader("content-disposition"); + assertNotNull(cd); + assertEquals("Attachment;", cd.getValue()); + + assertEquals(4,responseContent.length); + for (int i = 0; i < 4; i++) { + assertEquals(i+1, responseContent[i]); // should be 1,2,3,4 + } + + } + + } + + @Test + public void testVRead() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/2"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + IdentifierDt dt = ourCtx.newXmlParser().parseResource(Patient.class,responseContent).getIdentifierFirstRep(); + assertEquals("1", dt.getSystem().getValueAsString()); + assertEquals("2", dt.getValue().getValueAsString()); + + Header cl = status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION_LC); + assertNotNull(cl); + assertEquals("http://localhost:" + ourPort + "/Patient/1/_history/1", cl.getValue()); + } + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyProvider patientProvider = new DummyProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + ourCtx = servlet.getFhirContext(); + servlet.setResourceProviders(patientProvider, new DummyBinaryProvider(), new OrganizationProviderWithAbstractReturnType()); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyProvider implements IResourceProvider { + + @Read(version = true) + public Patient findPatient(@IdParam IdDt theId) { + Patient patient = new Patient(); + patient.addIdentifier(theId.getIdPart(), theId.getVersionIdPart()); + patient.setId("Patient/1/_history/1"); + return patient; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class OrganizationProviderWithAbstractReturnType implements IResourceProvider { + + @Read(version = true) + public BaseResource findPatient(@IdParam IdDt theId) { + Organization org = new Organization(); + org.addIdentifier(theId.getIdPart(), theId.getVersionIdPart()); + org.setId("Organization/1/_history/1"); + return org; + } + + @Override + public Class getResourceType() { + return Organization.class; + } + + } + + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyBinaryProvider implements IResourceProvider { + + @Read(version = true) + public Binary findPatient(@IdParam IdDt theId) { + Binary bin = new Binary(); + bin.setContentType("application/x-foo"); + bin.setContent(new byte[] {1,2,3,4}); + bin.setId("Binary/1/_history/1"); + return bin; + } + + @Override + public Class getResourceType() { + return Binary.class; + } + + } + + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReferenceParameterTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReferenceParameterTest.java new file mode 100644 index 00000000000..73d6dcfec25 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ReferenceParameterTest.java @@ -0,0 +1,373 @@ +package ca.uhn.fhir.rest.server; + +import static org.apache.commons.lang3.StringUtils.defaultString; +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam; +import ca.uhn.fhir.model.dstu.resource.Location; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.ReferenceParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ReferenceParameterTest { + + private static CloseableHttpClient ourClient; + private static int ourPort; + private static Server ourServer; + private static FhirContext ourCtx; + + @Test + public void testSearchWithValue() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + "=123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + List entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries(); + assertEquals(1, entries.size()); + Patient p = (Patient) entries.get(0).getResource(); + assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue()); + assertEquals("1", p.getName().get(1).getFamilyFirstRep().getValue()); + assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue()); + } + + @Test + public void testSearchWithValueAndType() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization=123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + List entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries(); + assertEquals(1, entries.size()); + Patient p = (Patient) entries.get(0).getResource(); + assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue()); + assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue()); + assertEquals("2", p.getName().get(2).getFamilyFirstRep().getValue()); + } + + @Test + public void testSearchWithValueAndTypeAndChain() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ":Organization.name=123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + List entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries(); + assertEquals(1, entries.size()); + Patient p = (Patient) entries.get(0).getResource(); + assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue()); + assertEquals("1Organization", p.getName().get(1).getFamilyFirstRep().getValue()); + assertEquals("2name", p.getName().get(2).getFamilyFirstRep().getValue()); + + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName1() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, containsString("value=\"thePartOfId po123 null\"")); + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName2() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.name=poname"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, containsString("value=\"thePartOfName poname\"")); + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName3() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof=po123&partof.name=poname"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, containsString("value=\"thePartOfId po123 null\"")); + assertThat(responseContent, containsString("value=\"thePartOfName poname\"")); + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName4() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.fooChain=po123&partof.name=poname"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, containsString("value=\"thePartOfId po123 fooChain\"")); + assertThat(responseContent, containsString("value=\"thePartOfName poname\"")); + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName5() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof.bar=po123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, containsString("value=\"theBarId po123 bar\"")); + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName6() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof:Organization.bar=po123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, containsString("value=\"theBarId Organization/po123 bar\"")); + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName7() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Organization?partof:Organization=po123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, containsString("value=\"thePartOfId Organization/po123 null\"")); + } + + @Test + public void testSearchWithMultipleParamsOfTheSameName8() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Location?partof=po123"); + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(400, status.getStatusLine().getStatusCode()); + } + + + @Test + public void testSearchWithValueAndChain() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?" + Patient.SP_PROVIDER + ".name=123"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + List entries = ourCtx.newXmlParser().parseBundle(responseContent).getEntries(); + assertEquals(1, entries.size()); + Patient p = (Patient) entries.get(0).getResource(); + assertEquals("0123", p.getName().get(0).getFamilyFirstRep().getValue()); + assertEquals("1", p.getName().get(1).getFamilyFirstRep().getValue()); + assertEquals("2name", p.getName().get(2).getFamilyFirstRep().getValue()); + } + } + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ReferenceParameterTest.class); + + @Test + public void testParamTypesInConformanceStatement() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata?_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info(responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Conformance conf = ourCtx.newXmlParser().parseResource(Conformance.class, responseContent); + + RestResource res = conf.getRestFirstRep().getResource().get(2); + assertEquals("Patient", res.getType().getValue()); + + RestResourceSearchParam param = res.getSearchParamFirstRep(); + assertEquals(Patient.SP_PROVIDER, param.getName().getValue()); + + assertEquals(1, param.getTarget().size()); + assertEquals(ResourceTypeEnum.ORGANIZATION, param.getTarget().get(0).getValueAsEnum()); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + ourCtx = servlet.getFhirContext(); + servlet.setResourceProviders(patientProvider, new DummyOrganizationResourceProvider(), new DummyLocationResourceProvider()); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + ourCtx = servlet.getFhirContext(); + } + + public static class DummyOrganizationResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Organization.class; + } + + /** + * https://github.com/jamesagnew/hapi-fhir/issues/19 + */ + //@formatter:off + @Search + public List searchByName( + @OptionalParam(name = "partof", chainWhitelist= {"", "fooChain"}) ReferenceParam thePartOfId, + @OptionalParam(name = "partof.name") StringParam thePartOfName) { + //@formatter:on + + ArrayList retVal = new ArrayList(); + if (thePartOfId != null) { + Organization org = new Organization(); + org.setId("1"); + org.getName().setValue("thePartOfId " + thePartOfId.getValue() + " " + thePartOfId.getChain()); + retVal.add(org); + } + if (thePartOfName != null) { + Organization org = new Organization(); + org.setId("2"); + org.getName().setValue("thePartOfName " + thePartOfName.getValue()); + retVal.add(org); + } + if (retVal.isEmpty()) { + ourLog.info("No values for foo - Going to fail"); + throw new InternalErrorException("No Values for foo"); + } + + return retVal; + } + + //@formatter:off + @Search + public List searchByNameWithDifferentChain( + @OptionalParam(name = "partof", chainWhitelist= {"bar"}) ReferenceParam theBarId) { + //@formatter:on + + ArrayList retVal = new ArrayList(); + if (theBarId != null) { + Organization org = new Organization(); + org.setId("1"); + org.getName().setValue("theBarId " + theBarId.getValue() + " " + theBarId.getChain()); + retVal.add(org); + } + if (retVal.isEmpty()) { + ourLog.info("No values for bar - Going to fail"); + throw new InternalErrorException("No Values for bar"); + } + + return retVal; + } + + } + + + public static class DummyLocationResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Location.class; + } + + //@formatter:off + @Search + public List searchByNameWithDifferentChain( + @OptionalParam(name = "partof", chainWhitelist= {"bar"}) ReferenceParam theBarId) { + //@formatter:on + + ArrayList retVal = new ArrayList(); + if (theBarId != null) { + Location loc = new Location(); + loc.setId("1"); + loc.getName().setValue("theBarId " + theBarId.getValue() + " " + theBarId.getChain()); + retVal.add(loc); + } + if (retVal.isEmpty()) { + ourLog.info("No values for bar - Going to fail"); + throw new InternalErrorException("No Values for bar"); + } + + return retVal; + } + + } + + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Search + public List findPatient(@OptionalParam(name = Patient.SP_PROVIDER, targetTypes = { Organization.class }) ReferenceParam theParam) { + ArrayList retVal = new ArrayList(); + + Patient p = new Patient(); + p.setId("1"); + p.addName().addFamily("0" + theParam.getValueAsQueryToken()); + p.addName().addFamily("1" + defaultString(theParam.getResourceType())); + p.addName().addFamily("2" + defaultString(theParam.getChain())); + retVal.add(p); + + return retVal; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResfulServerMethodTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResfulServerMethodTest.java new file mode 100644 index 00000000000..76d9ca301a5 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResfulServerMethodTest.java @@ -0,0 +1,1388 @@ +package ca.uhn.fhir.rest.server; + +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.not; +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import ca.uhn.fhir.model.dstu.resource.*; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hamcrest.core.StringContains; +import org.hamcrest.core.StringEndsWith; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.composite.QuantityDt; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.parser.IParser; +import ca.uhn.fhir.rest.annotation.Delete; +import ca.uhn.fhir.rest.annotation.History; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.IncludeParam; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Validate; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.param.DateParam; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; +import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; +import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.fhir.rest.server.provider.ServerProfileProvider; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ResfulServerMethodTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResfulServerMethodTest.class); + private static int ourPort; + private static DummyDiagnosticReportResourceProvider ourReportProvider; + private static Server ourServer; + private static RestfulServer ourRestfulServer; + + @Test + public void test404IsPropagatedCorrectly() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/DiagnosticReport?throw404=true"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(404, status.getStatusLine().getStatusCode()); + assertThat(responseContent, StringContains.containsString("AAAABBBB")); + } + + + @Test + public void testDateRangeParam() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?dateRange=%3E%3D2011-01-01&dateRange=%3C%3D2021-01-01"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Patient patient = (Patient) ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource(); + assertEquals(">=2011-01-01", patient.getName().get(0).getSuffix().get(0).getValue()); + assertEquals("<=2021-01-01", patient.getName().get(0).getSuffix().get(1).getValue()); + + } + + @Test + public void testDelete() throws Exception { + + HttpDelete httpGet = new HttpDelete("http://localhost:" + ourPort + "/Patient/1234"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + OperationOutcome patient = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent); + assertEquals("Patient/1234", patient.getIssueFirstRep().getDetails().getValue()); + + } + + @Test + public void testDeleteNoResponse() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpDelete httpGet = new HttpDelete("http://localhost:" + ourPort + "/DiagnosticReport/1234"); + HttpResponse status = ourClient.execute(httpGet); + + assertEquals(204, status.getStatusLine().getStatusCode()); + + } + + @Test + public void testEntryLinkSelf() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1&_include=include2&_include=include3"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + BundleEntry entry0 = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getId().getValue()); + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1&_include=include2&_include=include3&_format=json"); + status = ourClient.execute(httpGet); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + ourLog.info(responseContent); + bundle = ourCtx.newJsonParser().parseBundle(responseContent); + entry0 = bundle.getEntries().get(0); + // Should not include params such as _format=json + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkSelf().getValue()); + + } + + @Test + public void testFormatParamJson() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=json"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + Patient patient = (Patient) ourCtx.newJsonParser().parseResource(responseContent); + // assertEquals("PatientOne", + // patient.getName().get(0).getGiven().get(0).getValue()); + + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient)); + + } + + @Test + public void testFormatParamXml() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1?_format=xml"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Patient patient = (Patient) ourCtx.newXmlParser().parseResource(responseContent); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + + } + + @Test + public void testGetById() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Patient patient = (Patient) ourCtx.newXmlParser().parseResource(responseContent); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + + /* + * Different ID + */ + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/2"); + status = ourClient.execute(httpGet); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.debug("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + patient = (Patient) ourCtx.newXmlParser().parseResource(responseContent); + assertEquals("PatientTwo", patient.getName().get(0).getGiven().get(0).getValue()); + + /* + * Bad ID + */ + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/9999999"); + status = ourClient.execute(httpGet); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.debug("Response was:\n{}", responseContent); + + assertEquals(404, status.getStatusLine().getStatusCode()); + + } + + @Test + public void testGetByVersionId() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1/_history/999"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Patient patient = (Patient) ourCtx.newXmlParser().parseResource(responseContent); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + assertEquals("999", patient.getName().get(0).getText().getValue()); + + } + + @Test + public void testGetMetadata() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + // ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + IParser parser = ourCtx.newXmlParser().setPrettyPrint(true); + Conformance bundle = parser.parseResource(Conformance.class, responseContent); + + { + IParser p = ourCtx.newXmlParser().setPrettyPrint(true); + String enc = p.encodeResourceToString(bundle); + ourLog.info("Response:\n{}", enc); + + p = ourCtx.newXmlParser().setPrettyPrint(false); + enc = p.encodeResourceToString(bundle); + ourLog.info("Response:\n{}", enc); + assertThat(enc, StringContains.containsString("")); + } + // { + // IParser p = ourCtx.newJsonParser().setPrettyPrint(true); + // + // p.encodeResourceToWriter(bundle, new OutputStreamWriter(System.out)); + // + // String enc = p.encodeResourceToString(bundle); + // ourLog.info("Response:\n{}", enc); + // assertTrue(enc.contains(ExtensionConstants.CONF_ALSO_CHAIN)); + // + // } + } + + @Test + public void testHistoryFailsIfResourcesAreIncorrectlyPopulated() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/999/_history"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(500, status.getStatusLine().getStatusCode()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/998/_history"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(500, status.getStatusLine().getStatusCode()); + } + } + + // @Test + // public void testSearchByComplex() throws Exception { + // + // HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + + // "/Patient?Patient.identifier=urn:oid:2.16.840.1.113883.3.239.18.148%7C7000135&name=urn:oid:1.3.6.1.4.1.12201.102.5%7C522&date="); + // HttpResponse status = ourClient.execute(httpGet); + // + // String responseContent = + // IOUtils.toString(status.getEntity().getContent()); + // ourLog.info("Response was:\n{}", responseContent); + // + // assertEquals(200, status.getStatusLine().getStatusCode()); + // } + + @Test + public void testHistoryResourceInstance() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/222/_history"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(2, bundle.getEntries().size()); + + // Older resource + { + BundleEntry olderEntry = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/222", olderEntry.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/222/_history/1", olderEntry.getLinkSelf().getValue()); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = olderEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(20000L)); + InstantDt updActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = olderEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + // Newer resource + { + BundleEntry newerEntry = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/222", newerEntry.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/222/_history/2", newerEntry.getLinkSelf().getValue()); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = newerEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(30000L)); + InstantDt updActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = newerEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + + } + + @Test + public void testHistoryResourceType() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/_history"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(2, bundle.getEntries().size()); + + // Older resource + { + BundleEntry olderEntry = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/1", olderEntry.getId().getValue()); + assertThat(olderEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/1/_history/1")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = olderEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(20000L)); + InstantDt updActualRes = (InstantDt) olderEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = olderEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + // Newer resource + { + BundleEntry newerEntry = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/1", newerEntry.getId().getValue()); + assertThat(newerEntry.getLinkSelf().getValue(), StringEndsWith.endsWith("/Patient/1/_history/2")); + InstantDt pubExpected = new InstantDt(new Date(10000L)); + InstantDt pubActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED); + InstantDt pubActualBundle = newerEntry.getPublished(); + assertEquals(pubExpected.getValueAsString(), pubActualRes.getValueAsString()); + assertEquals(pubExpected.getValueAsString(), pubActualBundle.getValueAsString()); + InstantDt updExpected = new InstantDt(new Date(30000L)); + InstantDt updActualRes = (InstantDt) newerEntry.getResource().getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + InstantDt updActualBundle = newerEntry.getUpdated(); + assertEquals(updExpected.getValueAsString(), updActualRes.getValueAsString()); + assertEquals(updExpected.getValueAsString(), updActualBundle.getValueAsString()); + } + + } + + @Test + public void testReadOnTypeThatDoesntSupportRead() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/AdverseReaction/223"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(Constants.STATUS_HTTP_400_BAD_REQUEST, status.getStatusLine().getStatusCode()); + + } + + @Test + public void testSearchAll() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/AdverseReaction"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(2, bundle.getEntries().size()); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/AdverseReaction/_search"); + status = ourClient.execute(httpPost); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(2, bundle.getEntries().size()); + + } + + @Test + public void testSearchAllProfiles() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Profile?"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + // ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + IParser parser = ourCtx.newXmlParser().setPrettyPrint(true); + Bundle bundle = parser.parseBundle(responseContent); + + ourLog.info("Response:\n{}", parser.encodeBundleToString(bundle)); + + } + + @Test + public void testSearchByDob() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?dob=2011-01-02"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + Patient patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue()); + assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue()); + + /* + * With comparator + */ + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?dob=%3E%3D2011-01-02"); + status = ourClient.execute(httpGet); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals(">=", patient.getIdentifier().get(1).getValue().getValue()); + assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue()); + + } + + @Test + public void testSearchByDobWithSearchActionAndPost() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/_search?dob=2011-01-02"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + Patient patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue()); + assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue()); + + // POST + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?dob=2011-01-02"); + status = ourClient.execute(httpPost); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue()); + assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue()); + + // POST with form encoded + + httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search"); + List urlParameters = new ArrayList(); + urlParameters.add(new BasicNameValuePair("dob", "2011-01-02")); + httpPost.setEntity(new UrlEncodedFormEntity(urlParameters)); + status = ourClient.execute(httpPost); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("NONE", patient.getIdentifier().get(1).getValue().getValue()); + assertEquals("2011-01-02", patient.getIdentifier().get(2).getValue().getValue()); + + } + + @Test + public void testSearchByMultipleIdentifiers() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?ids=urn:aaa%7Caaa,urn:bbb%7Cbbb"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + Patient patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("urn:aaa|aaa", patient.getIdentifier().get(1).getValueAsQueryToken()); + assertEquals("urn:bbb|bbb", patient.getIdentifier().get(2).getValueAsQueryToken()); + } + + @Test + public void testSearchByParamIdentifier() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?identifier=urn:hapitest:mrns%7C00001"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + Patient patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + + /** + * Alternate form + */ + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search?identifier=urn:hapitest:mrns%7C00001"); + status = ourClient.execute(httpPost); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + + /** + * failing form + */ + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/_search?identifier=urn:hapitest:mrns%7C00001"); + status = ourClient.execute(httpGet); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + } + + @Test + public void testSearchNamedNoParams() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/?_query=someQueryNoParams"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Patient patient = (Patient) ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource(); + assertEquals("someQueryNoParams", patient.getName().get(1).getFamilyAsSingleString()); + + InstantDt lm = (InstantDt) patient.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED); + assertEquals("2011-01-02T22:01:02", lm.getValueAsString()); + + } + + @Test + public void testSearchNamedOneParam() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/?_query=someQueryOneParam¶m1=AAAA"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Patient patient = (Patient) ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource(); + assertEquals("AAAA", patient.getName().get(1).getFamilyAsSingleString()); + + } + + @Test + public void testSearchQuantityParam() throws Exception { + + // HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + + // "/Patient/1"); + // httpPost.setEntity(new StringEntity("test", + // ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/?quantityParam=%3E%3D123%7Cfoo%7Cbar"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Patient patient = (Patient) ourCtx.newXmlParser().parseBundle(responseContent).getEntries().get(0).getResource(); + assertEquals(">=", patient.getName().get(1).getFamily().get(0).getValue()); + assertEquals("123", patient.getName().get(1).getFamily().get(1).getValue()); + assertEquals("foo", patient.getName().get(1).getFamily().get(2).getValue()); + assertEquals("bar", patient.getName().get(1).getFamily().get(3).getValue()); + + } + + @Test + public void testSearchWithIncludes() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1&_include=include2&_include=include3"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + BundleEntry entry0 = bundle.getEntries().get(0); + Patient patient = (Patient) entry0.getResource(); + assertEquals("include1", patient.getCommunication().get(0).getText().getValue()); + assertEquals("include2", patient.getAddress().get(0).getLine().get(0).getValue()); + assertEquals("include3", patient.getAddress().get(1).getLine().get(0).getValue()); + } + + @Test + public void testSearchWithIncludesBad() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1&_include=include2&_include=include4"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(400, status.getStatusLine().getStatusCode()); + } + + @Test + public void testSearchWithIncludesNone() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?withIncludes=include1"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + // Make sure there is no crash + assertEquals(200, status.getStatusLine().getStatusCode()); + } + + @Test + public void testSearchWithOptionalParam() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name1=AAA"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + Patient patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("AAA", patient.getName().get(0).getFamily().get(0).getValue()); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + + /* + * Now with optional value populated + */ + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name1=AAA&name2=BBB"); + status = ourClient.execute(httpGet); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("AAA", patient.getName().get(0).getFamily().get(0).getValue()); + assertEquals("BBB", patient.getName().get(0).getGiven().get(0).getValue()); + + } + + @Test + public void testValidate() throws Exception { + + Patient patient = new Patient(); + patient.addName().addFamily("FOO"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + assertThat(responseContent, not(containsString("\n "))); + + assertEquals(200, status.getStatusLine().getStatusCode()); + OperationOutcome oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent); + assertEquals("it passed", oo.getIssueFirstRep().getDetails().getValue()); + + // Now should fail + + patient = new Patient(); + patient.addName().addFamily("BAR"); + + httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + status = ourClient.execute(httpPost); + + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(422, status.getStatusLine().getStatusCode()); + oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent); + assertEquals("it failed", oo.getIssueFirstRep().getDetails().getValue()); + + // Should fail with outcome + + patient = new Patient(); + patient.addName().addFamily("BAZ"); + + httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + status = ourClient.execute(httpPost); + + // responseContent = IOUtils.toString(status.getEntity().getContent()); + // ourLog.info("Response was:\n{}", responseContent); + + assertEquals(204, status.getStatusLine().getStatusCode()); + assertNull(status.getEntity()); + // assertEquals("", responseContent); + + } + + @Test + public void testValidateWithPrettyPrintResponse() throws Exception { + + Patient patient = new Patient(); + patient.addName().addFamily("FOO"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/_validate?_pretty=true"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + assertThat(responseContent, containsString("\n ")); + } + + @Test + public void testWithAdditionalParams() throws Exception { + + HttpDelete httpGet = new HttpDelete("http://localhost:" + ourPort + "/Patient/1234?_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + OperationOutcome patient = ourCtx.newXmlParser().parseResource(OperationOutcome.class, responseContent); + assertEquals("Patient/1234", patient.getIssueFirstRep().getDetails().getValue()); + + } + + @Test + public void testServerProfileProviderFindsProfiles() { + ServerProfileProvider profileProvider = (ServerProfileProvider)ourRestfulServer.getServerProfilesProvider(); + IdDt id = new IdDt("Profile", "observation"); + Profile profile = profileProvider.getProfileById(id); + assertNotNull(profile); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + ourCtx = new FhirContext(Patient.class); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + ServerProfileProvider profProvider = new ServerProfileProvider(ourCtx); + ourReportProvider = new DummyDiagnosticReportResourceProvider(); + DummyAdverseReactionResourceProvider adv = new DummyAdverseReactionResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + ourRestfulServer =new DummyRestfulServer(patientProvider, profProvider, ourReportProvider, adv); + ServletHolder servletHolder = new ServletHolder(ourRestfulServer); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyAdverseReactionResourceProvider implements IResourceProvider { + + @Search() + public Collection getAllResources() { + ArrayList retVal = new ArrayList(); + + AdverseReaction ar1 = new AdverseReaction(); + ar1.setId("1"); + retVal.add(ar1); + + AdverseReaction ar2 = new AdverseReaction(); + ar2.setId("2"); + retVal.add(ar2); + + return retVal; + } + + @Override + public Class getResourceType() { + return AdverseReaction.class; + } + + } + + public static class DummyDiagnosticReportResourceProvider implements IResourceProvider { + + + + /** + * @param theValue + */ + @Search + public DiagnosticReport alwaysThrow404(@RequiredParam(name = "throw404") StringDt theValue) { + throw new ResourceNotFoundException("AAAABBBB"); + } + + + @Delete() + public void deleteDiagnosticReport(@IdParam IdDt theId) { + // do nothing + } + + + + @Override + public Class getResourceType() { + return DiagnosticReport.class; + } + + + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + + @Delete() + public MethodOutcome deletePatient(@IdParam IdDt theId) { + MethodOutcome retVal = new MethodOutcome(); + retVal.setOperationOutcome(new OperationOutcome()); + retVal.getOperationOutcome().addIssue().setDetails(theId.getValue()); + return retVal; + } + + public List findDiagnosticReportsByPatient(@RequiredParam(name = "Patient.identifier") IdentifierDt thePatientId, + @RequiredParam(name = DiagnosticReport.SP_NAME) TokenOrListParam theNames, @OptionalParam(name = DiagnosticReport.SP_DATE) DateRangeParam theDateRange) throws Exception { + return Collections.emptyList(); + } + + @History + public List getHistoryResourceInstance(@IdParam IdDt theId) { + ArrayList retVal = new ArrayList(); + + IdDt id = theId; + if (id.getIdPart().equals("999")) { + id = null; // to test the error when no ID is present + } + + Patient older = createPatient1(); + older.setId(id); + older.getNameFirstRep().getFamilyFirstRep().setValue("OlderFamily"); + older.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, "1"); + older.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, new Date(10000L)); + older.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt(new Date(20000L))); + if (id != null && !id.getIdPart().equals("998")) { + older.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, "1"); + } + retVal.add(older); + + Patient newer = createPatient1(); + newer.setId(theId); + newer.getNameFirstRep().getFamilyFirstRep().setValue("NewerFamily"); + if (id != null && !id.getIdPart().equals("998")) { + newer.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, "2"); + } + newer.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, new Date(10000L)); + newer.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt(new Date(30000L))); + retVal.add(newer); + + return retVal; + } + + @History + public List getHistoryResourceType() { + ArrayList retVal = new ArrayList(); + + Patient older = createPatient1(); + older.getNameFirstRep().getFamilyFirstRep().setValue("OlderFamily"); + older.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, "1"); + older.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, new Date(10000L)); + older.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt(new Date(20000L))); + older.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, "1"); + retVal.add(older); + + Patient newer = createPatient1(); + newer.getNameFirstRep().getFamilyFirstRep().setValue("NewerFamily"); + newer.getResourceMetadata().put(ResourceMetadataKeyEnum.VERSION_ID, "2"); + newer.getResourceMetadata().put(ResourceMetadataKeyEnum.PUBLISHED, new Date(10000L)); + newer.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt(new Date(30000L))); + retVal.add(newer); + + return retVal; + } + + public Map getIdToPatient() { + Map idToPatient = new HashMap(); + { + Patient patient = createPatient1(); + idToPatient.put("1", patient); + } + { + Patient patient = new Patient(); + patient.getIdentifier().add(new IdentifierDt()); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00002"); + patient.getName().add(new HumanNameDt()); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientTwo"); + patient.getGender().setText("F"); + patient.getId().setValue("2"); + idToPatient.put("2", patient); + } + return idToPatient; + } + + @Search() + public Patient getPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) { + for (Patient next : getIdToPatient().values()) { + for (IdentifierDt nextId : next.getIdentifier()) { + if (nextId.matchesSystemAndValue(theIdentifier)) { + return next; + } + } + } + return null; + } + + @Search() + public Patient getPatientByDateRange(@RequiredParam(name = "dateRange") DateRangeParam theIdentifiers) { + Patient retVal = getIdToPatient().get("1"); + retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getLowerBound().getValueAsQueryToken()); + retVal.getName().get(0).addSuffix().setValue(theIdentifiers.getUpperBound().getValueAsQueryToken()); + return retVal; + } + + @Search() + public List getPatientMultipleIdentifiers(@RequiredParam(name = "ids") TokenOrListParam theIdentifiers) { + List retVal = new ArrayList(); + Patient next = getIdToPatient().get("1"); + + for (BaseCodingDt nextId : theIdentifiers.getListAsCodings()) { + next.getIdentifier().add(new IdentifierDt(nextId.getSystemElement().getValueAsString(), nextId.getCodeElement().getValue())); + } + + retVal.add(next); + + return retVal; + } + + @Search(queryName = "someQueryNoParams") + public Patient getPatientNoParams() { + Patient next = getIdToPatient().get("1"); + next.addName().addFamily("someQueryNoParams"); + next.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, new InstantDt("2011-01-02T22:01:02")); + return next; + } + + @Search(queryName = "someQueryOneParam") + public Patient getPatientOneParam(@RequiredParam(name = "param1") StringDt theParam) { + Patient next = getIdToPatient().get("1"); + next.addName().addFamily(theParam.getValue()); + return next; + } + + @Search() + public Patient getPatientQuantityParam(@RequiredParam(name = "quantityParam") QuantityDt theParam) { + Patient next = getIdToPatient().get("1"); + next.addName().addFamily(theParam.getComparator().getValueAsString()).addFamily(theParam.getValue().getValueAsString()).addFamily(theParam.getSystem().getValueAsString()) + .addFamily(theParam.getUnits().getValueAsString()); + return next; + } + + @Search() + public Patient getPatientWithDOB(@RequiredParam(name = "dob") DateParam theDob) { + Patient next = getIdToPatient().get("1"); + if (theDob.getComparator() != null) { + next.addIdentifier().setValue(theDob.getComparator().getCode()); + } else { + next.addIdentifier().setValue("NONE"); + } + next.addIdentifier().setValue(theDob.getValueAsString()); + return next; + } + + @Search() + public Patient getPatientWithIncludes(@RequiredParam(name = "withIncludes") StringDt theString, + @IncludeParam(allow = { "include1", "include2", "include3" }) List theIncludes) { + Patient next = getIdToPatient().get("1"); + + next.addCommunication().setText(theString.getValue()); + + for (Include line : theIncludes) { + next.addAddress().addLine(line.getValue()); + } + + return next; + } + + @Search() + public List getPatientWithOptionalName(@RequiredParam(name = "name1") StringDt theName1, @OptionalParam(name = "name2") StringDt theName2) { + List retVal = new ArrayList(); + Patient next = getIdToPatient().get("1"); + next.getName().get(0).getFamily().set(0, theName1); + if (theName2 != null) { + next.getName().get(0).getGiven().set(0, theName2); + } + retVal.add(next); + + return retVal; + } + + /** + * @param theName3 + */ + @Search() + public List getPatientWithOptionalName(@RequiredParam(name = "aaa") StringDt theName1, @OptionalParam(name = "bbb") StringDt theName2, @OptionalParam(name = "ccc") StringDt theName3) { + List retVal = new ArrayList(); + Patient next = getIdToPatient().get("1"); + next.getName().get(0).getFamily().set(0, theName1); + if (theName2 != null) { + next.getName().get(0).getGiven().set(0, theName2); + } + retVal.add(next); + + return retVal; + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Read() + public Patient read(@IdParam IdDt theId) { + return getIdToPatient().get(theId.getIdPart()); + } + + @Read(version=true) + public Patient vread(@IdParam IdDt theId) { + Patient retVal = getIdToPatient().get(theId.getIdPart()); + if (retVal == null) { + throw new ResourceNotFoundException("Couldn't find ID " + theId.getIdPart() + " - Valid IDs are: " + getIdToPatient().keySet()); + } + + List name = retVal.getName(); + HumanNameDt nameDt = name.get(0); + String value = theId.getVersionIdPart(); + nameDt.setText(value); + return retVal; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + + + + + @Validate() + public MethodOutcome validatePatient(@ResourceParam Patient thePatient) { + if (thePatient.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals("FOO")) { + MethodOutcome methodOutcome = new MethodOutcome(); + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDetails("it passed"); + methodOutcome.setOperationOutcome(oo); + return methodOutcome; + } + if (thePatient.getNameFirstRep().getFamilyFirstRep().getValueNotNull().equals("BAR")) { + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDetails("it failed"); + throw new UnprocessableEntityException(oo); + } + return new MethodOutcome(); + } + + private Patient createPatient1() { + Patient patient = new Patient(); + patient.addIdentifier(); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00001"); + patient.addName(); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientOne"); + patient.getGender().setText("M"); + patient.getId().setValue("1"); + return patient; + } + + } + + public static class DummyRestfulServer extends RestfulServer { + + private static final long serialVersionUID = 1L; + + private Collection myResourceProviders; + + public DummyRestfulServer(IResourceProvider... theResourceProviders) { + myResourceProviders = Arrays.asList(theResourceProviders); + } + + @Override + public Collection getResourceProviders() { + return myResourceProviders; + } + + @Override + public ISecurityManager getSecurityManager() { + return null; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResfulServerSelfReferenceTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResfulServerSelfReferenceTest.java new file mode 100644 index 00000000000..cefba40d599 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResfulServerSelfReferenceTest.java @@ -0,0 +1,216 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.HashMap; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.server.handler.ContextHandlerCollection; +import org.eclipse.jetty.servlet.ServletContextHandler; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.annotation.Create; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.rest.server.provider.ServerProfileProvider; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ResfulServerSelfReferenceTest { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResfulServerSelfReferenceTest.class); + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx; + + @BeforeClass + public static void beforeClass() throws Exception { + ourCtx = new FhirContext(Patient.class); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + } + + @Test + public void testContextWithSpace() throws Exception { + int port = PortUtil.findFreePort(); + Server server = new Server(port); + + RestfulServer restServer = new RestfulServer(); + restServer.setFhirContext(ourCtx); + restServer.setResourceProviders(new DummyPatientResourceProvider()); + + // ServletHandler proxyHandler = new ServletHandler(); + ServletHolder servletHolder = new ServletHolder(restServer); + + ServletContextHandler ch = new ServletContextHandler(); + ch.setContextPath("/root ctx/rcp2"); + ch.addServlet(servletHolder, "/fhir ctx/fcp2/*"); + + ContextHandlerCollection contexts = new ContextHandlerCollection(); + server.setHandler(contexts); + + server.setHandler(ch); + server.start(); + try { + + String baseUri = "http://localhost:" + port + "/root%20ctx/rcp2/fhir%20ctx/fcp2"; + String uri = baseUri + "/Patient?identifier=urn:hapitest:mrns%7C00001"; + HttpGet httpGet = new HttpGet(uri); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + } finally { + server.stop(); + } + + } + + @Test + public void testSearchByParamIdentifier() throws Exception { + int port = PortUtil.findFreePort(); + Server hServer = new Server(port); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + ServerProfileProvider profProvider = new ServerProfileProvider(ourCtx); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer server = new RestfulServer(); + server.setFhirContext(ourCtx); + server.setResourceProviders(patientProvider, profProvider); + ServletHolder servletHolder = new ServletHolder(server); + proxyHandler.addServletWithMapping(servletHolder, "/fhir/context/*"); + hServer.setHandler(proxyHandler); + hServer.start(); + try { + String baseUri = "http://localhost:" + port + "/fhir/context"; + String uri = baseUri + "/Patient?identifier=urn:hapitest:mrns%7C00001"; + HttpGet httpGet = new HttpGet(uri); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + + assertEquals(1, bundle.getEntries().size()); + + Patient patient = (Patient) bundle.getEntries().get(0).getResource(); + assertEquals("PatientOne", patient.getName().get(0).getGiven().get(0).getValue()); + + assertEquals(uri, bundle.getLinkSelf().getValue()); + assertEquals(baseUri, bundle.getLinkBase().getValue()); + } finally { + hServer.stop(); + } + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + public Map getIdToPatient() { + Map idToPatient = new HashMap(); + { + Patient patient = new Patient(); + patient.setId("1"); + patient.addIdentifier(); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00001"); + patient.addName(); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientOne"); + patient.getGender().setText("M"); + idToPatient.put("1", patient); + } + { + Patient patient = new Patient(); + patient.setId("2"); + patient.getIdentifier().add(new IdentifierDt()); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00002"); + patient.getName().add(new HumanNameDt()); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientTwo"); + patient.getGender().setText("F"); + idToPatient.put("2", patient); + } + return idToPatient; + } + + @Create + public MethodOutcome create(@ResourceParam Patient thePatient) { + return new MethodOutcome(thePatient.getId()); + } + + @Search() + public Patient getPatient(@RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) { + for (Patient next : getIdToPatient().values()) { + for (IdentifierDt nextId : next.getIdentifier()) { + if (nextId.matchesSystemAndValue(theIdentifier)) { + return next; + } + } + } + return null; + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Read() + public Patient getResourceById(@IdParam IdDt theId) { + return getIdToPatient().get(theId.getValue()); + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResourceMethodTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResourceMethodTest.java new file mode 100644 index 00000000000..e7cf6ee3313 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResourceMethodTest.java @@ -0,0 +1,124 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.method.IParameter; +import ca.uhn.fhir.rest.method.Request; +import ca.uhn.fhir.rest.method.SearchMethodBinding; +import ca.uhn.fhir.rest.method.SearchMethodBinding.RequestType; +import ca.uhn.fhir.rest.method.SearchParameter; + +public class ResourceMethodTest { + + private SearchMethodBinding rm; + + @Search + public Bundle foo() { + return null; + } + + @Before + public void before() throws NoSuchMethodException, SecurityException { + rm = new SearchMethodBinding(Patient.class, ResourceMethodTest.class.getMethod("foo"), new FhirContext(), null); + } + + @Test + public void testRequiredParamsMissing() { + List methodParams = new ArrayList(); + + methodParams.add(new SearchParameter("firstName", false)); + methodParams.add(new SearchParameter("lastName", false)); + methodParams.add(new SearchParameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("lastName"); + + assertEquals(false, rm.incomingServerRequestMatchesMethod(Request.withResourceAndParams("Patient", RequestType.GET, inputParams))); // False + } + + @Test + public void testRequiredParamsOnly() { + List methodParams = new ArrayList(); + + methodParams.add(new SearchParameter("firstName", false)); + methodParams.add(new SearchParameter("lastName", false)); + methodParams.add(new SearchParameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("mrn"); + assertEquals(true, rm.incomingServerRequestMatchesMethod(Request.withResourceAndParams("Patient", RequestType.GET, inputParams))); // True + } + + @Test + public void testMixedParams() { + List methodParams = new ArrayList(); + + methodParams.add(new SearchParameter("firstName", false)); + methodParams.add(new SearchParameter("lastName", false)); + methodParams.add(new SearchParameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("mrn"); + + assertEquals(true, rm.incomingServerRequestMatchesMethod(Request.withResourceAndParams("Patient", RequestType.GET, inputParams))); // True + } + + @Test + public void testAllParams() { + List methodParams = new ArrayList(); + + methodParams.add(new SearchParameter("firstName", false)); + methodParams.add(new SearchParameter("lastName", false)); + methodParams.add(new SearchParameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("lastName"); + inputParams.add("mrn"); + + Request params = Request.withResourceAndParams("Patient", RequestType.GET, inputParams); + boolean actual = rm.incomingServerRequestMatchesMethod(params); + assertTrue( actual); // True + } + + @Test + public void testAllParamsWithExtra() { + List methodParams = new ArrayList(); + + methodParams.add(new SearchParameter("firstName", false)); + methodParams.add(new SearchParameter("lastName", false)); + methodParams.add(new SearchParameter("mrn", true)); + + rm.setParameters(methodParams); + + Set inputParams = new HashSet(); + inputParams.add("firstName"); + inputParams.add("lastName"); + inputParams.add("mrn"); + inputParams.add("foo"); + + assertEquals(false, rm.incomingServerRequestMatchesMethod(Request.withResourceAndParams("Patient", RequestType.GET, inputParams))); // False + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResourceProviderWithNoMethodsTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResourceProviderWithNoMethodsTest.java new file mode 100644 index 00000000000..18a0b82d6bf --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ResourceProviderWithNoMethodsTest.java @@ -0,0 +1,106 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import javax.servlet.ServletException; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.Test; + +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Binary; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.util.PortUtil; + +public class ResourceProviderWithNoMethodsTest { + + private Server ourServer; + + @After + public void after() throws Exception { + ourServer.stop(); + } + + @Test + public void testNoAnnotatedMethods() throws Exception { + int port = PortUtil.findFreePort(); + ourServer = new Server(port); + + ResourceProvider patientProvider = new ResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + + try { + ourServer.start(); + fail(); + } catch (ServletException e) { + assertEquals(e.getCause().getClass(), ConfigurationException.class); + } + } + + @Test + public void testNonPublicMethod() throws Exception { + int port = PortUtil.findFreePort(); + ourServer = new Server(port); + + NonPublicMethodProvider patientProvider = new NonPublicMethodProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + + try { + ourServer.start(); + fail(); + } catch (ServletException e) { + assertEquals(e.getCause().getClass(), ConfigurationException.class); + } + } + + public static class ResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Binary.class; + } + + public Binary read(@IdParam IdDt theId) { + Binary retVal = new Binary(); + retVal.setContent(new byte[] { 1, 2, 3, 4 }); + retVal.setContentType(theId.getIdPart()); + return retVal; + } + + } + + public static class NonPublicMethodProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Binary.class; + } + + @Read + protected Binary read(@IdParam IdDt theId) { + Binary retVal = new Binary(); + retVal.setContent(new byte[] { 1, 2, 3, 4 }); + retVal.setContentType(theId.getIdPart()); + return retVal; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/SearchTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/SearchTest.java new file mode 100644 index 00000000000..965b3ed80b1 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/SearchTest.java @@ -0,0 +1,383 @@ +package ca.uhn.fhir.rest.server; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.NameValuePair; +import org.apache.http.client.entity.UrlEncodedFormEntity; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.apache.http.message.BasicNameValuePair; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.google.common.net.UrlEscapers; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; +import ca.uhn.fhir.model.dstu.composite.CodingDt; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.ReferenceParam; +import ca.uhn.fhir.rest.param.StringOrListParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; +import ca.uhn.fhir.rest.param.TokenParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class SearchTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchTest.class); + private static int ourPort; + + private static Server ourServer; + + @Test + public void testOmitEmptyOptionalParam() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id="); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(null, p.getNameFirstRep().getFamilyFirstRep().getValue()); + } + + @Test + public void testReturnLinks() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=findWithLinks"); + + CloseableHttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue()); + assertEquals("http://foo/Patient?_id=1", bundle.getEntries().get(0).getLinkSearch().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/9988", bundle.getEntries().get(0).getLinkAlternate().getValue()); + + assertEquals("http://foo/Patient?_id=1", ResourceMetadataKeyEnum.LINK_SEARCH.get(p)); + assertEquals("http://localhost:" + ourPort + "/Patient/9988", ResourceMetadataKeyEnum.LINK_ALTERNATE.get(p)); + + } + + @Test + public void testSearchById() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString()); + assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue()); + } + + @Test + public void testSearchWithOrList() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?findPatientWithOrList=aaa,bbb"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("aaa", p.getIdentifier().get(0).getValue().getValue()); + assertEquals("bbb", p.getIdentifier().get(1).getValue().getValue()); + } + + @Test + public void testSearchWithTokenParameter() throws Exception { + String token = UrlEscapers.urlFragmentEscaper().asFunction().apply("http://www.dmix.gov/vista/2957|301"); + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?tokenParam="+token); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("http://www.dmix.gov/vista/2957", p.getNameFirstRep().getFamilyAsSingleString()); + assertEquals("301", p.getNameFirstRep().getGivenAsSingleString()); + } + + + @Test + public void testSearchByPost() throws Exception { + HttpPost filePost = new HttpPost("http://localhost:" + ourPort + "/Patient/_search"); + + // add parameters to the post method + List parameters = new ArrayList(); + parameters.add(new BasicNameValuePair("_id", "aaa")); + + UrlEncodedFormEntity sendentity = new UrlEncodedFormEntity(parameters, "UTF-8"); + filePost.setEntity(sendentity); + + HttpResponse status = ourClient.execute(filePost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("idaaa", p.getNameFirstRep().getFamilyAsSingleString()); + assertEquals("IDAAA (identifier123)", bundle.getEntries().get(0).getTitle().getValue()); + } + + @Test + public void testSearchCompartment() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/123/fooCompartment"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + ourLog.info(responseContent); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("fooCompartment", p.getIdentifierFirstRep().getValue().getValue()); + assertThat(bundle.getEntries().get(0).getId().getValue(), containsString("Patient/123")); + } + + @Test + public void testSearchGetWithUnderscoreSearch() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/_search?subject%3APatient=100&name=3141-9%2C8302-2%2C8287-5%2C39156-5"); + + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Observation p = bundle.getResources(Observation.class).get(0); + assertEquals("Patient/100", p.getSubject().getReference().toString()); + assertEquals(4, p.getName().getCoding().size()); + assertEquals("3141-9", p.getName().getCoding().get(0).getCode().getValue()); + assertEquals("8302-2", p.getName().getCoding().get(1).getCode().getValue()); + + } + + @Test + public void testSpecificallyNamedQueryGetsPrecedence() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?AAA=123"); + + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals("AAA", p.getIdentifierFirstRep().getValue().getValue()); + + // Now the named query + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=findPatientByAAA&AAA=123"); + + status = ourClient.execute(httpGet); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + assertEquals(200, status.getStatusLine().getStatusCode()); + bundle = ourCtx.newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.getEntries().size()); + + p = bundle.getResources(Patient.class).get(0); + assertEquals("AAANamed", p.getIdentifierFirstRep().getValue().getValue()); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.getFhirContext().setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator()); + + servlet.setResourceProviders(patientProvider, new DummyObservationResourceProvider()); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + public static class DummyObservationResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Observation.class; + } + + @Search + public Observation search(@RequiredParam(name = "subject") ReferenceParam theSubject, @RequiredParam(name = "name") TokenOrListParam theName) { + Observation o = new Observation(); + o.setId("1"); + + o.getSubject().setReference(theSubject.getResourceType() + "/" + theSubject.getIdPart()); + for (BaseCodingDt next : theName.getListAsCodings()) { + o.getName().getCoding().add(new CodingDt(next)); + } + + return o; + } + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Search(compartmentName = "fooCompartment") + public List compartment(@IdParam IdDt theId) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId(theId); + patient.addIdentifier("system", "fooCompartment"); + retVal.add(patient); + return retVal; + } + + @Search + public List findPatient(@RequiredParam(name = "_id") StringParam theParam) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("1"); + patient.addIdentifier("system", "identifier123"); + if (theParam != null) { + patient.addName().addFamily("id" + theParam.getValue()); + } + retVal.add(patient); + return retVal; + } + + @Search + public List findPatientByAAA01(@RequiredParam(name = "AAA") StringParam theParam) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("1"); + patient.addIdentifier("system", "AAA"); + retVal.add(patient); + return retVal; + } + + @Search(queryName = "findPatientByAAA") + public List findPatientByAAA02Named(@OptionalParam(name = "AAA") StringParam theParam) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("1"); + patient.addIdentifier("system", "AAANamed"); + retVal.add(patient); + return retVal; + } + + @Search() + public List findPatientWithOrList(@RequiredParam(name = "findPatientWithOrList") StringOrListParam theParam) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("1"); + for (StringParam next : theParam.getValuesAsQueryTokens()) { + patient.addIdentifier("system", next.getValue()); + } + retVal.add(patient); + return retVal; + } + + + @Search() + public List findPatientWithToken(@RequiredParam(name = "tokenParam") TokenParam theParam) { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("1"); + patient.addName().addFamily(theParam.getSystem()).addGiven(theParam.getValue()); + retVal.add(patient); + return retVal; + } + + + @Search(queryName = "findWithLinks") + public List findWithLinks() { + ArrayList retVal = new ArrayList(); + + Patient patient = new Patient(); + patient.setId("1"); + patient.addIdentifier("system", "AAANamed"); + ResourceMetadataKeyEnum.LINK_SEARCH.put(patient, ("http://foo/Patient?_id=1")); + ResourceMetadataKeyEnum.LINK_ALTERNATE.put(patient, ("Patient/9988")); + retVal.add(patient); + return retVal; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerBaseTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerBaseTest.java new file mode 100644 index 00000000000..1e98cb7b04a --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerBaseTest.java @@ -0,0 +1,179 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.After; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ServerBaseTest { + + private static CloseableHttpClient ourClient; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerBaseTest.class); + private Server myServer; + private static FhirContext ourCtx = new FhirContext(); + + @Test + public void testTransaction() throws Exception { + + } + + @After + public void after() throws Exception { + if (myServer != null) { + myServer.stop(); + } + } + + @Test + public void testWithContextPath() throws Exception { + int port = PortUtil.findFreePort(); + myServer = new Server(port); + + DummyProvider patientProvider = new DummyProvider(); + RestfulServer server = new RestfulServer(ourCtx); + server.setProviders(patientProvider); + + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); + proxyHandler.setContextPath("/ctx"); + + ServletHolder handler = new ServletHolder(); + handler.setServlet(server); + proxyHandler.addServlet(handler, "/*"); + + myServer.setHandler(proxyHandler); + myServer.start(); + + // test + + HttpGet httpPost = new HttpGet("http://localhost:" + port + "/ctx/Patient?_pretty=true"); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + BundleEntry entry = bundle.getEntries().get(0); + assertEquals("http://localhost:" + port + "/ctx/Patient/123", entry.getId().getValue()); + assertEquals("http://localhost:" + port + "/ctx/Patient/123/_history/456", entry.getLinkSelf().getValue()); + } + + + @Test + public void testWithContextAndServletPath() throws Exception { + int port = PortUtil.findFreePort(); + myServer = new Server(port); + + DummyProvider patientProvider = new DummyProvider(); + RestfulServer server = new RestfulServer(ourCtx); + server.setProviders(patientProvider); + + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); + proxyHandler.setContextPath("/ctx"); + + ServletHolder handler = new ServletHolder(); + handler.setServlet(server); + proxyHandler.addServlet(handler, "/servlet/*"); + + myServer.setHandler(proxyHandler); + myServer.start(); + + // test + + HttpGet httpPost = new HttpGet("http://localhost:" + port + "/ctx/servlet/Patient?_pretty=true"); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + BundleEntry entry = bundle.getEntries().get(0); + assertEquals("http://localhost:" + port + "/ctx/servlet/Patient/123", entry.getId().getValue()); + assertEquals("http://localhost:" + port + "/ctx/servlet/Patient/123/_history/456", entry.getLinkSelf().getValue()); + } + + @Test + public void testWithNoPath() throws Exception { + int port = PortUtil.findFreePort(); + myServer = new Server(port); + + DummyProvider patientProvider = new DummyProvider(); + RestfulServer server = new RestfulServer(ourCtx); + server.setProviders(patientProvider); + + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); + proxyHandler.setContextPath("/"); + + ServletHolder handler = new ServletHolder(); + handler.setServlet(server); + proxyHandler.addServlet(handler, "/*"); + + myServer.setHandler(proxyHandler); + myServer.start(); + + // test + + HttpGet httpPost = new HttpGet("http://localhost:" + port + "/Patient?_pretty=true"); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + ourLog.info(responseContent); + assertEquals(200, status.getStatusLine().getStatusCode()); + + Bundle bundle = ourCtx.newXmlParser().parseBundle(responseContent); + BundleEntry entry = bundle.getEntries().get(0); + assertEquals("http://localhost:" + port + "/Patient/123", entry.getId().getValue()); + assertEquals("http://localhost:" + port + "/Patient/123/_history/456", entry.getLinkSelf().getValue()); + } + @BeforeClass + public static void beforeClass() { + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyProvider implements IResourceProvider { + + @Search + public List search() { + Patient p = new Patient(); + p.setId(new IdDt("Patient", "123", "456")); + p.addIdentifier("urn:system", "12345"); + return Collections.singletonList(p); + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderTest.java new file mode 100644 index 00000000000..582e1d805a9 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerConformanceProviderTest.java @@ -0,0 +1,203 @@ +package ca.uhn.fhir.rest.server; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +import java.util.Collection; +import java.util.List; +import java.util.Set; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Conformance; +import ca.uhn.fhir.model.dstu.resource.Conformance.Rest; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestQuery; +import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.annotation.IncludeParam; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.method.BaseMethodBinding; +import ca.uhn.fhir.rest.method.SearchMethodBinding; +import ca.uhn.fhir.rest.method.SearchParameter; +import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; +import ca.uhn.fhir.rest.server.provider.ServerConformanceProvider; + +public class ServerConformanceProviderTest { + + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ServerConformanceProviderTest.class); + private FhirContext myCtx = new FhirContext(); + + @Test + public void testSearchParameterDocumentation() throws Exception { + + RestfulServer rs = new RestfulServer(); + rs.setProviders(new SearchProvider()); + + ServerConformanceProvider sc = new ServerConformanceProvider(rs); + rs.setServerConformanceProvider(sc); + + rs.init(null); + + boolean found=false; + Collection resourceBindings = rs.getResourceBindings(); + for (ResourceBinding resourceBinding : resourceBindings) { + if (resourceBinding.getResourceName().equals("Patient")) { + List> methodBindings = resourceBinding.getMethodBindings(); + SearchMethodBinding binding = (SearchMethodBinding) methodBindings.get(0); + SearchParameter param = (SearchParameter) binding.getParameters().iterator().next(); + assertEquals("The patient's identifier (MRN or other card number)", param.getDescription()); + found=true; + } + } + assertTrue(found); + Conformance conformance = sc.getServerConformance(); + + String conf = myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); + ourLog.info(conf); + + assertThat(conf, containsString("")); + assertThat(conf, containsString("")); + + } + + + @Test + public void testValidateGeneratedStatement() throws Exception { + + RestfulServer rs = new RestfulServer(); + rs.setProviders(new MultiOptionalProvider()); + + ServerConformanceProvider sc = new ServerConformanceProvider(rs); + rs.setServerConformanceProvider(sc); + + rs.init(null); + + Conformance conformance = sc.getServerConformance(); + + myCtx.newValidator().validate(conformance); + } + + + + @Test + public void testMultiOptionalDocumentation() throws Exception { + + RestfulServer rs = new RestfulServer(); + rs.setProviders(new MultiOptionalProvider()); + + ServerConformanceProvider sc = new ServerConformanceProvider(rs); + rs.setServerConformanceProvider(sc); + + rs.init(null); + + boolean found=false; + Collection resourceBindings = rs.getResourceBindings(); + for (ResourceBinding resourceBinding : resourceBindings) { + if (resourceBinding.getResourceName().equals("Patient")) { + List> methodBindings = resourceBinding.getMethodBindings(); + SearchMethodBinding binding = (SearchMethodBinding) methodBindings.get(0); + SearchParameter param = (SearchParameter) binding.getParameters().iterator().next(); + assertEquals("The patient's identifier", param.getDescription()); + found=true; + } + } + assertTrue(found); + Conformance conformance = sc.getServerConformance(); + String conf = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); + ourLog.info(conf); + + assertThat(conf, containsString("")); + assertThat(conf, containsString("")); + assertThat(conf, containsString("")); + } + + @Test + public void testProviderWithRequiredAndOptional() throws Exception { + + RestfulServer rs = new RestfulServer(); + rs.setProviders(new ProviderWithRequiredAndOptional()); + + ServerConformanceProvider sc = new ServerConformanceProvider(rs); + rs.setServerConformanceProvider(sc); + + rs.init(null); + + Conformance conformance = sc.getServerConformance(); + String conf = new FhirContext().newXmlParser().setPrettyPrint(true).encodeResourceToString(conformance); + ourLog.info(conf); + + Rest rest = conformance.getRestFirstRep(); + RestResource res = rest.getResourceFirstRep(); + assertEquals("DiagnosticReport", res.getType().getValueAsString()); + + RestQuery p0 = rest.getQueryFirstRep(); + assertEquals("subject.identifier", p0.getParameterFirstRep().getName().getValue()); + + assertEquals(1,res.getSearchInclude().size()); + assertEquals("DiagnosticReport.result", res.getSearchIncludeFirstRep().getValue()); + } + + + /** + * Created by dsotnikov on 2/25/2014. + */ + @SuppressWarnings("unused") + public static class SearchProvider { + + @Search(type = Patient.class) + public Patient findPatient( + @Description(shortDefinition = "The patient's identifier (MRN or other card number)") + @RequiredParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier) { + return null; + } + + } + + + /** + * Created by dsotnikov on 2/25/2014. + */ + @SuppressWarnings("unused") + public static class MultiOptionalProvider { + + @Search(type = Patient.class) + public Patient findPatient( + @Description(shortDefinition = "The patient's identifier") + @OptionalParam(name = Patient.SP_IDENTIFIER) IdentifierDt theIdentifier, + @Description(shortDefinition = "The patient's name") + @OptionalParam(name=Patient.SP_NAME) StringDt theName) { + return null; + } + + } + + + public static class ProviderWithRequiredAndOptional { + + @Description(shortDefinition="This is a search for stuff!") + @Search + public List findDiagnosticReportsByPatient ( + @RequiredParam(name=DiagnosticReport.SP_SUBJECT + '.' + Patient.SP_IDENTIFIER) IdentifierDt thePatientId, + @OptionalParam(name=DiagnosticReport.SP_NAME) TokenOrListParam theNames, + @OptionalParam(name=DiagnosticReport.SP_DATE) DateRangeParam theDateRange, + @IncludeParam(allow= {"DiagnosticReport.result"}) Set theIncludes + ) throws Exception { + return null; + } + + + } + + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerExtraParametersTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerExtraParametersTest.java new file mode 100644 index 00000000000..ae0d9f27a97 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerExtraParametersTest.java @@ -0,0 +1,133 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hamcrest.core.StringContains; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.ServerBase; +import ca.uhn.fhir.rest.client.IGenericClient; +import ca.uhn.fhir.rest.client.api.IBasicClient; +import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; +import ca.uhn.fhir.rest.gclient.StringClientParam; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; +import ca.uhn.fhir.util.PortUtil; + +public class ServerExtraParametersTest { + + private int myPort; + private Server myServer; + private RestfulServer myServlet; + + @Before + public void before() { + myPort = PortUtil.findFreePort(); + myServer = new Server(myPort); + + ServletHandler proxyHandler = new ServletHandler(); + myServlet = new RestfulServer(); + ServletHolder servletHolder = new ServletHolder(myServlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + myServer.setHandler(proxyHandler); + + } + + @Test + public void testServerBase() throws Exception { + MyServerBaseProvider patientProvider = new MyServerBaseProvider(); + myServlet.setResourceProviders(patientProvider); + + myServer.start(); + + FhirContext ctx = new FhirContext(); + PatientClient client = ctx.newRestfulClient(PatientClient.class, "http://localhost:" + myPort + "/"); + + List actualPatients = client.searchForPatients(new StringDt("AAAABBBB")); + assertEquals(1, actualPatients.size()); + assertEquals("AAAABBBB", actualPatients.get(0).getNameFirstRep().getFamilyAsSingleString()); + + assertEquals("http://localhost:" + myPort, patientProvider.getServerBase()); + } + + @Test + public void testNonRepeatableParam() throws Exception { + MyServerBaseProvider patientProvider = new MyServerBaseProvider(); + myServlet.setResourceProviders(patientProvider); + + myServer.start(); + + FhirContext ctx = new FhirContext(); + IGenericClient client = ctx.newRestfulGenericClient("http://localhost:" + myPort + "/"); + client.registerInterceptor(new LoggingInterceptor(true)); + + try { + client.search().forResource("Patient").where(new StringClientParam("singleParam").matches().values(Arrays.asList("AA", "BB"))).execute(); + fail(); + } catch (InvalidRequestException e) { + assertThat( + e.getMessage(), + StringContains + .containsString("HTTP 400 Bad Request: Multiple values detected for non-repeatable parameter 'singleParam'. This server is not configured to allow multiple (AND/OR) values for this param.")); + } + } + + @After + public void after() throws Exception { + myServer.stop(); + } + + public static class MyServerBaseProvider implements IResourceProvider { + private String myServerBase; + + public String getServerBase() { + return myServerBase; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Search + public List searchSingleParam(@RequiredParam(name = "singleParam") StringParam theFooParam) { + Patient retVal = new Patient(); + retVal.setId("1"); + return Collections.singletonList(retVal); + } + + @Search + public List searchForPatients(@RequiredParam(name = "fooParam") StringDt theFooParam, @ServerBase String theServerBase) { + myServerBase = theServerBase; + + Patient retVal = new Patient(); + retVal.setId("1"); + retVal.addName().addFamily(theFooParam.getValue()); + return Collections.singletonList(retVal); + } + + } + + private static interface PatientClient extends IBasicClient { + + @Search + public List searchForPatients(@RequiredParam(name = "fooParam") StringDt theFooParam); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerFeaturesTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerFeaturesTest.java new file mode 100644 index 00000000000..b8cd559dd57 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerFeaturesTest.java @@ -0,0 +1,369 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hamcrest.core.IsNot; +import org.hamcrest.core.StringContains; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class ServerFeaturesTest { + + private static CloseableHttpClient ourClient; + private static int ourPort; + private static Server ourServer; + private static RestfulServer servlet; + + @Test + public void testPrettyPrint() throws Exception { + /* + * Not specified + */ + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertThat(responseContent, StringContains.containsString("http://foo/bar/Patient/1")); + + } + + @Test + public void testAcceptHeaderWithPrettyPrint() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + httpGet.addHeader("Accept", Constants.CT_FHIR_XML + "; pretty=true"); + CloseableHttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertThat(responseContent, StringContains.containsString("\n ")); + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + httpGet.addHeader("Accept", Constants.CT_FHIR_JSON + "; pretty=true"); + status = ourClient.execute(httpGet); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertThat(responseContent, StringContains.containsString("\",\n")); + + httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + httpGet.addHeader("Accept", Constants.CT_FHIR_JSON + "; pretty=true" + ", " + Constants.CT_FHIR_XML + "; pretty=true"); + status = ourClient.execute(httpGet); + responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertThat(responseContent, StringContains.containsString("\"identifier\":")); + + } + + @Test + public void testInternalErrorIfNoId() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/?_query=findPatientsWithNoIdSpecified"); + httpGet.addHeader("Accept", Constants.CT_FHIR_XML + "; pretty=true"); + CloseableHttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(500, status.getStatusLine().getStatusCode()); + assertThat(responseContent, StringContains.containsString("ID")); + + } + + @Test + public void testSearchWithWildcardRetVal() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/?_query=searchWithWildcardRetVal"); + httpGet.addHeader("Accept", Constants.CT_FHIR_XML + "; pretty=true"); + CloseableHttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertThat(responseContent, StringContains.containsString("searchWithWildcardRetVal")); + + } + + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @Before + public void before() { + servlet.setServerAddressStrategy(new IncomingRequestAddressStrategy()); + } + + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + public Map getIdToPatient() { + Map idToPatient = new HashMap(); + { + Patient patient = createPatient1(); + idToPatient.put("1", patient); + } + { + Patient patient = new Patient(); + patient.getIdentifier().add(new IdentifierDt()); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00002"); + patient.getName().add(new HumanNameDt()); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientTwo"); + patient.getGender().setText("F"); + patient.getId().setValue("2"); + idToPatient.put("2", patient); + } + return idToPatient; + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Read() + public Patient getResourceById(@IdParam IdDt theId) { + String key = theId.getIdPart(); + Patient retVal = getIdToPatient().get(key); + return retVal; + } + + + @Search(queryName="searchWithWildcardRetVal") + public List searchWithWildcardRetVal() { + Patient p = new Patient(); + p.setId("1234"); + p.addName().addFamily("searchWithWildcardRetVal"); + return Collections.singletonList(p); + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Search() + public List getResourceById(@RequiredParam(name = "_id") String theId) { + Patient patient = getIdToPatient().get(theId); + if (patient != null) { + return Collections.singletonList(patient); + } else { + return Collections.emptyList(); + } + } + + @Search(queryName = "findPatientsWithNoIdSpecified") + public List findPatientsWithNoIdSpecified() { + Patient p = new Patient(); + p.addIdentifier().setSystem("foo"); + return Collections.singletonList(p); + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + private Patient createPatient1() { + Patient patient = new Patient(); + patient.addIdentifier(); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00001"); + patient.addName(); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientOne"); + patient.getGender().setText("M"); + patient.getId().setValue("1"); + return patient; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerInvalidDefinitionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerInvalidDefinitionTest.java new file mode 100644 index 00000000000..fa53d6d58fe --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/ServerInvalidDefinitionTest.java @@ -0,0 +1,159 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.List; + +import javax.servlet.ServletException; + +import org.hamcrest.core.StringContains; +import org.junit.Test; + +import ca.uhn.fhir.model.api.BaseResource; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.StringParam; + +public class ServerInvalidDefinitionTest { + + @Test + public void testPrivateResourceProvider() { + RestfulServer srv = new RestfulServer(); + srv.setResourceProviders(new PrivateResourceProvider()); + + try { + srv.init(); + fail(); + } catch (ServletException e) { + assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException")); + assertThat(e.getCause().toString(), StringContains.containsString("public")); + } + } + + @Test + public void testInvalidSpecialNameResourceProvider() { + RestfulServer srv = new RestfulServer(); + srv.setResourceProviders(new InvalidSpecialParameterNameResourceProvider()); + + try { + srv.init(); + fail(); + } catch (ServletException e) { + assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException")); + assertThat(e.getCause().toString(), StringContains.containsString("_pretty")); + } + } + + @Test + public void testReadMethodWithSearchParameters() { + RestfulServer srv = new RestfulServer(); + srv.setResourceProviders(new ReadMethodWithSearchParamProvider()); + + try { + srv.init(); + fail(); + } catch (ServletException e) { + assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException")); + } + } + + @Test + public void testSearchWithId() { + RestfulServer srv = new RestfulServer(); + srv.setResourceProviders(new SearchWithIdParamProvider()); + + try { + srv.init(); + fail(); + } catch (ServletException e) { + assertThat(e.getCause().toString(), StringContains.containsString("ConfigurationException")); + assertThat(e.getCause().toString(), StringContains.containsString("compartment")); + } + } + + /** + * Normal, should initialize properly + */ + @Test() + public void testBaseline() throws ServletException { + RestfulServer srv = new RestfulServer(); + srv.setResourceProviders(new InstantiableTypeForResourceProvider()); + srv.init(); + } + + private static class PrivateResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Read + public Patient read(@IdParam IdDt theId) { + return null; + } + + } + + public static class ReadMethodWithSearchParamProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Read + public Patient read(@IdParam IdDt theId, @RequiredParam(name = "aaa") StringParam theParam) { + return null; + } + + } + + public static class SearchWithIdParamProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Search + public List read(@IdParam IdDt theId, @RequiredParam(name = "aaa") StringParam theParam) { + return null; + } + + } + + public static class InvalidSpecialParameterNameResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Search + public List search(@RequiredParam(name = "_pretty") StringParam theParam) { + return null; + } + + } + + public static class InstantiableTypeForResourceProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + @Read + public Patient read(@IdParam IdDt theId) { + return null; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/SortTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/SortTest.java new file mode 100644 index 00000000000..fe49b53e367 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/SortTest.java @@ -0,0 +1,183 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.annotation.Sort; +import ca.uhn.fhir.rest.api.SortSpec; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class SortTest { + + private static CloseableHttpClient ourClient; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SortTest.class); + private static int ourPort; + private static Server ourServer; + + @Test + public void testNoSort() throws Exception { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(1, p.getName().size()); + assertEquals("Hello", p.getNameFirstRep().getFamilyFirstRep().getValue()); + } + + @Test + public void testSingleSort() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_sort=given"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(2, p.getName().size()); + assertEquals("Hello", p.getNameFirstRep().getFamilyFirstRep().getValue()); + assertEquals("given|null", p.getName().get(1).getFamilyFirstRep().getValue()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_sort:asc=given"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(2, p.getName().size()); + assertEquals("Hello", p.getNameFirstRep().getFamilyFirstRep().getValue()); + assertEquals("given|ASC", p.getName().get(1).getFamilyFirstRep().getValue()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_sort:desc=given"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(2, p.getName().size()); + assertEquals("Hello", p.getNameFirstRep().getFamilyFirstRep().getValue()); + assertEquals("given|DESC", p.getName().get(1).getFamilyFirstRep().getValue()); + } + + } + + @Test + public void testSortChain() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?name=Hello&_sort=given&_sort=family&_sort=name"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(1, bundle.size()); + + Patient p = bundle.getResources(Patient.class).get(0); + assertEquals(4, p.getName().size()); + assertEquals("Hello", p.getNameFirstRep().getFamilyFirstRep().getValue()); + assertEquals("given|null", p.getName().get(1).getFamilyFirstRep().getValue()); + assertEquals("family|null", p.getName().get(2).getFamilyFirstRep().getValue()); + assertEquals("name|null", p.getName().get(3).getFamilyFirstRep().getValue()); + } + + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Search + public List findPatient(@RequiredParam(name = Patient.SP_NAME) StringDt theName, @Sort SortSpec theSort) { + ArrayList retVal = new ArrayList(); + + Patient p = new Patient(); + p.setId("1"); + p.addName().addFamily().setValue(theName.getValue()); + SortSpec sort = theSort; + while (sort != null) { + p.addName().addFamily().setValue(sort.getParamName() + "|" + sort.getOrder()); + sort = sort.getChain(); + } + + retVal.add(p); + + return retVal; + } + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/StringParameterTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/StringParameterTest.java new file mode 100644 index 00000000000..eeeb582c0c1 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/StringParameterTest.java @@ -0,0 +1,233 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.rest.annotation.OptionalParam; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class StringParameterTest { + + private static CloseableHttpClient ourClient; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(StringParameterTest.class); + private static int ourPort; + private static Server ourServer; + + @Test + public void testSearchWithFormatAndPretty() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=aaa&_format=xml&_pretty=true"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(1, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + } + + @Test + public void testSearchNormalMatch() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(1, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=AAA"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(1, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str=BBB"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(0, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + } + + @Test + public void testRawString() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?plain=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(1, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?plain=BBB"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(0, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + } + + @Test + public void testSearchExactMatch() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str:exact=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(1, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str:exact=AAA"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(0, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?str:exact=BBB"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(0, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + } + + @Test + public void testSearchExactMatchOptional() throws Exception { + { + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?ccc:exact=aaa"); + HttpResponse status = ourClient.execute(httpGet); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals(1, new FhirContext().newXmlParser().parseBundle(responseContent).getEntries().size()); + } + } + + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + @Search + public List findPatientByStringParam(@RequiredParam(name = "str") StringParam theParam) { + ArrayList retVal = new ArrayList(); + + if (theParam.isExact() && theParam.getValue().equals("aaa")) { + Patient patient = new Patient(); + patient.setId("1"); + retVal.add(patient); + } + if (!theParam.isExact() && theParam.getValue().toLowerCase().equals("aaa")) { + Patient patient = new Patient(); + patient.setId("2"); + retVal.add(patient); + } + + return retVal; + } + + @Search + public List findPatientByString(@RequiredParam(name = "plain") String theParam) { + ArrayList retVal = new ArrayList(); + + if (theParam.toLowerCase().equals("aaa")) { + Patient patient = new Patient(); + patient.setId("1"); + retVal.add(patient); + } + + return retVal; + } + + @Search + public List findPatientWithOptional(@OptionalParam(name = "ccc") StringParam theParam) { + ArrayList retVal = new ArrayList(); + + if (theParam.isExact() && theParam.getValue().equals("aaa")) { + Patient patient = new Patient(); + patient.setId("1"); + retVal.add(patient); + } + if (!theParam.isExact() && theParam.getValue().toLowerCase().equals("aaa")) { + Patient patient = new Patient(); + patient.setId("2"); + retVal.add(patient); + } + + return retVal; + } + + + @Override + public Class getResourceType() { + return Patient.class; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TagsServerTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TagsServerTest.java new file mode 100644 index 00000000000..1fa5a8f7739 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TagsServerTest.java @@ -0,0 +1,319 @@ +package ca.uhn.fhir.rest.server; + +import static org.apache.commons.lang.StringUtils.defaultString; +import static org.junit.Assert.assertEquals; + +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.AddTags; +import ca.uhn.fhir.rest.annotation.DeleteTags; +import ca.uhn.fhir.rest.annotation.GetTags; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.TagListParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class TagsServerTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx; + private static String ourLastOutcome; + private static TagList ourLastTagList; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TagsServerTest.class); + private static int ourPort; + private static DummyProvider ourProvider; + private static Server ourServer; + + @Before + public void before() { + ourLastOutcome = null; + ourLastTagList = null; + } + + @Test + public void testAddTagsById() throws Exception { + + TagList tagList = new TagList(); + tagList.addTag("scheme", "term", "label"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/111/_tags"); + httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeTagListToString(tagList), ContentType.create(EncodingEnum.JSON.getResourceContentType(), "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("add111", ourLastOutcome); + assertEquals(tagList, ourLastTagList); + } + + @Test + public void testAddTagsByIdAndVersion() throws Exception { + + TagList tagList = new TagList(); + tagList.addTag("scheme", "term", "label"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/111/_history/222/_tags"); + httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeTagListToString(tagList), ContentType.create(EncodingEnum.JSON.getResourceContentType(), "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("add111222", ourLastOutcome); + assertEquals(tagList, ourLastTagList); + } + + + @Test + public void testGetAllTags() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/_tags"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + TagList tagList = ourCtx.newXmlParser().parseTagList(responseContent); + assertEquals(ourProvider.getAllTags(), tagList); + } + + @Test + public void testGetAllTagsPatient() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/_tags"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + TagList actual = ourCtx.newXmlParser().parseTagList(responseContent); + + TagList expected = new TagList(); + expected.addTag(null, "Patient", "DogLabel"); + expected.addTag("http://cats", "AllCat", "CatLabel"); + assertEquals(expected, actual); + } + + @Test + public void testGetAllTagsPatientId() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/111/_tags"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + TagList actual = ourCtx.newXmlParser().parseTagList(responseContent); + + TagList expected = new TagList(); + expected.addTag(null, "Patient111", "DogLabel"); + expected.addTag("http://cats", "AllCat", "CatLabel"); + assertEquals(expected, actual); + } + + @Test + public void testGetAllTagsPatientIdVersion() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/111/_history/222/_tags"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + TagList actual = ourCtx.newXmlParser().parseTagList(responseContent); + TagList expected = new TagList(); + expected.addTag(null, "Patient111222", "DogLabel"); + expected.addTag("http://cats", "AllCat", "CatLabel"); + assertEquals(expected, actual); + } + + @Test + public void testGetAllTagsObservationIdVersion() throws Exception { + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Observation/111/_history/222/_tags"); + HttpResponse status = ourClient.execute(httpGet); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + TagList actual = ourCtx.newXmlParser().parseTagList(responseContent); + TagList expected = new TagList(); + expected.addTag(null, "Patient111222", "DogLabel"); + expected.addTag("http://cats", "AllCat", "CatLabel"); + assertEquals(expected, actual); + } + + @Test + public void testRemoveTagsById() throws Exception { + + TagList tagList = new TagList(); + tagList.addTag("scheme", "term", "label"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/111/_tags/_delete"); + httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeTagListToString(tagList), ContentType.create(EncodingEnum.JSON.getResourceContentType(), "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("Remove111", ourLastOutcome); + assertEquals(tagList, ourLastTagList); + } + + @Test + public void testRemoveTagsByIdAndVersion() throws Exception { + + TagList tagList = new TagList(); + tagList.addTag("scheme", "term", "label"); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/Patient/111/_history/222/_tags/_delete"); + httpPost.setEntity(new StringEntity(ourCtx.newJsonParser().encodeTagListToString(tagList), ContentType.create(EncodingEnum.JSON.getResourceContentType(), "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("Remove111222", ourLastOutcome); + assertEquals(tagList, ourLastTagList); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + ourCtx = new FhirContext(Patient.class); + + ourProvider = new DummyProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setPlainProviders(ourProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + public static class DummyProvider { + + @AddTags(type = Patient.class) + public void addTagsPatient(@IdParam IdDt theId, @TagListParam TagList theTagList) { + ourLastOutcome = "add" + theId.getIdPart() + StringUtils.defaultString(theId.getVersionIdPart()); + ourLastTagList=theTagList; + } + + @GetTags + public TagList getAllTags() { + TagList tagList = new TagList(); + tagList.add(new Tag((String) null, "AllDog", "DogLabel")); + tagList.add(new Tag("http://cats", "AllCat", "CatLabel")); + return tagList; + } + + @GetTags(type = Patient.class) + public TagList getAllTagsPatient() { + TagList tagList = new TagList(); + tagList.add(new Tag((String) null, "Patient", "DogLabel")); + tagList.add(new Tag("http://cats", "AllCat", "CatLabel")); + return tagList; + } + + @GetTags(type = Patient.class) + public TagList getAllTagsPatientId(@IdParam IdDt theId) { + TagList tagList = new TagList(); + tagList.add(new Tag((String) null, "Patient" + theId.getIdPart() + defaultString(theId.getVersionIdPart()), "DogLabel")); + tagList.add(new Tag("http://cats", "AllCat", "CatLabel")); + return tagList; + } + +// @GetTags(type = Patient.class) +// public TagList getAllTagsPatientIdVersion(@IdParam IdDt theId, @VersionIdParam IdDt theVersion) { +// TagList tagList = new TagList(); +// tagList.add(new Tag((String) null, "Patient" + theId.getIdPart() + theVersion.getVersionIdPart(), "DogLabel")); +// tagList.add(new Tag("http://cats", "AllCat", "CatLabel")); +// return tagList; +// } + + @GetTags(type = Observation.class) + public TagList getAllTagsObservationIdVersion(@IdParam IdDt theId) { + TagList tagList = new TagList(); + tagList.add(new Tag((String) null, "Patient" + theId.getIdPart() + theId.getVersionIdPart(), "DogLabel")); + tagList.add(new Tag("http://cats", "AllCat", "CatLabel")); + return tagList; + } + +// @DeleteTags(type = Patient.class) +// public void RemoveTagsPatient(@IdParam IdDt theId, @VersionIdParam IdDt theVersion, @TagListParam TagList theTagList) { +// ourLastOutcome = "Remove" + theId.getIdPart() + theVersion.getVersionIdPart(); +// ourLastTagList=theTagList; +// } + + @DeleteTags(type = Patient.class) + public void RemoveTagsPatient(@IdParam IdDt theId, @TagListParam TagList theTagList) { + ourLastOutcome = "Remove" + theId.getIdPart()+StringUtils.defaultString(theId.getVersionIdPart()); + ourLastTagList=theTagList; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TransactionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TransactionTest.java new file mode 100644 index 00000000000..67e82345bdf --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TransactionTest.java @@ -0,0 +1,285 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.rest.annotation.Transaction; +import ca.uhn.fhir.rest.annotation.TransactionParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class TransactionTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(); + private static boolean ourDropFirstResource; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionTest.class); + private static int ourPort; + private static boolean ourReturnOperationOutcome; + private static Server ourServer; + + @Before + public void before() { + ourReturnOperationOutcome = false; + ourDropFirstResource = false; + } + + @Test + public void testTransaction() throws Exception { + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(3, bundle.size()); + + BundleEntry entry0 = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); + + BundleEntry entry1 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(2); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); + } + + @Test + public void testTransactionWithFewerResponseElements() throws Exception { + ourDropFirstResource =true; + + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(2, bundle.size()); + + BundleEntry entry1 = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); + } + + @Test + public void testTransactionWithOperationOutcome() throws Exception { + ourReturnOperationOutcome = true; + + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(4, bundle.size()); + + assertEquals(OperationOutcome.class, bundle.getEntries().get(0).getResource().getClass()); + assertEquals("OperationOutcome (no ID)", bundle.getEntries().get(0).getTitle().getValue()); + + BundleEntry entry0 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); + + BundleEntry entry1 = bundle.getEntries().get(2); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(3); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); + } + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyProvider patientProvider = new DummyProvider(); + RestfulServer server = new RestfulServer(); + server.setProviders(patientProvider); + + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); + proxyHandler.setContextPath("/"); + + ServletHolder handler = new ServletHolder(); + handler.setServlet(server); + proxyHandler.addServlet(handler, "/*"); + + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyProvider { + + @Transaction + public List transaction(@TransactionParam List theResources) { + int index = 1; + for (IResource next : theResources) { + String newId = "8" + Integer.toString(index); + if (next.getResourceMetadata().containsKey(ResourceMetadataKeyEnum.DELETED_AT)) { + newId = next.getId().getIdPart(); + } + next.setId(new IdDt("Patient", newId, "9" + Integer.toString(index))); + index++; + } + + List retVal = new ArrayList(theResources); + + if (ourDropFirstResource) { + retVal.remove(0); + } + + if (ourReturnOperationOutcome) { + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDetails("AAAAA"); + retVal.add(0, oo); + } + + return retVal; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TransactionWithBundleParamTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TransactionWithBundleParamTest.java new file mode 100644 index 00000000000..a13c5333fd0 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/TransactionWithBundleParamTest.java @@ -0,0 +1,234 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.api.BundleEntry; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.rest.annotation.Transaction; +import ca.uhn.fhir.rest.annotation.TransactionParam; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class TransactionWithBundleParamTest { + + private static CloseableHttpClient ourClient; + private static FhirContext ourCtx = new FhirContext(); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TransactionWithBundleParamTest.class); + private static int ourPort; + private static boolean ourReturnOperationOutcome; + + private static Server ourServer; + + + + @Before + public void before() { + ourReturnOperationOutcome = false; + } + + @Test + public void testTransaction() throws Exception { + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(3, bundle.size()); + + BundleEntry entry0 = bundle.getEntries().get(0); + assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); + + BundleEntry entry1 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(2); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); +} + + + @Test + public void testTransactionWithOperationOutcome() throws Exception { + ourReturnOperationOutcome = true; + + Bundle b = new Bundle(); + InstantDt nowInstant = InstantDt.withCurrentTime(); + + Patient p1 = new Patient(); + p1.addName().addFamily("Family1"); + BundleEntry entry = b.addEntry(); + entry.getId().setValue("1"); + entry.setResource(p1); + + Patient p2 = new Patient(); + p2.addName().addFamily("Family2"); + entry = b.addEntry(); + entry.getId().setValue("2"); + entry.setResource(p2); + + BundleEntry deletedEntry = b.addEntry(); + deletedEntry.setId(new IdDt("Patient/3")); + deletedEntry.setDeleted(nowInstant); + + String bundleString = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(b); + ourLog.info(bundleString); + + HttpPost httpPost = new HttpPost("http://localhost:" + ourPort + "/"); + httpPost.addHeader("Accept", Constants.CT_ATOM_XML + "; pretty=true"); + httpPost.setEntity(new StringEntity(bundleString, ContentType.create(Constants.CT_ATOM_XML, "UTF-8"))); + HttpResponse status = ourClient.execute(httpPost); + String responseContent = IOUtils.toString(status.getEntity().getContent()); IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + + ourLog.info(responseContent); + + Bundle bundle = new FhirContext().newXmlParser().parseBundle(responseContent); + assertEquals(4, bundle.size()); + + assertEquals(OperationOutcome.class, bundle.getEntries().get(0).getResource().getClass()); + assertEquals("OperationOutcome (no ID)", bundle.getEntries().get(0).getTitle().getValue()); + + BundleEntry entry0 = bundle.getEntries().get(1); + assertEquals("http://localhost:" + ourPort + "/Patient/81", entry0.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/81/_history/91", entry0.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/1", entry0.getLinkAlternate().getValue()); + + BundleEntry entry1 = bundle.getEntries().get(2); + assertEquals("http://localhost:" + ourPort + "/Patient/82", entry1.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/82/_history/92", entry1.getLinkSelf().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/2", entry1.getLinkAlternate().getValue()); + + BundleEntry entry2 = bundle.getEntries().get(3); + assertEquals("http://localhost:" + ourPort + "/Patient/3", entry2.getId().getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/3/_history/93", entry2.getLinkSelf().getValue()); + assertEquals(nowInstant.getValueAsString(), entry2.getDeletedAt().getValueAsString()); +} + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyProvider patientProvider = new DummyProvider(); + RestfulServer server = new RestfulServer(); + server.setProviders(patientProvider); + + org.eclipse.jetty.servlet.ServletContextHandler proxyHandler = new org.eclipse.jetty.servlet.ServletContextHandler(); + proxyHandler.setContextPath("/"); + + ServletHolder handler = new ServletHolder(); + handler.setServlet(server); + proxyHandler.addServlet(handler, "/*"); + + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyProvider { + + @Transaction + public List transaction(@TransactionParam Bundle theResources) { + int index=1; + for (IResource next : theResources.toListOfResources()) { + String newId = "8"+Integer.toString(index); + if (next.getResourceMetadata().containsKey(ResourceMetadataKeyEnum.DELETED_AT)) { + newId = next.getId().getIdPart(); + } + next.setId(new IdDt("Patient", newId, "9"+Integer.toString(index))); + index++; + } + + List retVal = theResources.toListOfResources(); + if (ourReturnOperationOutcome) { + retVal = new ArrayList(); + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDetails("AAAAA"); + retVal.add(oo); + retVal.addAll(theResources.toListOfResources()); + } + + return retVal; + } + + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/UpdateTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/UpdateTest.java new file mode 100644 index 00000000000..b4ac663f43a --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/UpdateTest.java @@ -0,0 +1,425 @@ +package ca.uhn.fhir.rest.server; + +import static org.junit.Assert.*; + +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.ContentType; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum; +import ca.uhn.fhir.model.api.Tag; +import ca.uhn.fhir.model.api.TagList; +import ca.uhn.fhir.model.dstu.resource.DiagnosticOrder; +import ca.uhn.fhir.model.dstu.resource.DiagnosticReport; +import ca.uhn.fhir.model.dstu.resource.Observation; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.ResourceParam; +import ca.uhn.fhir.rest.annotation.Update; +import ca.uhn.fhir.rest.api.MethodOutcome; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class UpdateTest { + private static CloseableHttpClient ourClient; + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(UpdateTest.class); + private static int ourPort; + private static DiagnosticReportProvider ourReportProvider; + private static Server ourServer; + + @Test + public void testUpdate() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/001"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + OperationOutcome oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent); + assertEquals("OODETAILS", oo.getIssueFirstRep().getDetails().getValue()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("location").getValue()); + assertEquals("http://localhost:" + ourPort + "/Patient/001/_history/002", status.getFirstHeader("content-location").getValue()); + + } + + + @Test + public void testUpdateWhichReturnsCreate() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Patient/001CREATE"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + OperationOutcome oo = new FhirContext().newXmlParser().parseResource(OperationOutcome.class, responseContent); + assertEquals("OODETAILS", oo.getIssueFirstRep().getDetails().getValue()); + + assertEquals(201, status.getStatusLine().getStatusCode()); + assertEquals("http://localhost:" + ourPort + "/Patient/001CREATE/_history/002", status.getFirstHeader("location").getValue()); + + } + + @Test + public void testUpdateMethodReturnsInvalidId() throws Exception { + + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/AAAAAA"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ourLog.info("Response was:\n{}", responseContent); + + assertEquals(500, status.getStatusLine().getStatusCode()); + + } + + @Test + public void testUpdateNoResponse() throws Exception { + + DiagnosticReport dr = new DiagnosticReport(); + dr.addCodedDiagnosis().addCoding().setCode("AAA"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPost); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002", status.getFirstHeader("location").getValue()); + + IOUtils.closeQuietly(status.getEntity().getContent()); + } + + @Test + public void testUpdateWithTagMultiple() throws Exception { + + DiagnosticReport dr = new DiagnosticReport(); + dr.addCodedDiagnosis().addCoding().setCode("AAA"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.addHeader("Category", "Dog; scheme=\"urn:animals\", Cat; scheme=\"urn:animals\""); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + CloseableHttpResponse status = ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(2, ourReportProvider.getLastTags().size()); + assertEquals(new Tag("urn:animals", "Dog"), ourReportProvider.getLastTags().get(0)); + assertEquals(new Tag("urn:animals", "Cat"), ourReportProvider.getLastTags().get(1)); + + httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.addHeader("Category", "Dog; label=\"aa\"; scheme=\"urn:animals\", Cat; label=\"bb\"; scheme=\"urn:animals\""); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + status = ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(2, ourReportProvider.getLastTags().size()); + assertEquals(new Tag("urn:animals", "Dog", "aa"), ourReportProvider.getLastTags().get(0)); + assertEquals(new Tag("urn:animals", "Cat", "bb"), ourReportProvider.getLastTags().get(1)); + + } + + @Test + public void testUpdateWithTagSimple() throws Exception { + + DiagnosticReport dr = new DiagnosticReport(); + dr.addCodedDiagnosis().addCoding().setCode("AAA"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.addHeader("Category", "Dog; scheme=\"animals\""); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + CloseableHttpResponse status = ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(1, ourReportProvider.getLastTags().size()); + assertEquals(new Tag("animals", "Dog"), ourReportProvider.getLastTags().get(0)); + + } + + @Test + public void testUpdateWithTagWithScheme() throws Exception { + + DiagnosticReport dr = new DiagnosticReport(); + dr.addCodedDiagnosis().addCoding().setCode("AAA"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.addHeader("Category", "Dog; scheme=\"http://foo\""); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + CloseableHttpResponse status = ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(1, ourReportProvider.getLastTags().size()); + assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0)); + + httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.addHeader("Category", "Dog; scheme=\"http://foo\";"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(1, ourReportProvider.getLastTags().size()); + assertEquals(new Tag("http://foo", "Dog", null), ourReportProvider.getLastTags().get(0)); + + } + + @Test + public void testUpdateWithTagWithSchemeAndLabel() throws Exception { + + DiagnosticReport dr = new DiagnosticReport(); + dr.addCodedDiagnosis().addCoding().setCode("AAA"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.addHeader("Category", "Dog; scheme=\"http://foo\"; label=\"aaaa\""); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + CloseableHttpResponse status = ourClient.execute(httpPost); + assertEquals(1, ourReportProvider.getLastTags().size()); + assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0)); + IOUtils.closeQuietly(status.getEntity().getContent()); + + httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.addHeader("Category", "Dog; scheme=\"http://foo\"; label=\"aaaa\"; "); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(dr), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + status=ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(1, ourReportProvider.getLastTags().size()); + assertEquals(new Tag("http://foo", "Dog", "aaaa"), ourReportProvider.getLastTags().get(0)); + + } + + @Test + public void testUpdateWithVersion() throws Exception { + + DiagnosticReport patient = new DiagnosticReport(); + patient.getIdentifier().setValue("001"); + + HttpPut httpPut = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPut.addHeader("Content-Location", "/DiagnosticReport/001/_history/004"); + httpPut.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + HttpResponse status = ourClient.execute(httpPut); + IOUtils.closeQuietly(status.getEntity().getContent()); + + // String responseContent = + // IOUtils.toString(status.getEntity().getContent()); + // ourLog.info("Response was:\n{}", responseContent); + + assertEquals(200, status.getStatusLine().getStatusCode()); + assertEquals("http://localhost:" + ourPort + "/DiagnosticReport/001/_history/002", status.getFirstHeader("Location").getValue()); + + } + + @Test() + public void testUpdateWithVersionBadContentLocationHeader() throws Exception { + + DiagnosticReport patient = new DiagnosticReport(); + patient.getIdentifier().setValue("001"); + + HttpPut httpPut = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPut.addHeader("Content-Location", "/Patient/001/_history/002"); + httpPut.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + CloseableHttpResponse status = ourClient.execute(httpPut); + String responseContent = IOUtils.toString(status.getEntity().getContent()); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(400, status.getStatusLine().getStatusCode()); + ourLog.info("Response was:\n{}", responseContent); + + } + + public void testUpdateWrongResourceType() throws Exception { + + // TODO: this method sends in the wrong resource type vs. the URL so it + // should + // give a useful error message (and then make this unit test actually + // run) + Patient patient = new Patient(); + patient.addIdentifier().setValue("002"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/DiagnosticReport/001"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + ourClient.execute(httpPost); + fail(); + } + +@Test + public void testUpdateWithNoReturn() throws Exception { + + Organization patient = new Organization(); + patient.addIdentifier().setValue("002"); + + HttpPut httpPost = new HttpPut("http://localhost:" + ourPort + "/Organization/001"); + httpPost.setEntity(new StringEntity(new FhirContext().newXmlParser().encodeResourceToString(patient), ContentType.create(Constants.CT_FHIR_XML, "UTF-8"))); + + CloseableHttpResponse status = ourClient.execute(httpPost); + IOUtils.closeQuietly(status.getEntity().getContent()); + + assertEquals(200, status.getStatusLine().getStatusCode()); + status.close(); + } + + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + PatientProvider patientProvider = new PatientProvider(); + + ourReportProvider = new DiagnosticReportProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + RestfulServer servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider, ourReportProvider, new ObservationProvider(), new OrganizationResourceProvider()); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + + public static class OrganizationResourceProvider implements IResourceProvider + { + + @Override + public Class getResourceType() { + return Organization.class; + } + + @SuppressWarnings("unused") + @Update + public MethodOutcome update(@IdParam IdDt theId, @ResourceParam Organization theOrganization) { + return new MethodOutcome(); + } + + } + + public static class DiagnosticReportProvider implements IResourceProvider { + private TagList myLastTags; + + public TagList getLastTags() { + return myLastTags; + } + + @Override + public Class getResourceType() { + return DiagnosticReport.class; + } + + + @Update() + public MethodOutcome updateDiagnosticReportWithVersionAndNoResponse(@IdParam IdDt theId, @ResourceParam DiagnosticReport theDr) { + IdDt id = theId; + + if (theId.getValue().contains("AAAAAA")) { + IdDt id2 = new IdDt(id.getIdPart(), "002"); + return new MethodOutcome(id2); // this is invalid + } + + myLastTags = (TagList) theDr.getResourceMetadata().get(ResourceMetadataKeyEnum.TAG_LIST); + return new MethodOutcome(new IdDt("DiagnosticReport", id.getIdPart(), "002")); + } + + } + + public static class ObservationProvider implements IResourceProvider{ + + @Override + public Class getResourceType() { + return Observation.class; + } + + @SuppressWarnings("unused") + @Update() + public MethodOutcome updateDiagnosticReportWithVersion(@IdParam IdDt theId, @ResourceParam DiagnosticOrder thePatient) { + /* + * TODO: THIS METHOD IS NOT USED. It's the wrong type (DiagnosticOrder), so it should cause an exception on startup. Also we should detect if there are multiple resource params on an + * update/create/etc method + */ + IdDt id = theId; + return new MethodOutcome(id); + } + } + + + public static class PatientProvider implements IResourceProvider { + + @Override + public Class getResourceType() { + return Patient.class; + } + + + + @Update() + public MethodOutcome updatePatient(@IdParam IdDt theId, @ResourceParam Patient thePatient) { + IdDt id = theId.withVersion(thePatient.getIdentifierFirstRep().getValue().getValue()); + OperationOutcome oo = new OperationOutcome(); + oo.addIssue().setDetails("OODETAILS"); + if (theId.getValueAsString().contains("CREATE")) { + return new MethodOutcome(id,oo, true); + } + + return new MethodOutcome(id,oo); + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/exceptions/ExceptionTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/exceptions/ExceptionTest.java new file mode 100644 index 00000000000..8786d945df2 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/exceptions/ExceptionTest.java @@ -0,0 +1,54 @@ +package ca.uhn.fhir.rest.server.exceptions; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import org.junit.Test; + +import ca.uhn.fhir.model.base.resource.BaseOperationOutcome; + +import com.google.common.collect.ImmutableSet; +import com.google.common.reflect.ClassPath; +import com.google.common.reflect.ClassPath.ClassInfo; + +public class ExceptionTest { + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExceptionTest.class); + + @Test + public void testExceptionsAreGood() throws Exception { + ImmutableSet classes = ClassPath.from(Thread.currentThread().getContextClassLoader()).getTopLevelClasses(BaseServerResponseException.class.getPackage().getName()); + assertTrue(classes.size() > 5); + + for (ClassInfo classInfo : classes) { + ourLog.info("Scanning {}", classInfo.getName()); + + Class next = Class.forName(classInfo.getName()); + assertNotNull(next); + + if (next == getClass()) { + continue; + } + if (next == BaseServerResponseException.class) { + continue; + } + if (next == UnclassifiedServerFailureException.class) { + continue; + } + + assertTrue(BaseServerResponseException.isExceptionTypeRegistered(next)); + + if (next == AuthenticationException.class) { + continue; + } + + try { + next.getConstructor(String.class, BaseOperationOutcome.class); + } catch (NoSuchMethodException e) { + fail(classInfo.getName() + " has no constructor with params: (String, OperationOutcome)"); + } + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptorTest.java new file mode 100644 index 00000000000..e9d63086887 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/rest/server/interceptor/LoggingInterceptorTest.java @@ -0,0 +1,228 @@ +package ca.uhn.fhir.rest.server.interceptor; + +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpResponse; +import org.apache.http.client.methods.HttpGet; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClientBuilder; +import org.apache.http.impl.conn.PoolingHttpClientConnectionManager; +import org.eclipse.jetty.server.Server; +import org.eclipse.jetty.servlet.ServletHandler; +import org.eclipse.jetty.servlet.ServletHolder; +import org.hamcrest.core.StringContains; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.slf4j.Logger; + +import ca.uhn.fhir.model.dstu.composite.HumanNameDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Read; +import ca.uhn.fhir.rest.annotation.RequiredParam; +import ca.uhn.fhir.rest.annotation.Search; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; +import ca.uhn.fhir.util.PortUtil; + +/** + * Created by dsotnikov on 2/25/2014. + */ +public class LoggingInterceptorTest { + + private static CloseableHttpClient ourClient; + private static int ourPort; + private static Server ourServer; + private static RestfulServer servlet; + private IServerInterceptor myInterceptor; + + + + @Test + public void testRead() throws Exception { + + LoggingInterceptor interceptor = new LoggingInterceptor(); + servlet.setInterceptors(Collections.singletonList((IServerInterceptor)interceptor)); + + Logger logger = mock(Logger.class); + interceptor.setLogger(logger); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient/1"); + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(logger, times(1)).info(captor.capture()); + assertThat(captor.getValue(), StringContains.containsString("read - Patient/1")); + } + + @Test + public void testSearch() throws Exception { + + LoggingInterceptor interceptor = new LoggingInterceptor(); + interceptor.setMessageFormat( "${operationType} - ${idOrResourceName} - ${requestParameters}"); + servlet.setInterceptors(Collections.singletonList((IServerInterceptor)interceptor)); + + Logger logger = mock(Logger.class); + interceptor.setLogger(logger); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_id=1"); + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(logger, times(1)).info(captor.capture()); + assertThat(captor.getValue(), StringContains.containsString("search-type - Patient - ?_id=1")); + } + + @Test + public void testMetadata() throws Exception { + + LoggingInterceptor interceptor = new LoggingInterceptor(); + servlet.setInterceptors(Collections.singletonList((IServerInterceptor)interceptor)); + + Logger logger = mock(Logger.class); + interceptor.setLogger(logger); + + HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/metadata"); + HttpResponse status = ourClient.execute(httpGet); + IOUtils.closeQuietly(status.getEntity().getContent()); + + ArgumentCaptor captor = ArgumentCaptor.forClass(String.class); + verify(logger, times(1)).info(captor.capture()); + assertThat(captor.getValue(), StringContains.containsString("metadata - ")); + } + + + + @AfterClass + public static void afterClass() throws Exception { + ourServer.stop(); + } + + @Before + public void before() { + myInterceptor = mock(IServerInterceptor.class); + servlet.setInterceptors(Collections.singletonList(myInterceptor)); + } + + + @BeforeClass + public static void beforeClass() throws Exception { + ourPort = PortUtil.findFreePort(); + ourServer = new Server(ourPort); + + DummyPatientResourceProvider patientProvider = new DummyPatientResourceProvider(); + + ServletHandler proxyHandler = new ServletHandler(); + servlet = new RestfulServer(); + servlet.setResourceProviders(patientProvider); + ServletHolder servletHolder = new ServletHolder(servlet); + proxyHandler.addServletWithMapping(servletHolder, "/*"); + ourServer.setHandler(proxyHandler); + ourServer.start(); + + PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS); + HttpClientBuilder builder = HttpClientBuilder.create(); + builder.setConnectionManager(connectionManager); + ourClient = builder.build(); + + } + + /** + * Created by dsotnikov on 2/25/2014. + */ + public static class DummyPatientResourceProvider implements IResourceProvider { + + public Map getIdToPatient() { + Map idToPatient = new HashMap(); + { + Patient patient = createPatient1(); + idToPatient.put("1", patient); + } + { + Patient patient = new Patient(); + patient.getIdentifier().add(new IdentifierDt()); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00002"); + patient.getName().add(new HumanNameDt()); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientTwo"); + patient.getGender().setText("F"); + patient.getId().setValue("2"); + idToPatient.put("2", patient); + } + return idToPatient; + } + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Read() + public Patient getResourceById(@IdParam IdDt theId) { + String key = theId.getIdPart(); + Patient retVal = getIdToPatient().get(key); + return retVal; + } + + + /** + * Retrieve the resource by its identifier + * + * @param theId + * The resource identity + * @return The resource + */ + @Search() + public List getResourceById(@RequiredParam(name = "_id") String theId) { + Patient patient = getIdToPatient().get(theId); + if (patient != null) { + return Collections.singletonList(patient); + } else { + return Collections.emptyList(); + } + } + + + @Override + public Class getResourceType() { + return Patient.class; + } + + private Patient createPatient1() { + Patient patient = new Patient(); + patient.addIdentifier(); + patient.getIdentifier().get(0).setUse(IdentifierUseEnum.OFFICIAL); + patient.getIdentifier().get(0).setSystem(new UriDt("urn:hapitest:mrns")); + patient.getIdentifier().get(0).setValue("00001"); + patient.addName(); + patient.getName().get(0).addFamily("Test"); + patient.getName().get(0).addGiven("PatientOne"); + patient.getGender().setText("M"); + patient.getId().setValue("1"); + return patient; + } + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/test/FhirTerserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/test/FhirTerserTest.java new file mode 100644 index 00000000000..bc935f03bb1 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/test/FhirTerserTest.java @@ -0,0 +1,36 @@ +package ca.uhn.fhir.test; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.AdministrativeGenderCodesEnum; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.util.FhirTerser; + +public class FhirTerserTest { + + @Test + public void testGetAllPopulatedChildElementsOfType() { + + Patient p = new Patient(); + p.setGender(AdministrativeGenderCodesEnum.M); + p.addIdentifier().setSystem("urn:foo"); + p.addAddress().addLine("Line1"); + p.addAddress().addLine("Line2"); + p.addName().addFamily("Line3"); + + FhirTerser t = new FhirContext().newTerser(); + List strings = t.getAllPopulatedChildElementsOfType(p, StringDt.class); + + assertEquals(3, strings.size()); + assertThat(strings, containsInAnyOrder(new StringDt("Line1"), new StringDt("Line2"), new StringDt("Line3"))); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/IdentifierDt.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/IdentifierDt.java new file mode 100644 index 00000000000..766fe8141e3 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/IdentifierDt.java @@ -0,0 +1,406 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.testmodel; + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IQueryParameterType; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.composite.PeriodDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Organization; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; + +/** + * HAPI/FHIR Identifier Datatype + * (An identifier intended for computation) + * + *

+ * Definition: + * A technical identifier - identifies some entity uniquely and unambiguously + *

+ * + *

+ * Requirements: + * Need to be able to identify things with confidence and be sure that the identification is not subject to misinterpretation + *

+ */ +@DatatypeDef(name="Identifier") +public class IdentifierDt + extends BaseIdentifiableElement implements ICompositeDatatype , IQueryParameterType { + + /** + * Creates a new identifier + */ + public IdentifierDt() { + // nothing + } + + /** + * Creates a new identifier with the given system and value + */ + public IdentifierDt(String theSystem, String theValue) { + setSystem(theSystem); + setValue(theValue); + } + + @Child(name="use", type=CodeDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="usual | official | temp | secondary (If known)", + formalDefinition="The purpose of this identifier" + ) + private BoundCodeDt myUse; + + @Child(name="label", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Description of identifier", + formalDefinition="A text string for the identifier that can be displayed to a human so they can recognize the identifier" + ) + private StringDt myLabel; + + @Child(name="system", type=UriDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="The namespace for the identifier", + formalDefinition="Establishes the namespace in which set of possible id values is unique." + ) + private UriDt mySystem; + + @Child(name="value", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="The value that is unique", + formalDefinition="The portion of the identifier typically displayed to the user and which is unique within the context of the system." + ) + private StringDt myValue; + + @Child(name="period", type=PeriodDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="Time period when id is/was valid for use", + formalDefinition="Time period during which identifier is/was valid for use" + ) + private PeriodDt myPeriod; + + @Child(name="assigner", order=5, min=0, max=1, type={ + Organization.class, + }) + @Description( + shortDefinition="Organization that issued id (may be just text)", + formalDefinition="Organization that issued/manages the identifier" + ) + private ResourceReferenceDt myAssigner; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myUse, myLabel, mySystem, myValue, myPeriod, myAssigner); + } + + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myUse, myLabel, mySystem, myValue, myPeriod, myAssigner ); + } + + + /** + * Gets the value(s) for use (usual | official | temp | secondary (If known)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The purpose of this identifier + *

+ */ + public BoundCodeDt getUse() { + if (myUse == null) { + myUse = new BoundCodeDt(IdentifierUseEnum.VALUESET_BINDER); + } + return myUse; + } + + /** + * Sets the value(s) for use (usual | official | temp | secondary (If known)) + * + *

+ * Definition: + * The purpose of this identifier + *

+ */ + public void setUse(BoundCodeDt theValue) { + myUse = theValue; + } + + + /** + * Sets the value(s) for use (usual | official | temp | secondary (If known)) + * + *

+ * Definition: + * The purpose of this identifier + *

+ */ + public void setUse(IdentifierUseEnum theValue) { + getUse().setValueAsEnum(theValue); + } + + + /** + * Gets the value(s) for label (Description of identifier). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A text string for the identifier that can be displayed to a human so they can recognize the identifier + *

+ */ + public StringDt getLabel() { + if (myLabel == null) { + myLabel = new StringDt(); + } + return myLabel; + } + + /** + * Sets the value(s) for label (Description of identifier) + * + *

+ * Definition: + * A text string for the identifier that can be displayed to a human so they can recognize the identifier + *

+ */ + public void setLabel(StringDt theValue) { + myLabel = theValue; + } + + + /** + * Sets the value for label (Description of identifier) + * + *

+ * Definition: + * A text string for the identifier that can be displayed to a human so they can recognize the identifier + *

+ */ + public void setLabel( String theString) { + myLabel = new StringDt(theString); + } + + + /** + * Gets the value(s) for system (The namespace for the identifier). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Establishes the namespace in which set of possible id values is unique. + *

+ */ + public UriDt getSystem() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + /** + * Sets the value(s) for system (The namespace for the identifier) + * + *

+ * Definition: + * Establishes the namespace in which set of possible id values is unique. + *

+ */ + public void setSystem(UriDt theValue) { + mySystem = theValue; + } + + + /** + * Sets the value for system (The namespace for the identifier) + * + *

+ * Definition: + * Establishes the namespace in which set of possible id values is unique. + *

+ */ + public void setSystem( String theUri) { + mySystem = new UriDt(theUri); + } + + + /** + * Gets the value(s) for value (The value that is unique). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The portion of the identifier typically displayed to the user and which is unique within the context of the system. + *

+ */ + public StringDt getValue() { + if (myValue == null) { + myValue = new StringDt(); + } + return myValue; + } + + /** + * Sets the value(s) for value (The value that is unique) + * + *

+ * Definition: + * The portion of the identifier typically displayed to the user and which is unique within the context of the system. + *

+ */ + public void setValue(StringDt theValue) { + myValue = theValue; + } + + + /** + * Sets the value for value (The value that is unique) + * + *

+ * Definition: + * The portion of the identifier typically displayed to the user and which is unique within the context of the system. + *

+ */ + public void setValue( String theString) { + myValue = new StringDt(theString); + } + + + /** + * Gets the value(s) for period (Time period when id is/was valid for use). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Time period during which identifier is/was valid for use + *

+ */ + public PeriodDt getPeriod() { + if (myPeriod == null) { + myPeriod = new PeriodDt(); + } + return myPeriod; + } + + /** + * Sets the value(s) for period (Time period when id is/was valid for use) + * + *

+ * Definition: + * Time period during which identifier is/was valid for use + *

+ */ + public void setPeriod(PeriodDt theValue) { + myPeriod = theValue; + } + + + + /** + * Gets the value(s) for assigner (Organization that issued id (may be just text)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Organization that issued/manages the identifier + *

+ */ + public ResourceReferenceDt getAssigner() { + if (myAssigner == null) { + myAssigner = new ResourceReferenceDt(); + } + return myAssigner; + } + + /** + * Sets the value(s) for assigner (Organization that issued id (may be just text)) + * + *

+ * Definition: + * Organization that issued/manages the identifier + *

+ */ + public void setAssigner(ResourceReferenceDt theValue) { + myAssigner = theValue; + } + + + + + /** + * Returns true if this identifier has the same {@link IdentifierDt#getValue() value} + * and {@link IdentifierDt#getSystem() system} (as compared by simple equals comparison). + * Does not compare other values (e.g. {@link IdentifierDt#getUse() use}) or any extensions. + */ + public boolean matchesSystemAndValue(IdentifierDt theIdentifier) { + if (theIdentifier == null) { + return false; + } + return getValue().equals(theIdentifier.getValue()) && getSystem().equals(theIdentifier.getSystem()); + } + + /** + * {@inheritDoc} + */ + @Override + public String getValueAsQueryToken() { + if (org.apache.commons.lang3.StringUtils.isNotBlank(getSystem().getValueAsString())) { + return getSystem().getValueAsString() + '|' + getValue().getValueAsString(); + } else { + return getValue().getValueAsString(); + } + } + + /** + * {@inheritDoc} + */ + @Override + public void setValueAsQueryToken(String theQualifier, String theValue) { + int barIndex = theValue.indexOf('|'); + if (barIndex != -1) { + setSystem(new UriDt(theValue.substring(0, barIndex))); + setValue(theValue.substring(barIndex + 1)); + } else { + setValue(theValue); + } + } + + @Override + public String getQueryParameterQualifier() { + return null; + } + + +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/Patient.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/Patient.java new file mode 100644 index 00000000000..8446c4ea371 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/testmodel/Patient.java @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.testmodel; + +import java.util.ArrayList; +import java.util.List; + +import ca.uhn.fhir.model.api.BaseResource; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.ResourceDef; + +/** + * HAPI/FHIR Patient Resource + * (Information about a person or animal receiving health care services) + * + *

+ * Definition: + * Demographics and other administrative information about a person or animal receiving care or other health-related services + *

+ * + *

+ * Requirements: + * Tracking patient is the center of the healthcare process + *

+ */ +@ResourceDef(name="Patient", profile="http://hl7.org/fhir/profiles/Patient") +public class Patient extends BaseResource implements IResource { + + + @Child(name="identifier", type=IdentifierDt.class, order=0, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="An identifier for the person as this patient", + formalDefinition="An identifier that applies to this person as a patient" + ) + private List myIdentifier; + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myIdentifier ); + } + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myIdentifier); + } + + /** + * Gets the value(s) for identifier (An identifier for the person as this patient). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An identifier that applies to this person as a patient + *

+ */ + public List getIdentifier() { + if (myIdentifier == null) { + myIdentifier = new ArrayList(); + } + return myIdentifier; + } + + /** + * Sets the value(s) for identifier (An identifier for the person as this patient) + * + *

+ * Definition: + * An identifier that applies to this person as a patient + *

+ */ + public void setIdentifier(List theValue) { + myIdentifier = theValue; + } + + /** + * Adds and returns a new value for identifier (An identifier for the person as this patient) + * + *

+ * Definition: + * An identifier that applies to this person as a patient + *

+ */ + public IdentifierDt addIdentifier() { + IdentifierDt newType = new IdentifierDt(); + getIdentifier().add(newType); + return newType; + } + + + + + +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/FhirTerserTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/FhirTerserTest.java new file mode 100644 index 00000000000..a2072ef1cdf --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/FhirTerserTest.java @@ -0,0 +1,59 @@ +package ca.uhn.fhir.util; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Observation; + +public class FhirTerserTest { + + @Test + public void testTerser() { + + //@formatter:off + String msg = "\n" + + " \n" + + " \n" + + "
\n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + " \n" + + ""; + //@formatter:on + + Observation parsed = ourCtx.newXmlParser().parseResource(Observation.class, msg); + FhirTerser t = ourCtx.newTerser(); + + List elems = t.getAllPopulatedChildElementsOfType(parsed, ResourceReferenceDt.class); + assertEquals(2, elems.size()); + assertEquals("cid:patient@bundle", elems.get(0).getReference().getValue()); + assertEquals("cid:device@bundle", elems.get(1).getReference().getValue()); + } + + private static FhirContext ourCtx = new FhirContext(); +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/XmlUtilTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/XmlUtilTest.java new file mode 100644 index 00000000000..d5fa0160107 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/util/XmlUtilTest.java @@ -0,0 +1,26 @@ +package ca.uhn.fhir.util; + +import java.io.StringReader; +import java.io.StringWriter; + +import org.junit.Test; + +public class XmlUtilTest { + + + @Test + public void testCreateReader() throws Exception { + XmlUtil.createXmlReader(new StringReader("")); + } + + @Test + public void testCreateWriter() throws Exception { + XmlUtil.createXmlWriter(new StringWriter()); + } + + @Test + public void testCreateStreamWriter() throws Exception { + XmlUtil.createXmlStreamWriter(new StringWriter()); + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ResourceValidatorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ResourceValidatorTest.java new file mode 100644 index 00000000000..3594ada3176 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ResourceValidatorTest.java @@ -0,0 +1,135 @@ +package ca.uhn.fhir.validation; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.model.api.Bundle; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; +import ca.uhn.fhir.model.dstu.resource.Patient; +import ca.uhn.fhir.model.dstu.valueset.ContactSystemEnum; +import org.apache.commons.io.IOUtils; +import org.junit.Test; + +import java.io.IOException; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +public class ResourceValidatorTest { + + private static FhirContext ourCtx = new FhirContext(); + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceValidatorTest.class); + + @Test + public void testSchemaResourceValidator() throws IOException { + String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("patient-example-dicom.xml")); + Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res); + + 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) { + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome())); + assertEquals(1, e.getOperationOutcome().getIssue().size()); + assertThat(e.getOperationOutcome().getIssueFirstRep().getDetailsElement().getValue(), containsString("Invalid content was found starting with element 'breed'")); + } + } + + @Test + public void testSchemaBundleValidator() throws IOException { + String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml")); + Bundle b = ourCtx.newXmlParser().parseBundle(res); + + FhirValidator val = createFhirValidator(); + + val.validate(b); + + Patient p = (Patient) b.getEntries().get(0).getResource(); + p.getTelecomFirstRep().setValue("123-4567"); + + try { + val.validate(b); + fail(); + } catch (ValidationFailureException e) { + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(e.getOperationOutcome())); + assertEquals(1, e.getOperationOutcome().getIssue().size()); + assertThat(e.getOperationOutcome().getIssueFirstRep().getDetailsElement().getValue(), containsString("Inv-2: A system is required if a value is provided.")); + } + } + + @Test + public void testSchematronResourceValidator() throws IOException { + String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("patient-example-dicom.xml")); + Patient p = ourCtx.newXmlParser().parseResource(Patient.class, res); + + FhirValidator val = ourCtx.newValidator(); + val.setValidateAgainstStandardSchema(false); + val.setValidateAgainstStandardSchematron(true); + + ValidationResult validationResult = val.validateWithResult(p); + assertTrue(validationResult.isSuccessful()); + + p.getTelecomFirstRep().setValue("123-4567"); + validationResult = val.validateWithResult(p); + assertFalse(validationResult.isSuccessful()); + OperationOutcome operationOutcome = (OperationOutcome) validationResult.getOperationOutcome(); + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome)); + assertEquals(1, operationOutcome.getIssue().size()); + assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided.")); + + p.getTelecomFirstRep().setSystem(ContactSystemEnum.EMAIL); + validationResult = val.validateWithResult(p); + assertTrue(validationResult.isSuccessful()); + } + + @Test + public void testSchemaBundleValidatorIsSuccessful() throws IOException { + String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml")); + Bundle b = ourCtx.newXmlParser().parseBundle(res); + + FhirValidator val = createFhirValidator(); + + ValidationResult result = val.validateWithResult(b); + assertTrue(result.isSuccessful()); + OperationOutcome operationOutcome = (OperationOutcome) result.getOperationOutcome(); + assertNotNull(operationOutcome); + assertEquals(0, operationOutcome.getIssue().size()); + } + + @Test + public void testSchemaBundleValidatorFails() throws IOException { + String res = IOUtils.toString(getClass().getClassLoader().getResourceAsStream("atom-document-large.xml")); + Bundle b = ourCtx.newXmlParser().parseBundle(res); + + FhirValidator val = createFhirValidator(); + + ValidationResult validationResult = val.validateWithResult(b); + assertTrue(validationResult.isSuccessful()); + + Patient p = (Patient) b.getEntries().get(0).getResource(); + p.getTelecomFirstRep().setValue("123-4567"); + validationResult = val.validateWithResult(b); + assertFalse(validationResult.isSuccessful()); + OperationOutcome operationOutcome = (OperationOutcome) validationResult.getOperationOutcome(); + ourLog.info(ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(operationOutcome)); + assertEquals(1, operationOutcome.getIssue().size()); + assertThat(operationOutcome.getIssueFirstRep().getDetails().getValue(), containsString("Inv-2: A system is required if a value is provided.")); + } + + private FhirValidator createFhirValidator() { + FhirValidator val = ourCtx.newValidator(); + val.setValidateAgainstStandardSchema(true); + val.setValidateAgainstStandardSchematron(true); + return val; + } +} diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ValidationResultTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ValidationResultTest.java new file mode 100644 index 00000000000..b4f2a2fa503 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ValidationResultTest.java @@ -0,0 +1,48 @@ +package ca.uhn.fhir.validation; + +import ca.uhn.fhir.model.base.resource.BaseOperationOutcome.BaseIssue; +import ca.uhn.fhir.model.dstu.resource.OperationOutcome; + +import org.junit.Test; + +import java.util.List; +import java.util.UUID; + +import static org.hamcrest.Matchers.containsString; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; + +public class ValidationResultTest { + + @Test + public void isSuccessful_IsTrueForNullOperationOutcome() { + ValidationResult result = ValidationResult.valueOf(null); + assertTrue(result.isSuccessful()); + } + + @Test + public void isSuccessful_IsTrueForNoIssues() { + OperationOutcome operationOutcome = new OperationOutcome(); + // make sure a non-null ID doesn't cause the validation result to be a fail + operationOutcome.setId(UUID.randomUUID().toString()); + ValidationResult result = ValidationResult.valueOf(operationOutcome); + assertTrue(result.isSuccessful()); + } + + @Test + public void isSuccessful_FalseForIssues() { + OperationOutcome operationOutcome = new OperationOutcome(); + OperationOutcome.Issue issue = operationOutcome.addIssue(); + String errorMessage = "There was a validation problem"; + issue.setDetails(errorMessage); + ValidationResult result = ValidationResult.valueOf(operationOutcome); + assertFalse(result.isSuccessful()); + List issues = result.getOperationOutcome().getIssue(); + assertEquals(1, issues.size()); + assertEquals(errorMessage, issues.get(0).getDetailsElement().getValue()); + + assertThat("ValidationResult#toString should contain the issue description", result.toString(), containsString(errorMessage)); + } +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ValidatorInstantiatorTest.java b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ValidatorInstantiatorTest.java new file mode 100644 index 00000000000..f73ae04ed7c --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/java/ca/uhn/fhir/validation/ValidatorInstantiatorTest.java @@ -0,0 +1,24 @@ +package ca.uhn.fhir.validation; + +import static org.junit.Assert.*; + +import org.junit.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.validation.FhirValidator; + +public class ValidatorInstantiatorTest { + + @Test + public void testValidator() { + + FhirContext ctx = new FhirContext(); + FhirValidator val = ctx.newValidator(); + + // We have a full classpath, so take advantage + assertTrue(val.isValidateAgainstStandardSchema()); + assertTrue(val.isValidateAgainstStandardSchematron()); + + } + +} diff --git a/hapi-fhir-structures-dstu/src/test/resources/alert.profile.json b/hapi-fhir-structures-dstu/src/test/resources/alert.profile.json new file mode 100644 index 00000000000..d2466f49221 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/alert.profile.json @@ -0,0 +1,294 @@ +{ + "resourceType": "Profile", + "text": { + "status": "generated", + "div": "
\r\n<Alert xmlns="http://hl7.org/fhir"> \"doco\"\r\n <!-- from Resource: extension, modifierExtension, language, text, and contained -->\r\n <identifier><!-- 0..* Identifier Business identifier --></identifier>\r\n <category><!-- 0..1 CodeableConcept Clinical, administrative, etc. --></category>\r\n <status value="[code]"/><!-- 1..1 active | inactive | entered in error -->\r\n <subject><!-- 1..1 Resource(Patient) Who is alert about? --></subject>\r\n <author><!-- 0..1 Resource(Practitioner|Patient|Device) Alert creator --></author>\r\n <note value="[string]"/><!-- 1..1 Text of alert -->\r\n</Alert>\r\n
" + }, + "name": "alert", + "publisher": "FHIR Project", + "description": "Basic Profile. Prospective warnings of potential issues when providing care to the patient.", + "status": "draft", + "date": "2014-05-09", + "requirements": "Scope and Usage The Alert resource provides a single interface for managing clinical and administrative facts that need to be brought to the attention of users of clinical systems. Examples can include many things. Patient's posing particular risks (falls, physical violence), patient's needing special accomodations (hard of hearing, use easy-open caps), administrative concerns (verify postal address, pre-payment required) or any other situation that needs to be brought to attention within the context of a particular workflow. (The workflow relevant to the issue can be identified by the category element.) \r\n\r\nUsually, resources specific to particular types of issues (health conditions, allergies, active medications will be used to communicate those issues. However, in some cases, particularly important information (a latex or severe food allergy) migt be highlighted as an Alert as well as the more typical resource.", + "mapping": [ + { + "identity": "rim", + "uri": "http://hl7.org/v3", + "name": "RIM" + } + ], + "structure": [ + { + "type": "Alert", + "publish": true, + "element": [ + { + "path": "Alert", + "definition": { + "short": "Key information to flag to healthcare providers", + "formal": "Prospective warnings of potential issues when providing care to the patient.", + "min": 1, + "max": "1", + "type": [ + { + "code": "Resource" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "Observation[classCode=ISSUE, moodCode=EVN]" + } + ] + } + }, + { + "path": "Alert.extension", + "definition": { + "short": "Additional Content defined by implementations", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Alert.modifierExtension", + "definition": { + "short": "Extensions that cannot be ignored", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Alert.text", + "definition": { + "short": "Text summary of the resource, for human interpretation", + "formal": "A human-readable narrative that contains a summary of the resource, and may be used to represent the content of the resource to a human. The narrative need not encode all the structured data, but is required to contain sufficient detail to make it \"clinically safe\" for a human to just read the narrative. Resource definitions may define what content should be represented in the narrative to ensure clinical safety.", + "comments": "Contained resources do not have narrative. Resources that are not contained SHOULD have a narrative.", + "synonym": [ + "narrative", + "html", + "xhtml", + "display" + ], + "min": 0, + "max": "1", + "type": [ + { + "code": "Narrative" + } + ], + "isModifier": false + } + }, + { + "path": "Alert.contained", + "definition": { + "short": "Contained, inline Resources", + "formal": "These resources do not have an independent existence apart from the resource that contains them - they cannot be identified independently, and nor can they have their own independent transaction scope.", + "comments": "This should never be done when the content can be identified properly, as once identification is lost, it is extremely difficult (and context dependent) to restore it again.", + "synonym": [ + "inline resources", + "anonymous resources", + "contained resources" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Resource" + } + ], + "isModifier": false + } + }, + { + "path": "Alert.identifier", + "definition": { + "short": "Business identifier", + "formal": "Identifier assigned to the alert for external use (outside the FHIR environment).", + "min": 0, + "max": "*", + "type": [ + { + "code": "Identifier" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": ".id" + } + ] + } + }, + { + "path": "Alert.category", + "definition": { + "short": "Clinical, administrative, etc.", + "formal": "Allows an alert to be divided into different categories like clinical, administrative etc.", + "min": 0, + "max": "1", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": ".code" + } + ] + } + }, + { + "path": "Alert.status", + "definition": { + "short": "active | inactive | entered in error", + "formal": "Supports basic workflow.", + "min": 1, + "max": "1", + "type": [ + { + "code": "code" + } + ], + "isModifier": false, + "binding": { + "name": "AlertStatus", + "isExtensible": false, + "conformance": "required", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/alert-status" + } + }, + "mapping": [ + { + "identity": "rim", + "map": ".status" + } + ] + } + }, + { + "path": "Alert.subject", + "definition": { + "short": "Who is alert about?", + "formal": "The person who this alert concerns.", + "min": 1, + "max": "1", + "type": [ + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Patient" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": ".participation[typeCode=SBJ].role[classCode=PAT]" + } + ] + } + }, + { + "path": "Alert.author", + "definition": { + "short": "Alert creator", + "formal": "The person or device that created the alert.", + "min": 0, + "max": "1", + "type": [ + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Practitioner" + }, + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Patient" + }, + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Device" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": ".participation[typeCode=AUT].role" + } + ] + } + }, + { + "path": "Alert.note", + "definition": { + "short": "Text of alert", + "formal": "The textual component of the alert to display to the user.", + "min": 1, + "max": "1", + "type": [ + { + "code": "string" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": ".value" + } + ] + } + } + ], + "searchParam": [ + { + "name": "_id", + "type": "token", + "documentation": "The logical resource id associated with the resource (must be supported by all servers)" + }, + { + "name": "_language", + "type": "token", + "documentation": "The language of the resource" + }, + { + "name": "subject", + "type": "reference", + "documentation": "The identity of a subject to list alerts for", + "xpath": "f:Alert/f:subject" + } + ] + } + ] +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/atom-document-large.json b/hapi-fhir-structures-dstu/src/test/resources/atom-document-large.json new file mode 100644 index 00000000000..e1fbe3a9a38 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/atom-document-large.json @@ -0,0 +1,3281 @@ +{ + "resourceType" : "Bundle", + "title" : "Search results for resource type DiagnosticReport", + "id" : "urn:uuid:0b754ff9-03cf-4322-a119-15019af8a3", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/", + "rel" : "fhir-base" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id", + "rel" : "self" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id&search-offset=0&_count=50", + "rel" : "first" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id&search-offset=50&_count=50", + "rel" : "next" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/_search?_format=application/json+fhir&search-id=46d5f0e7-9240-4d4f-9f51-f8ac975c65&search-sort=_id&search-offset=306&_count=50", + "rel" : "last" + } + ], + "updated" : "2014-03-22T15:37:12Z", + "category" : [{ + "term" : "http://term", + "label" : "label", + "scheme" : "http://scheme" + }], + "totalResults" : "356", + "entry" : [ + { + "title" : "DiagnosticReport \"101\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/101", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/101/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:55:59Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n

CBC Report for Wile. E. COYOTE (MRN: 23453) issued 3-Mar 2011 11:45

\r\n \r\n
Test                  Units       Value       Reference Range
Haemoglobin           g/L         176         135 - 180
Red Cell Count        x10*12/L    5.9         4.2 - 6.0
Haematocrit                       0.55+       0.38 - 0.52
Mean Cell Volume      fL          99+         80 - 98
Mean Cell Haemoglobin pg          36+         27 - 35
Platelet Count        x10*9/L     444         150 - 450
White Cell Count      x10*9/L     4.6         4.0 - 11.0
Neutrophils           %           20 
Neutrophils           x10*9/L     0.9---      2.0 - 7.5
Lymphocytes           %           20  
Lymphocytes           x10*9/L     0.9-        1.1 - 4.0
Monocytes             %           20 
Monocytes             x10*9/L     0.9         0.2 - 1.0
Eosinophils           %           20 
Eosinophils           x10*9/L     0.92++      0.04 - 0.40
Basophils             %           20 
Basophils             x10*9/L     0.92+++     <0.21
      
\r\n

Acme Laboratory, Inc signed: Dr Pete Pathologist

" + }, + "contained" : [ + { + "resourceType" : "Observation", + "id" : "r1", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "718-7", + "display" : "Hemoglobin [Mass/volume] in Blood" + } + ], + "text" : "Haemoglobin" + }, + "valueQuantity" : { + "value" : "176", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "135", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + }, + "high" : { + "value" : "180", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r2", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "789-8", + "display" : "Erythrocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Red Cell Count" + }, + "valueQuantity" : { + "value" : "5.9", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "4.2", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + }, + "high" : { + "value" : "6.0", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r3", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "4544-3", + "display" : "Hematocrit [Volume Fraction] of Blood by Automated count" + } + ], + "text" : "Haematocrit" + }, + "valueQuantity" : { + "value" : "55", + "units" : "%" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "38", + "units" : "%" + }, + "high" : { + "value" : "52", + "units" : "%" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r4", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "787-2", + "display" : "Erythrocyte mean corpuscular volume [Entitic volume] by Automated count" + } + ], + "text" : "Mean Cell Volume" + }, + "valueQuantity" : { + "value" : "99", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "80", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + }, + "high" : { + "value" : "98", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r5", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "785-6", + "display" : "Erythrocyte mean corpuscular hemoglobin [Entitic mass] by Automated count" + } + ], + "text" : "Mean Cell Haemoglobin" + }, + "valueQuantity" : { + "value" : "36", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "27", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + }, + "high" : { + "value" : "35", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r6", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "777-3", + "display" : "Platelets [#/volume] in Blood by Automated count" + } + ], + "text" : "Platelet Count" + }, + "valueQuantity" : { + "value" : "444", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "150", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "450", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r7", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "6690-2", + "display" : "Leukocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "White Cell Count" + }, + "valueQuantity" : { + "value" : "4.6", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "4.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "11.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r8", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "770-8", + "display" : "Neutrophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Neutrophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r9", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "751-8", + "display" : "Neutrophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Neutrophils" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "LL" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "2.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "7.5", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r10", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "736-9", + "display" : "Lymphocytes/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Lymphocytes" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r11", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "731-0", + "display" : "Lymphocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Lymphocytes" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "L" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "1.1", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "4.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r12", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "5905-5", + "display" : "Monocytes/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Monocytes" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r13", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "742-7", + "display" : "Monocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Monocytes" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "0.2", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "1.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r14", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "713-8", + "display" : "Eosinophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Eosinophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r15", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "711-2", + "display" : "Eosinophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Eosinophils" + }, + "valueQuantity" : { + "value" : "0.92", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "HH" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "0.04", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "0.40", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r16", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "706-2", + "display" : "Basophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Basophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r17", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "704-7", + "display" : "Basophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Basophils" + }, + "valueQuantity" : { + "value" : "0.92", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "high" : { + "value" : "0.21", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + } + ], + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "58410-2", + "display" : "Complete blood count (hemogram) panel - Blood by Automated count" + }, + { + "code" : "CBC", + "display" : "MASTER FULL BLOOD COUNT" + } + ], + "text" : "Complete Blood Count" + }, + "status" : "final", + "issued" : "2011-03-04T11:45:33+11:00", + "_issued" : { + }, + "subject" : { + "reference" : "Patient/pat2" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "5234342" + }, + "serviceCategory" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0074", + "code" : "HM" + } + ] + }, + "diagnosticDateTime" : "2011-03-04T08:30:00+11:00", + "result" : [ + { + "reference" : "#r1" + }, + { + "reference" : "#r2" + }, + { + "reference" : "#r3" + }, + { + "reference" : "#r4" + }, + { + "reference" : "#r5" + }, + { + "reference" : "#r6" + }, + { + "reference" : "#r7" + }, + { + "reference" : "#r8" + }, + { + "reference" : "#r9" + }, + { + "reference" : "#r10" + }, + { + "reference" : "#r11" + }, + { + "reference" : "#r12" + }, + { + "reference" : "#r13" + }, + { + "reference" : "#r14" + }, + { + "reference" : "#r15" + }, + { + "reference" : "#r16" + }, + { + "reference" : "#r17" + } + ], + "presentedForm" : [ + { + "contentType" : "application/pdf", + "language" : "en-AU", + "data" : "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PSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz48cGRmOlByb2R1Y2VyPkdQTCBHaG9zdHNjcmlwdCA5LjA0PC9wZGY6UHJvZHVjZXI+CjxwZGY6S2V5d29yZHM+KCk8L3BkZjpLZXl3b3Jkcz4KPC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSdlOTA4ODRhMy0zYzlhLTExZTEtMDAwMC02NDI2MDMzYWE1MCYjODsnIHhtbG5zOnhtcD0naHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyc+PHhtcDpNb2RpZnlEYXRlPjIwMTItMDEtMDlUMDg6MjU6NTQrMTE6MDA8L3htcDpNb2RpZnlEYXRlPgo8eG1wOkNyZWF0ZURhdGU+MjAxMi0wMS0wOVQwODoyNTo1NCsxMTowMDwveG1wOkNyZWF0ZURhdGU+Cjx4bXA6Q3JlYXRvclRvb2w+UERGQ3JlYXRvciBWZXJzaW9uIDEuMi4zPC94bXA6Q3JlYXRvclRvb2w+PC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSdlOTA4ODRhMy0zYzlhLTExZTEtMDAwMC02NDI2MDMzYWE1MCYjODsnIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vJyB4YXBNTTpEb2N1bWVudElEPSd1dWlkOmU5MDg4NGEzLTNjOWEtMTFlMS0wMDAwLTY0MjYwMzNhYTUwJiMxMzg7pyYjMTU3O+7SYyYjMzE7JiMxNjsnLz4KPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9J2U5MDg4NGEzLTNjOWEtMTFlMS0wMDAwLTY0MjYwMzNhYTUwJiM4OycgeG1sbnM6ZGM9J2h0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJyBkYzpmb3JtYXQ9J2FwcGxpY2F0aW9uL3BkZic+PGRjOnRpdGxlPjxyZGY6QWx0PjxyZGY6bGkgeG1sOmxhbmc9J3gtZGVmYXVsdCc+Q0JDIFJlcG9ydCBmb3IgV2lsZS4gRS4gQ09ZT1RFIChNUk46IDIzNDUzKSBpc3N1ZWQgMy1NYXIgMjAxMSAxMTo0NTwvcmRmOmxpPjwvcmRmOkFsdD48L2RjOnRpdGxlPjxkYzpjcmVhdG9yPjxyZGY6U2VxPjxyZGY6bGk+R3JhaGFtZTwvcmRmOmxpPjwvcmRmOlNlcT48L2RjOmNyZWF0b3I+PGRjOmRlc2NyaXB0aW9uPjxyZGY6U2VxPjxyZGY6bGk+KCk8L3JkZjpsaT48L3JkZjpTZXE+PC9kYzpkZXNjcmlwdGlvbj48L3JkZjpEZXNjcmlwdGlvbj4KPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSd3Jz8+CmVuZHN0cmVhbQplbmRvYmoKMiAwIG9iago8PC9Qcm9kdWNlcihHUEwgR2hvc3RzY3JpcHQgOS4wNCkKL0NyZWF0aW9uRGF0ZShEOjIwMTIwMTA5MDgyNTU0KzExJzAwJykKL01vZERhdGUoRDoyMDEyMDEwOTA4MjU1NCsxMScwMCcpCi9UaXRsZShcMzc2XDM3N1wwMDBDXDAwMEJcMDAwQ1wwMDAgXDAwMFJcMDAwZVwwMDBwXDAwMG9cMDAwclwwMDB0XDAwMCBcMDAwZlwwMDBvXDAwMHJcMDAwIFwwMDBXXDAwMGlcMDAwbFwwMDBlXDAwMC5cMDAwIFwwMDBFXDAwMC5cMDAwIFwwMDBDXDAwME9cMDAwWVwwMDBPXDAwMFRcMDAwRVwwMDAgXDAwMFwoXDAwME1cMDAwUlwwMDBOXDAwMDpcMDAwIFwwMDAyXDAwMDNcMDAwNFwwMDA1XDAwMDNcMDAwXClcMDAwIFwwMDBpXDAwMHNcMDAwc1wwMDB1XDAwMGVcMDAwZFwwMDAgXDAwMDNcMDAwLVwwMDBNXDAwMGFcMDAwclwwMDAgXDAwMDJcMDAwMFwwMDAxXDAwMDFcMDAwIFwwMDAxXDAwMDFcMDAwOlwwMDA0XDAwMDUpCi9DcmVhdG9yKFwzNzZcMzc3XDAwMFBcMDAwRFwwMDBGXDAwMENcMDAwclwwMDBlXDAwMGFcMDAwdFwwMDBvXDAwMHJcMDAwIFwwMDBWXDAwMGVcMDAwclwwMDBzXDAwMGlcMDAwb1wwMDBuXDAwMCBcMDAwMVwwMDAuXDAwMDJcMDAwLlwwMDAzKQovQXV0aG9yKFwzNzZcMzc3XDAwMEdcMDAwclwwMDBhXDAwMGhcMDAwYVwwMDBtXDAwMGUpCi9LZXl3b3JkcygpCi9TdWJqZWN0KCk+PmVuZG9iagp4cmVmCjAgMjEKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAyMTM3IDAwMDAwIG4gCjAwMDAwNjg3OTMgMDAwMDAgbiAKMDAwMDAwMjA3OCAwMDAwMCBuIAowMDAwMDAxOTM2IDAwMDAwIG4gCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMTkxNiAwMDAwMCBuIAowMDAwMDAyNjU2IDAwMDAwIG4gCjAwMDAwMDQ2ODEgMDAwMDAgbiAKMDAwMDAwMzQ3OSAwMDAwMCBuIAowMDAwMDIxNTc3IDAwMDAwIG4gCjAwMDAwMDQzMjkgMDAwMDAgbiAKMDAwMDA0MTMwNyAwMDAwMCBuIAowMDAwMDAyMjAyIDAwMDAwIG4gCjAwMDAwMDQ5MDUgMDAwMDAgbiAKMDAwMDAyMTc5MyAwMDAwMCBuIAowMDAwMDQxNTI5IDAwMDAwIG4gCjAwMDAwMDIyNTIgMDAwMDAgbiAKMDAwMDAwMjk0OCAwMDAwMCBuIAowMDAwMDAzODMxIDAwMDAwIG4gCjAwMDAwNjcwODggMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSAyMSAvUm9vdCAxIDAgUiAvSW5mbyAyIDAgUgovSUQgWzw4RDdGNzc5QTAwQzcwOTc5NTg3MDQyRjA5MkJBQjhDNj48OEQ3Rjc3OUEwMEM3MDk3OTU4NzA0MkYwOTJCQUI4QzY+XQo+PgpzdGFydHhyZWYKNjk0ODUKJSVFT0YK", + "title" : "HTML Report" + } + ] + }, + "summary" : "\r\n
\r\n

CBC Report for Wile. E. COYOTE (MRN: 23453) issued 3-Mar 2011 11:45

\r\n \r\n
Test                  Units       Value       Reference Range
Haemoglobin           g/L         176         135 - 180
Red Cell Count        x10*12/L    5.9         4.2 - 6.0
Haematocrit                       0.55+       0.38 - 0.52
Mean Cell Volume      fL          99+         80 - 98
Mean Cell Haemoglobin pg          36+         27 - 35
Platelet Count        x10*9/L     444         150 - 450
White Cell Count      x10*9/L     4.6         4.0 - 11.0
Neutrophils           %           20 
Neutrophils           x10*9/L     0.9---      2.0 - 7.5
Lymphocytes           %           20  
Lymphocytes           x10*9/L     0.9-        1.1 - 4.0
Monocytes             %           20 
Monocytes             x10*9/L     0.9         0.2 - 1.0
Eosinophils           %           20 
Eosinophils           x10*9/L     0.92++      0.04 - 0.40
Basophils             %           20 
Basophils             x10*9/L     0.92+++     <0.21
      
\r\n

Acme Laboratory, Inc signed: Dr Pete Pathologist

" + }, + { + "title" : "DiagnosticReport \"102\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/102", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/102/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:00Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n

DXA BONE DENSITOMETRY

\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
NAMEXXXXXXX
DOB10/02/1974
REFERRING DRSmith, Jane
INDICATIONSEarly menopause on estrogen levels. No period for 18 months
PROCEDUREDual energy x-ray absorptiometry (DEXA)
\r\n

Bone Mineral Density

\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
Scan TypeRegionMeasuredAgeBMDT-ScoreZ-ScoreΔBMD(g/cm2)ΔBMD(%)
AP SpineL1-L417/06/200834.41.148 g/cm²-0.4-0.5--
Left FemurNeck17/06/200834.40.891 g/cm²-1.0-0.9--
Left FemurTotal17/06/200834.40.887 g/cm²-1.2-1.3--
Right FemurNeck17/06/200834.40.885 g/cm²-1.0-1.0--
Right FemurTotal17/06/200834.40.867 g/cm²-1.4-1.4--
\r\n

Assessment:

\r\n
    \r\n
  • The Spine L1-L4 BMD is normal.
  • \r\n
  • The Left Femur Neck BMD is in the osteopenic range. Relative fracture risk is about 2.
  • \r\n
  • The Left Femur Total BMD is in the osteopenic range. Relative fracture risk is about 2.
  • \r\n
  • The Right Femur Neck BMD is in the osteopenic range. Relative fracture risk is about 2.
  • \r\n
  • The Right Femur Total BMD is in the osteopenic range. Relative fracture risk is about 2.
\r\n

\r\n COMMENT

\r\n

Osteopenia on measured BMD. The estimated 10-year probability of fracture based on present age, gender and measured BMD is less than 10%. This absolute fracture risk remains low. A follow-up assessment may be considered in 2 to 3 years to monitor the trend in BMD.

\r\n

Thank you for your referral. Dr Peter Ng 17/06/2008

\r\n
Note:
WHO classification of osteoporosis (WHO Technical Report Series 1994: 843)
- Normal: T-score equal to -1.0 s.d. or higher
- Osteopenia: T-score  between -1.0 and -2.5 s.d.
- Osteoporosis: T-score equal to -2.5 s.d. or lower
- Severe/Established osteoporosis: Osteoporosis with one or more fragility fracture.

T-score: The number of s.d. from the mean BMD for a gender-matched young adult population. 
Z-score: The number of s.d. from the mean BMD for an age-, weight- and gender-matched population.

Reference for 10-year probability of fracture risk: Kanis JA, Johnell O, Oden A, Dawson A,  De Laet C, Jonsson B. Ten year probabilities of osteoporotic fractures according to BMD and diagnostic thresholds. Osteoporos.Int. 2001;12(12):989-995.

GE LUNAR PRODIGY DENSITOMETER
" + }, + "contained" : [ + { + "resourceType" : "Observation", + "id" : "r1", + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "24701-5", + "display" : "Femur DXA Bone density" + } + ] + }, + "valueQuantity" : { + "value" : "0.887", + "units" : "g/cm²", + "system" : "http://unitsofmeasure.org", + "code" : "g/cm-2" + }, + "status" : "final", + "reliability" : "ok", + "bodySite" : { + "coding" : [ + { + "system" : "http://snomed.info/sct", + "code" : "71341001:272741003=7771000" + } + ] + } + } + ], + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "38269-7" + } + ], + "text" : "DXA BONE DENSITOMETRY" + }, + "status" : "final", + "issued" : "2008-06-18T09:23:00+10:00", + "_issued" : { + }, + "subject" : { + "reference" : "Patient/pat2" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Imaging Diagnostics" + }, + "diagnosticDateTime" : "2008-06-17", + "result" : [ + { + "reference" : "#r1" + } + ], + "codedDiagnosis" : [ + { + "coding" : [ + { + "system" : "http://snomed.info/sct", + "code" : "391040000", + "display" : "At risk of osteoporotic fracture" + } + ] + } + ] + }, + "summary" : "\r\n
\r\n

DXA BONE DENSITOMETRY

\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
NAMEXXXXXXX
DOB10/02/1974
REFERRING DRSmith, Jane
INDICATIONSEarly menopause on estrogen levels. No period for 18 months
PROCEDUREDual energy x-ray absorptiometry (DEXA)
\r\n

Bone Mineral Density

\r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n \r\n
Scan TypeRegionMeasuredAgeBMDT-ScoreZ-ScoreΔBMD(g/cm2)ΔBMD(%)
AP SpineL1-L417/06/200834.41.148 g/cm²-0.4-0.5--
Left FemurNeck17/06/200834.40.891 g/cm²-1.0-0.9--
Left FemurTotal17/06/200834.40.887 g/cm²-1.2-1.3--
Right FemurNeck17/06/200834.40.885 g/cm²-1.0-1.0--
Right FemurTotal17/06/200834.40.867 g/cm²-1.4-1.4--
\r\n

Assessment:

\r\n
    \r\n
  • The Spine L1-L4 BMD is normal.
  • \r\n
  • The Left Femur Neck BMD is in the osteopenic range. Relative fracture risk is about 2.
  • \r\n
  • The Left Femur Total BMD is in the osteopenic range. Relative fracture risk is about 2.
  • \r\n
  • The Right Femur Neck BMD is in the osteopenic range. Relative fracture risk is about 2.
  • \r\n
  • The Right Femur Total BMD is in the osteopenic range. Relative fracture risk is about 2.
\r\n

\r\n COMMENT

\r\n

Osteopenia on measured BMD. The estimated 10-year probability of fracture based on present age, gender and measured BMD is less than 10%. This absolute fracture risk remains low. A follow-up assessment may be considered in 2 to 3 years to monitor the trend in BMD.

\r\n

Thank you for your referral. Dr Peter Ng 17/06/2008

\r\n
Note:
WHO classification of osteoporosis (WHO Technical Report Series 1994: 843)
- Normal: T-score equal to -1.0 s.d. or higher
- Osteopenia: T-score  between -1.0 and -2.5 s.d.
- Osteoporosis: T-score equal to -2.5 s.d. or lower
- Severe/Established osteoporosis: Osteoporosis with one or more fragility fracture.

T-score: The number of s.d. from the mean BMD for a gender-matched young adult population. 
Z-score: The number of s.d. from the mean BMD for an age-, weight- and gender-matched population.

Reference for 10-year probability of fracture risk: Kanis JA, Johnell O, Oden A, Dawson A,  De Laet C, Jonsson B. Ten year probabilities of osteoporotic fractures according to BMD and diagnostic thresholds. Osteoporos.Int. 2001;12(12):989-995.

GE LUNAR PRODIGY DENSITOMETER
" + }, + { + "title" : "DiagnosticReport \"103\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/103", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/103/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:00Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z168748  Z968634  Z986932
      Date:  10/12/02 05/04/12 05/04/12
      Time:     16:00    11:15    23:30                   Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.1        *        *                          0.8-1.3
APTT               26        *        *                    secs  23-36
Fibrinogen        8.1H       *        *                    g/L   2.0-5.0

12Z968932 05/04/12 23:30
Comment: Please note specimen clotted. Ward notified.

12Z968634 05/04/12 11:15
Comment: * Specimen clotted.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/112" + }, + "clinicalNotes" : "Automatic Request Registration" + } + ], + "name" : { + "text" : "Routine Coagulation" + }, + "status" : "final", + "issued" : "2012-04-06T00:38:00Z", + "subject" : { + "reference" : "Patient/112" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986932-16258709" + }, + "diagnosticDateTime" : "2012-04-05T23:30:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z168748  Z968634  Z986932
      Date:  10/12/02 05/04/12 05/04/12
      Time:     16:00    11:15    23:30                   Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.1        *        *                          0.8-1.3
APTT               26        *        *                    secs  23-36
Fibrinogen        8.1H       *        *                    g/L   2.0-5.0

12Z968932 05/04/12 23:30
Comment: Please note specimen clotted. Ward notified.

12Z968634 05/04/12 11:15
Comment: * Specimen clotted.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + { + "title" : "DiagnosticReport \"104\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/104", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/104/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:01Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z916580  Z661921  Z766455  Z986634  Z968932
  Date:  09/10/06 26/03/07 28/09/07 05/04/12 05/04/12
  Time:     09:25    10:10    08:45    11:15    23:30  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            130      119      121      136      129  g/L       115-150
WCC           6.1      5.5      6.0      8.9      8.6  x10^9/L   4.0-11.0
PLT           263      237      264        *      213  x10^9/L   140-400
RCC          4.92     4.41     4.58     4.63     4.42  x10^12/L  3.80-5.10
PCV          0.39     0.35     0.36     0.39     0.38  L/L       0.35-0.45
MCV          79.3L    79.7L    79.3L    84.6     86.0  fL        80.0-96.0
MCH          26.5L    26.8L    26.3L    29.3     29.3  pg        27.0-33.0
MCHC          334      337      332      346      341  g/L       320-360
RDW          15.1H    15.5H    15.2H    13.7     14.0  %         11.0-15.0
White Cell Differential
Neut         3.8      2.9      3.4      6.7      6.2   x10^9/L   2.0-8.0
Lymph        1.6      2.0      2.0      1.5      1.5   x10^9/L   1.2-4.0
Mono         0.4      0.5      0.5      0.6      0.8   x10^9/L   0.1-1.0
Eos          0.2      0.0      0.1      0.0      0.0   x10^9/L   0.0-0.5
Baso         0.0      0.0      0.0      0.0      0.1   x10^9/L   0.0-0.1

07Z661921 26/03/07 10:10
Film Comment : Film scanned.

12Z986634 05/04/12 11:15
Film Comment : Platelets are clumped, but appear adequate in number. Red
               cells are mainly normocytic normochromic with mild
               rouleaux. White cells appear normal.
Comment: *PLEASE NOTE AMENDED REPORT*
" + }, + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T23:59:00Z", + "subject" : { + "reference" : "Patient/112" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968932-16258708" + }, + "diagnosticDateTime" : "2012-04-05T23:30:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z916580  Z661921  Z766455  Z986634  Z968932
  Date:  09/10/06 26/03/07 28/09/07 05/04/12 05/04/12
  Time:     09:25    10:10    08:45    11:15    23:30  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            130      119      121      136      129  g/L       115-150
WCC           6.1      5.5      6.0      8.9      8.6  x10^9/L   4.0-11.0
PLT           263      237      264        *      213  x10^9/L   140-400
RCC          4.92     4.41     4.58     4.63     4.42  x10^12/L  3.80-5.10
PCV          0.39     0.35     0.36     0.39     0.38  L/L       0.35-0.45
MCV          79.3L    79.7L    79.3L    84.6     86.0  fL        80.0-96.0
MCH          26.5L    26.8L    26.3L    29.3     29.3  pg        27.0-33.0
MCHC          334      337      332      346      341  g/L       320-360
RDW          15.1H    15.5H    15.2H    13.7     14.0  %         11.0-15.0
White Cell Differential
Neut         3.8      2.9      3.4      6.7      6.2   x10^9/L   2.0-8.0
Lymph        1.6      2.0      2.0      1.5      1.5   x10^9/L   1.2-4.0
Mono         0.4      0.5      0.5      0.6      0.8   x10^9/L   0.1-1.0
Eos          0.2      0.0      0.1      0.0      0.0   x10^9/L   0.0-0.5
Baso         0.0      0.0      0.0      0.0      0.1   x10^9/L   0.0-0.1

07Z661921 26/03/07 10:10
Film Comment : Film scanned.

12Z986634 05/04/12 11:15
Film Comment : Platelets are clumped, but appear adequate in number. Red
               cells are mainly normocytic normochromic with mild
               rouleaux. White cells appear normal.
Comment: *PLEASE NOTE AMENDED REPORT*
" + }, + { + "title" : "DiagnosticReport \"105\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/105", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/105/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:01Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Request No:  Z516369
      Date: 05/04/12                                              Arterial
      Time:    23:55                                      Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0                                      Deg. C
pH              7.38                                              7.35-7.45
pCO2              55H                                     mmHg    35-45
Base Excess      7.1H                                     mmol/L  -3.0/3.0
pO2               30L                                     mmHg    75-100
O2 Sat            41L                                     %       95-100

ELECTROLYTES (Whole Blood)
Potassium        4.3                                      mmol/L  3.5-5.5
Sodium           141                                      mmol/L  135-145

BLOOD CO-OXIMETRY
Total   Hb       145                                      g/L     130-170

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/113" + }, + "clinicalNotes" : "Automatic Request Registration" + } + ], + "name" : { + "text" : "Blood Gas" + }, + "status" : "final", + "issued" : "2012-04-05T23:57:00Z", + "subject" : { + "reference" : "Patient/113" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z561369-16258707" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T23:55:00" + }, + "summary" : "\r\n
\r\n
Request No:  Z516369
      Date: 05/04/12                                              Arterial
      Time:    23:55                                      Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0                                      Deg. C
pH              7.38                                              7.35-7.45
pCO2              55H                                     mmHg    35-45
Base Excess      7.1H                                     mmol/L  -3.0/3.0
pO2               30L                                     mmHg    75-100
O2 Sat            41L                                     %       95-100

ELECTROLYTES (Whole Blood)
Potassium        4.3                                      mmol/L  3.5-5.5
Sodium           141                                      mmol/L  135-145

BLOOD CO-OXIMETRY
Total   Hb       145                                      g/L     130-170

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + { + "title" : "DiagnosticReport \"106\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/106", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/106/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:01Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Anti-Factor Xa Assay (Plasma)
Heparin Level by Anti-Xa          0.03   U/mL

Anti-Factor Xa Comment:
   Reference range for Anti-Xa level depends upon route, time, dose and
   reason for anticoagulation.
   Therapeutic anticoagulation with LMWH (such as Enoxaparin) generally does
   not require routine monitoring. However, anti-Xa levels are recommended
   for patients on LMWH requiring dose adjustment in settings of (1) renal
   impairment, (2) obesity and (3) pregnancy.  To assist interpretation of
   therapeutic ranges, anti-Xa levels should be collected four hours after
   the third dose.  For less common indications such a patients at high risk
   of bleeding, and interpretation of results, please contact the on-call
   laboratory Haematology registrar or Haematologist via ACME switchboard.

" + }, + "name" : { + "text" : "Special Coagulation" + }, + "status" : "final", + "issued" : "2012-04-06T00:23:00Z", + "subject" : { + "reference" : "Patient/114" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968942-16258706" + }, + "diagnosticDateTime" : "2012-04-05T23:40:00" + }, + "summary" : "\r\n
\r\n
Anti-Factor Xa Assay (Plasma)
Heparin Level by Anti-Xa          0.03   U/mL

Anti-Factor Xa Comment:
   Reference range for Anti-Xa level depends upon route, time, dose and
   reason for anticoagulation.
   Therapeutic anticoagulation with LMWH (such as Enoxaparin) generally does
   not require routine monitoring. However, anti-Xa levels are recommended
   for patients on LMWH requiring dose adjustment in settings of (1) renal
   impairment, (2) obesity and (3) pregnancy.  To assist interpretation of
   therapeutic ranges, anti-Xa levels should be collected four hours after
   the third dose.  For less common indications such a patients at high risk
   of bleeding, and interpretation of results, please contact the on-call
   laboratory Haematology registrar or Haematologist via ACME switchboard.

" + }, + { + "title" : "DiagnosticReport \"107\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/107", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/107/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:01Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z968427  Z968448  Z986671  Z968774  Z968942
      Date:  05/04/12 05/04/12 05/04/12 05/04/12 05/04/12
      Time:     03:30    05:10    09:10    17:02    23:40 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.7H     1.7H                                  0.8-1.3
APTT               31       31       27       31       35  secs  23-36
Fibrinogen        1.9L     1.8L                            g/L   2.0-5.0

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + "name" : { + "text" : "Routine Coagulation" + }, + "status" : "final", + "issued" : "2012-04-06T00:19:00Z", + "subject" : { + "reference" : "Patient/114" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986942-16258705" + }, + "diagnosticDateTime" : "2012-04-05T23:40:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z968427  Z968448  Z986671  Z968774  Z968942
      Date:  05/04/12 05/04/12 05/04/12 05/04/12 05/04/12
      Time:     03:30    05:10    09:10    17:02    23:40 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.7H     1.7H                                  0.8-1.3
APTT               31       31       27       31       35  secs  23-36
Fibrinogen        1.9L     1.8L                            g/L   2.0-5.0

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + { + "title" : "DiagnosticReport \"108\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/108", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/108/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:01Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z466872  Z864523  Z560485  Z896274  Z968972
      Date:  08/01/09 08/01/09 17/02/09 19/02/09 05/04/12
      Time:     08:10    09:34    15:30    06:00    23:10 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR                 *      1.0      0.8      0.9      1.0        0.8-1.3
APTT                *       23L      25       25       24  secs  23-36
Fibrinogen          *      3.5      2.9      3.3      5.3H g/L   2.0-5.0

09Z466872 08/01/09 08:10
Comment: * Note: unsuitable specimen - tube underfilled.   Please
         fill coag. tubes to the blue line.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + "name" : { + "text" : "Routine Coagulation" + }, + "status" : "final", + "issued" : "2012-04-06T00:19:00Z", + "subject" : { + "reference" : "Patient/115" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968972-16258704" + }, + "diagnosticDateTime" : "2012-04-05T23:10:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z466872  Z864523  Z560485  Z896274  Z968972
      Date:  08/01/09 08/01/09 17/02/09 19/02/09 05/04/12
      Time:     08:10    09:34    15:30    06:00    23:10 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR                 *      1.0      0.8      0.9      1.0        0.8-1.3
APTT                *       23L      25       25       24  secs  23-36
Fibrinogen          *      3.5      2.9      3.3      5.3H g/L   2.0-5.0

09Z466872 08/01/09 08:10
Comment: * Note: unsuitable specimen - tube underfilled.   Please
         fill coag. tubes to the blue line.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + { + "title" : "DiagnosticReport \"109\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/109", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/109/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:01Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            141     mmol/L ( 135-145  )
Potassium         3.9     mmol/L ( 3.5-5.5  )
Chloride          108     mmol/L ( 95-110   )
HCO3               25     mmol/L ( 22-30    )
Creatinine         62     umol/L ( 64-104   )
 (Creatinine)    0.062    mmol/L ( 0.05-0.11)
Urea              6.3     mmol/L ( 2.5-8.3  )
 eGFR             >90            ( SEE-BELOW)
Calcium          2.40     mmol/L ( 2.10-2.60)
Phosphate        1.74     mmol/L ( 0.8-1.5  )
Magnesium        0.87     mmol/L ( 0.7-1.1  )
Albumin            32     g/L    ( 35-50    )
Troponin I       24.15    ug/L   (See Below )
CK                828     IU/L   ( <175     )
" + }, + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-06T00:39:00Z", + "subject" : { + "reference" : "Patient/115" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986972-16258703" + }, + "diagnosticDateTime" : "2012-04-05T23:10:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            141     mmol/L ( 135-145  )
Potassium         3.9     mmol/L ( 3.5-5.5  )
Chloride          108     mmol/L ( 95-110   )
HCO3               25     mmol/L ( 22-30    )
Creatinine         62     umol/L ( 64-104   )
 (Creatinine)    0.062    mmol/L ( 0.05-0.11)
Urea              6.3     mmol/L ( 2.5-8.3  )
 eGFR             >90            ( SEE-BELOW)
Calcium          2.40     mmol/L ( 2.10-2.60)
Phosphate        1.74     mmol/L ( 0.8-1.5  )
Magnesium        0.87     mmol/L ( 0.7-1.1  )
Albumin            32     g/L    ( 35-50    )
Troponin I       24.15    ug/L   (See Below )
CK                828     IU/L   ( <175     )
" + }, + { + "title" : "DiagnosticReport \"110\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/110", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/110/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:01Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
THYROID FUNCTION
Free T4                   75.1    H  pmol/L  ( 9.0-26.0 )
Free T3                   14.9    H  pmol/L  ( 3.5-6.5  )
TSH                       0.01    L  mIU/L   ( 0.1-4.0  )



" + }, + "name" : { + "text" : "Endo / Nutrition" + }, + "status" : "final", + "issued" : "2012-04-06T05:49:00Z", + "subject" : { + "reference" : "Patient/115" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968972-16258702" + }, + "diagnosticDateTime" : "2012-04-05T23:10:00" + }, + "summary" : "\r\n
\r\n
THYROID FUNCTION
Free T4                   75.1    H  pmol/L  ( 9.0-26.0 )
Free T3                   14.9    H  pmol/L  ( 3.5-6.5  )
TSH                       0.01    L  mIU/L   ( 0.1-4.0  )



" + }, + { + "title" : "DiagnosticReport \"1100\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1100", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1100/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:16Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            139     mmol/L ( 135-145  )
Potassium         3.9     mmol/L ( 3.5-5.5  )
Chloride          110     mmol/L ( 95-110   )
HCO3               18     mmol/L ( 22-30    )
Creatinine        132     umol/L ( 49-90    )
 (Creatinine)    0.132    mmol/L ( 0.05-0.09)
Urea             10.7     mmol/L ( 2.5-8.3  )
 eGFR             35             ( SEE-BELOW)
Calcium          2.09     mmol/L ( 2.10-2.60)
Phosphate        1.66     mmol/L ( 0.8-1.5  )
Magnesium        1.10     mmol/L ( 0.8-1.0  )
Albumin            28     g/L    ( 35-50    )
" + }, + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T22:31:00Z", + "subject" : { + "reference" : "Patient/121" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986819-16258609" + }, + "diagnosticDateTime" : "2012-04-05T21:40:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            139     mmol/L ( 135-145  )
Potassium         3.9     mmol/L ( 3.5-5.5  )
Chloride          110     mmol/L ( 95-110   )
HCO3               18     mmol/L ( 22-30    )
Creatinine        132     umol/L ( 49-90    )
 (Creatinine)    0.132    mmol/L ( 0.05-0.09)
Urea             10.7     mmol/L ( 2.5-8.3  )
 eGFR             35             ( SEE-BELOW)
Calcium          2.09     mmol/L ( 2.10-2.60)
Phosphate        1.66     mmol/L ( 0.8-1.5  )
Magnesium        1.10     mmol/L ( 0.8-1.0  )
Albumin            28     g/L    ( 35-50    )
" + }, + { + "title" : "DiagnosticReport \"1101\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1101", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1101/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:16Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z968356  Z986691  Z968819
  Date:  04/04/12 05/04/12 05/04/12
  Time:     22:01    10:00    21:40                    Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            109L      90L     100L                   g/L       115-150
WCC           7.3      8.8     12.8H                   x10^9/L   4.0-11.0
PLT           184      170      206                    x10^9/L   140-400
RCC          3.45L    2.82L    3.23L                   x10^12/L  3.80-5.10
PCV          0.32L    0.26L    0.30L                   L/L       0.35-0.45
MCV          92.5     92.1     92.4                    fL        80.0-96.0
MCH          31.5     31.9     31.0                    pg        27.0-33.0
MCHC          340      346      335                    g/L       320-360
RDW          15.8H    16.5H    16.3H                   %         11.0-15.0
White Cell Differential
Neut         6.7      8.0     11.4H                    x10^9/L   2.0-8.0
Lymph        0.5L     0.7L     0.5L                    x10^9/L   1.2-4.0
Mono         0.1      0.0L     0.9                     x10^9/L   0.1-1.0
Eos          0.0      0.0      0.0                     x10^9/L   0.0-0.5
Baso         0.0      0.1      0.1                     x10^9/L   0.0-0.1

12Z968691 05/04/12 10:00
Comment: Intra-op
" + }, + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T22:01:00Z", + "subject" : { + "reference" : "Patient/121" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968819-16258608" + }, + "diagnosticDateTime" : "2012-04-05T21:40:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z968356  Z986691  Z968819
  Date:  04/04/12 05/04/12 05/04/12
  Time:     22:01    10:00    21:40                    Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            109L      90L     100L                   g/L       115-150
WCC           7.3      8.8     12.8H                   x10^9/L   4.0-11.0
PLT           184      170      206                    x10^9/L   140-400
RCC          3.45L    2.82L    3.23L                   x10^12/L  3.80-5.10
PCV          0.32L    0.26L    0.30L                   L/L       0.35-0.45
MCV          92.5     92.1     92.4                    fL        80.0-96.0
MCH          31.5     31.9     31.0                    pg        27.0-33.0
MCHC          340      346      335                    g/L       320-360
RDW          15.8H    16.5H    16.3H                   %         11.0-15.0
White Cell Differential
Neut         6.7      8.0     11.4H                    x10^9/L   2.0-8.0
Lymph        0.5L     0.7L     0.5L                    x10^9/L   1.2-4.0
Mono         0.1      0.0L     0.9                     x10^9/L   0.1-1.0
Eos          0.0      0.0      0.0                     x10^9/L   0.0-0.5
Baso         0.0      0.1      0.1                     x10^9/L   0.0-0.1

12Z968691 05/04/12 10:00
Comment: Intra-op
" + }, + { + "title" : "DiagnosticReport \"1102\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1102", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1102/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:16Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z968694  Z986770  Z968745  Z968803  Z986809
      Date:  05/04/12 05/04/12 05/04/12 05/04/12 05/04/12
      Time:     11:25    14:57    17:00    19:00    21:30 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.1                                            0.8-1.3
APTT               55H      44H       *       67H      61H secs  23-36
Fibrinogen        4.3                                      g/L   2.0-5.0

12Z968803 05/04/12 19:00
Comment: Further testing with a heparin resistant reagent confirmed
         the presence of heparin. Please indicate anticoagulant
         therapy on request form.

12Z968745 05/04/12 17:00
Comment: * Insufficient specimen to perform APTT. Ward informed.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + "name" : { + "text" : "Routine Coagulation" + }, + "status" : "final", + "issued" : "2012-04-05T22:23:00Z", + "subject" : { + "reference" : "Patient/147" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968809-16258607" + }, + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z968694  Z986770  Z968745  Z968803  Z986809
      Date:  05/04/12 05/04/12 05/04/12 05/04/12 05/04/12
      Time:     11:25    14:57    17:00    19:00    21:30 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.1                                            0.8-1.3
APTT               55H      44H       *       67H      61H secs  23-36
Fibrinogen        4.3                                      g/L   2.0-5.0

12Z968803 05/04/12 19:00
Comment: Further testing with a heparin resistant reagent confirmed
         the presence of heparin. Please indicate anticoagulant
         therapy on request form.

12Z968745 05/04/12 17:00
Comment: * Insufficient specimen to perform APTT. Ward informed.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + { + "title" : "DiagnosticReport \"1103\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1103", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1103/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:16Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Request No:  Z561163  Z516164  Z561865  Z561566  Z516367
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    16:22    17:26    20:00    20:52    21:52  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.28L    7.17L    7.31L    7.37     7.37          7.35-7.45
pCO2              51H      50H      41       35       32L mmHg    35-45
HCO3(Std)                           20L      21L      20L mmol/L  22.0-30.0
Base Excess     -2.3     -9.8L    -4.8L    -4.6L    -6.0L mmol/L  -3.0/3.0
pO2              141H     233H     245H     134H     160H mmHg    75-100
O2 Sat            98       98       99       99       99  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        3.9      3.7      4.2      4.3      4.2  mmol/L  3.5-5.5
Sodium           141      144      141      142      141  mmol/L  135-145
Chloride                           115H     114H     115H mmol/L  95-110
iCa++                             1.07L    1.06L    1.07L mmol/L  1.12-1.30
Glucose                           10.8H    10.7H    11.0H mmol/L  3.6-7.7
Lactate                            1.0      1.2      1.1  mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb       104L      92L      94L      95L      98L g/L     130-170
Reduced Hb                         0.8      1.4      1.0  %       0-5
CarbOxy Hb                         0.3L     0.5      0.6  %       0.5-1.5
Meth    Hb                         1.6H     1.7H     1.6H %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/148" + }, + "clinicalNotes" : "Automatic Request Registration" + } + ], + "name" : { + "text" : "Blood Gas" + }, + "status" : "final", + "issued" : "2012-04-05T21:56:00Z", + "subject" : { + "reference" : "Patient/148" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z561367-16258606" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:52:00" + }, + "summary" : "\r\n
\r\n
Request No:  Z561163  Z516164  Z561865  Z561566  Z516367
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    16:22    17:26    20:00    20:52    21:52  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.28L    7.17L    7.31L    7.37     7.37          7.35-7.45
pCO2              51H      50H      41       35       32L mmHg    35-45
HCO3(Std)                           20L      21L      20L mmol/L  22.0-30.0
Base Excess     -2.3     -9.8L    -4.8L    -4.6L    -6.0L mmol/L  -3.0/3.0
pO2              141H     233H     245H     134H     160H mmHg    75-100
O2 Sat            98       98       99       99       99  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        3.9      3.7      4.2      4.3      4.2  mmol/L  3.5-5.5
Sodium           141      144      141      142      141  mmol/L  135-145
Chloride                           115H     114H     115H mmol/L  95-110
iCa++                             1.07L    1.06L    1.07L mmol/L  1.12-1.30
Glucose                           10.8H    10.7H    11.0H mmol/L  3.6-7.7
Lactate                            1.0      1.2      1.1  mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb       104L      92L      94L      95L      98L g/L     130-170
Reduced Hb                         0.8      1.4      1.0  %       0-5
CarbOxy Hb                         0.3L     0.5      0.6  %       0.5-1.5
Meth    Hb                         1.6H     1.7H     1.6H %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + { + "title" : "DiagnosticReport \"1104\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1104", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1104/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:16Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Request No:  Z561267
      Date: 05/04/12                                              Arterial
      Time:    21:49                                      Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0                                      Deg. C
pH              7.37                                              7.35-7.45
pCO2              53H                                     mmHg    35-45
Base Excess      5.0H                                     mmol/L  -3.0/3.0
pO2               19L                                     mmHg    75-100
O2 Sat            25L                                     %       95-100

ELECTROLYTES (Whole Blood)
Potassium        4.6                                      mmol/L  3.5-5.5
Sodium           142                                      mmol/L  135-145

BLOOD CO-OXIMETRY
Total   Hb       149                                      g/L     130-170

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/145" + }, + "clinicalNotes" : "Automatic Request Registration" + } + ], + "name" : { + "text" : "Blood Gas" + }, + "status" : "final", + "issued" : "2012-04-05T21:51:00Z", + "subject" : { + "reference" : "Patient/145" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z516267-16258605" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:49:00" + }, + "summary" : "\r\n
\r\n
Request No:  Z561267
      Date: 05/04/12                                              Arterial
      Time:    21:49                                      Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0                                      Deg. C
pH              7.37                                              7.35-7.45
pCO2              53H                                     mmHg    35-45
Base Excess      5.0H                                     mmol/L  -3.0/3.0
pO2               19L                                     mmHg    75-100
O2 Sat            25L                                     %       95-100

ELECTROLYTES (Whole Blood)
Potassium        4.6                                      mmol/L  3.5-5.5
Sodium           142                                      mmol/L  135-145

BLOOD CO-OXIMETRY
Total   Hb       149                                      g/L     130-170

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + { + "title" : "DiagnosticReport \"1105\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1105", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1105/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:16Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            142     mmol/L ( 135-145  )
Potassium         3.9     mmol/L ( 3.5-5.5  )
Chloride          105     mmol/L ( 95-110   )
HCO3               27     mmol/L ( 22-30    )
Creatinine         50     umol/L ( 49-90    )
 (Creatinine)    0.050    mmol/L ( 0.05-0.09)
Urea              4.4     mmol/L ( 2.5-8.3  )
 eGFR             >90            ( SEE-BELOW)
Albumin            40     g/L    ( 35-50    )
AP                 91     IU/L   ( 30-120   )
GGT                28     IU/L   ( 10-65    )
ALT                34     IU/L   ( <34      )
AST                22     IU/L   ( <31      )
Bili Total          7     umol/L ( <19      )
Protein Total      80     g/L    ( 65-85    )
Troponin I       <0.02    ug/L   (See Below )
C-React Prot        5     mg/L   ( <5       )
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/124" + }, + "clinicalNotes" : "Chest Pain" + } + ], + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T22:58:00Z", + "subject" : { + "reference" : "Patient/124" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986898-16258604" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:40:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            142     mmol/L ( 135-145  )
Potassium         3.9     mmol/L ( 3.5-5.5  )
Chloride          105     mmol/L ( 95-110   )
HCO3               27     mmol/L ( 22-30    )
Creatinine         50     umol/L ( 49-90    )
 (Creatinine)    0.050    mmol/L ( 0.05-0.09)
Urea              4.4     mmol/L ( 2.5-8.3  )
 eGFR             >90            ( SEE-BELOW)
Albumin            40     g/L    ( 35-50    )
AP                 91     IU/L   ( 30-120   )
GGT                28     IU/L   ( 10-65    )
ALT                34     IU/L   ( <34      )
AST                22     IU/L   ( <31      )
Bili Total          7     umol/L ( <19      )
Protein Total      80     g/L    ( 65-85    )
Troponin I       <0.02    ug/L   (See Below )
C-React Prot        5     mg/L   ( <5       )
" + }, + { + "title" : "DiagnosticReport \"1106\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1106", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1106/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:17Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z968898
  Date:  05/04/12
  Time:     21:40                                      Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            120                                      g/L       115-150
WCC           6.9                                      x10^9/L   4.0-11.0
PLT           250                                      x10^9/L   140-400
RCC          4.16                                      x10^12/L  3.80-5.10
PCV          0.34L                                     L/L       0.35-0.45
MCV          81.1                                      fL        80.0-96.0
MCH          28.9                                      pg        27.0-33.0
MCHC          356                                      g/L       320-360
RDW          13.4                                      %         11.0-15.0
White Cell Differential
Neut         3.8                                       x10^9/L   2.0-8.0
Lymph        2.6                                       x10^9/L   1.2-4.0
Mono         0.4                                       x10^9/L   0.1-1.0
Eos          0.1                                       x10^9/L   0.0-0.5
Baso         0.0                                       x10^9/L   0.0-0.1
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/124" + }, + "clinicalNotes" : "Chest Pain" + } + ], + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T22:01:00Z", + "subject" : { + "reference" : "Patient/124" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968898-16258603" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:40:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z968898
  Date:  05/04/12
  Time:     21:40                                      Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            120                                      g/L       115-150
WCC           6.9                                      x10^9/L   4.0-11.0
PLT           250                                      x10^9/L   140-400
RCC          4.16                                      x10^12/L  3.80-5.10
PCV          0.34L                                     L/L       0.35-0.45
MCV          81.1                                      fL        80.0-96.0
MCH          28.9                                      pg        27.0-33.0
MCHC          356                                      g/L       320-360
RDW          13.4                                      %         11.0-15.0
White Cell Differential
Neut         3.8                                       x10^9/L   2.0-8.0
Lymph        2.6                                       x10^9/L   1.2-4.0
Mono         0.4                                       x10^9/L   0.1-1.0
Eos          0.1                                       x10^9/L   0.0-0.5
Baso         0.0                                       x10^9/L   0.0-0.1
" + }, + { + "title" : "DiagnosticReport \"1107\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1107", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1107/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:17Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
CK                344     IU/L   ( <175     )
CKMB Mass         34.0    ug/L   ( <4       )
LIPIDS
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/149" + }, + "clinicalNotes" : "Trial See Slip" + } + ], + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-06T03:49:00Z", + "subject" : { + "reference" : "Patient/149" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968888-16258602" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:44:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
CK                344     IU/L   ( <175     )
CKMB Mass         34.0    ug/L   ( <4       )
LIPIDS
" + }, + { + "title" : "DiagnosticReport \"1108\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1108", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1108/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:17Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z066808
SPECIMEN
Specimen Type:         Faeces
Description:           Unformed


CLOSTRIDIUM DIFFICILE
C.difficile Culture:                       C.difficile NOT isolated


COMMENT
* Faeces examination for patients in hospital for >3 days will
ONLY have C.difficile tests performed.

 If the clinical condition requires more extensive culture, other
pathogen detection, or if the clinical condition warrants further
investigation, please contact the Microbiology Registrar.
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/150" + }, + "clinicalNotes" : "See Slip" + } + ], + "name" : { + "text" : "Faeces" + }, + "status" : "final", + "issued" : "2012-04-07T14:25:00Z", + "subject" : { + "reference" : "Patient/150" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968878-16258601" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:00:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z066808
SPECIMEN
Specimen Type:         Faeces
Description:           Unformed


CLOSTRIDIUM DIFFICILE
C.difficile Culture:                       C.difficile NOT isolated


COMMENT
* Faeces examination for patients in hospital for >3 days will
ONLY have C.difficile tests performed.

 If the clinical condition requires more extensive culture, other
pathogen detection, or if the clinical condition warrants further
investigation, please contact the Microbiology Registrar.
" + }, + { + "title" : "DiagnosticReport \"1109\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1109", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1109/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:18Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z996588
SPECIMEN
Specimen Type : Tracheal Aspirate


MICROSCOPY

GRAM STAIN
Pus Cells                                 +
No organisms seen





CULTURE

Standard culture:   ++ Mixed upper respiratory tract flora




" + }, + "name" : { + "text" : "Respiratory M/C/S" + }, + "status" : "final", + "issued" : "2012-04-07T12:54:00Z", + "subject" : { + "reference" : "Patient/118" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968868-16258600" + }, + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z996588
SPECIMEN
Specimen Type : Tracheal Aspirate


MICROSCOPY

GRAM STAIN
Pus Cells                                 +
No organisms seen





CULTURE

Standard culture:   ++ Mixed upper respiratory tract flora




" + }, + { + "title" : "DiagnosticReport \"111\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/111", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/111/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:02Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z466872  Z560485  Z869274  Z676769  Z968972
  Date:  08/01/09 17/02/09 19/02/09 24/01/12 05/04/12
  Time:     08:10    15:30    06:00    15:50    23:10  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            159      143      144      149      132  g/L       130-170
WCC           7.3      6.5      7.1      7.6      6.9  x10^9/L   4.0-11.0
PLT           231      241      220      225      227  x10^9/L   140-400
RCC          4.96     4.54     4.54     4.68     4.17L x10^12/L  4.50-5.70
PCV          0.46     0.42     0.42     0.43     0.38L L/L       0.40-0.50
MCV          92.9     92.7     92.3     92.4     91.7  fL        80.0-96.0
MCH          32.1     31.5     31.6     31.8     31.8  pg        27.0-33.0
MCHC          345      340      343      344      346  g/L       320-360
RDW          12.8     13.3     13.7     13.3     12.4  %         11.0-15.0
White Cell Differential
Neut         4.6      3.3      4.5      4.0      3.7   x10^9/L   2.0-8.0
Lymph        1.9      2.4      1.8      2.7      2.1   x10^9/L   1.2-4.0
Mono         0.5      0.5      0.6      0.6      0.8   x10^9/L   0.1-1.0
Eos          0.2      0.3      0.2      0.2      0.3   x10^9/L   0.0-0.5
Baso         0.1      0.0      0.0      0.0      0.0   x10^9/L   0.0-0.1
" + }, + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T23:59:00Z", + "subject" : { + "reference" : "Patient/115" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968972-16258701" + }, + "diagnosticDateTime" : "2012-04-05T23:10:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z466872  Z560485  Z869274  Z676769  Z968972
  Date:  08/01/09 17/02/09 19/02/09 24/01/12 05/04/12
  Time:     08:10    15:30    06:00    15:50    23:10  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            159      143      144      149      132  g/L       130-170
WCC           7.3      6.5      7.1      7.6      6.9  x10^9/L   4.0-11.0
PLT           231      241      220      225      227  x10^9/L   140-400
RCC          4.96     4.54     4.54     4.68     4.17L x10^12/L  4.50-5.70
PCV          0.46     0.42     0.42     0.43     0.38L L/L       0.40-0.50
MCV          92.9     92.7     92.3     92.4     91.7  fL        80.0-96.0
MCH          32.1     31.5     31.6     31.8     31.8  pg        27.0-33.0
MCHC          345      340      343      344      346  g/L       320-360
RDW          12.8     13.3     13.7     13.3     12.4  %         11.0-15.0
White Cell Differential
Neut         4.6      3.3      4.5      4.0      3.7   x10^9/L   2.0-8.0
Lymph        1.9      2.4      1.8      2.7      2.1   x10^9/L   1.2-4.0
Mono         0.5      0.5      0.6      0.6      0.8   x10^9/L   0.1-1.0
Eos          0.2      0.3      0.2      0.2      0.3   x10^9/L   0.0-0.5
Baso         0.1      0.0      0.0      0.0      0.0   x10^9/L   0.0-0.1
" + }, + { + "title" : "DiagnosticReport \"1110\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1110", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1110/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:18Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z736754
SPECIMEN
Specimen Type : Urine Type Not Stated


CHEMISTRY
pH              5.5
Protein         +
Specific Grav.  >=1.030
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      NEGATIVE


MICROSCOPY
Leucocytes                    4          x10^6/L ( <2x10^6/L )
Red Blood Cells               Nil        x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     Nil








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + "name" : { + "text" : "Urine M/C/S" + }, + "status" : "final", + "issued" : "2012-04-07T08:55:00Z", + "subject" : { + "reference" : "Patient/118" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968868-16258599" + }, + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z736754
SPECIMEN
Specimen Type : Urine Type Not Stated


CHEMISTRY
pH              5.5
Protein         +
Specific Grav.  >=1.030
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      NEGATIVE


MICROSCOPY
Leucocytes                    4          x10^6/L ( <2x10^6/L )
Red Blood Cells               Nil        x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     Nil








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + { + "title" : "DiagnosticReport \"1111\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1111", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1111/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:18Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No : Z366352
SPECIMENS
Specimen Type : Blood Cultures
Description   : Venous/peripheral

Aerobic bottle               4   days                 Negative
Anaerobic bottle             4   days                 Negative
" + }, + "name" : { + "text" : "Blood Cultures" + }, + "status" : "partial", + "issued" : "2012-04-09T22:49:00Z", + "subject" : { + "reference" : "Patient/118" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968868-16258598" + }, + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
Lab No : Z366352
SPECIMENS
Specimen Type : Blood Cultures
Description   : Venous/peripheral

Aerobic bottle               4   days                 Negative
Anaerobic bottle             4   days                 Negative
" + }, + { + "title" : "DiagnosticReport \"1112\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1112", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1112/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:18Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Bili Total          *     umol/L ( <19      )
Protein Total       *     g/L    ( 65-85    )

Comment: The requested tests were not completed as no
         sample was  received.
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/151" + }, + "clinicalNotes" : "S\\H/A Anneurism" + } + ], + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T23:43:00Z", + "subject" : { + "reference" : "Patient/151" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968858-16258597" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Bili Total          *     umol/L ( <19      )
Protein Total       *     g/L    ( 65-85    )

Comment: The requested tests were not completed as no
         sample was  received.
" + }, + { + "title" : "DiagnosticReport \"1113\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1113", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1113/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:18Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Miscellaneous Fluid
Fluid Type:   CSF
Cerebrospinal Fluid
Csf Protein      0.22 g/L    ( 0.15-0.45
Csf Glucose       3.6 mmol/L ( 2.5-5.0)

Xanthochromia Test

Date of Symptom Onset:   04/04/2012
Time of Symptom Onset:   12:00
Date of Lumbar Puncture: 05/04/2012
Time of Lumbar Puncture: 21:30
Hand Delivered?:         no
Time Difference:         33:30
Xan Result               As below
Xanthochromia Comment:   Oxyhaemoglobin present but no significant
                         bilirubin.   The concentration of oxyhaemoglobin
                         may mask a small  but significant increase in
                         bilirubin.  Subarachnoid  haemorrhage not
                         excluded.
                         NOTE: This xanthochromia result cannot be fully
                         relied  upon as specimens were not collected /
                         forwarded  according to protocol.

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/151" + }, + "clinicalNotes" : "S\\H/A Anneurism" + } + ], + "name" : { + "text" : "Csf & Fluid Chemistr" + }, + "status" : "final", + "issued" : "2012-04-05T23:01:00Z", + "subject" : { + "reference" : "Patient/151" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986858-16258596" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
Miscellaneous Fluid
Fluid Type:   CSF
Cerebrospinal Fluid
Csf Protein      0.22 g/L    ( 0.15-0.45
Csf Glucose       3.6 mmol/L ( 2.5-5.0)

Xanthochromia Test

Date of Symptom Onset:   04/04/2012
Time of Symptom Onset:   12:00
Date of Lumbar Puncture: 05/04/2012
Time of Lumbar Puncture: 21:30
Hand Delivered?:         no
Time Difference:         33:30
Xan Result               As below
Xanthochromia Comment:   Oxyhaemoglobin present but no significant
                         bilirubin.   The concentration of oxyhaemoglobin
                         may mask a small  but significant increase in
                         bilirubin.  Subarachnoid  haemorrhage not
                         excluded.
                         NOTE: This xanthochromia result cannot be fully
                         relied  upon as specimens were not collected /
                         forwarded  according to protocol.

" + }, + { + "title" : "DiagnosticReport \"1114\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1114", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1114/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:18Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z262849
SPECIMEN
Specimen Type : CSF Lumbar Puncture

MACROSCOPIC APPEARANCE                 MACROSCOPIC APPEARANCE

CSF Total volume: 7    ml(s)

TUBE 3                                 TUBE 1
Clear and colourless                   Faintly bloodstained

CELL COUNT:          x10^6/L           CELL COUNT:          x10^6/L
Erythrocytes         3                 Erythrocytes         114
Polymorphs           0                 Polymorphs           0
Lymphocytes          0                 Lymphocytes          0

CULTURE
No Growth After 2 Days.

COMMENT
This CSF specimen will be cultured on routine media for 48 hours.
Please contact the Microbiology registrar if either extended
culture or special media are required.
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/151" + }, + "clinicalNotes" : "S\\H/A Anneurism" + } + ], + "name" : { + "text" : "CSF M/C/S" + }, + "status" : "final", + "issued" : "2012-04-08T10:12:00Z", + "subject" : { + "reference" : "Patient/151" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968858-16258595" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z262849
SPECIMEN
Specimen Type : CSF Lumbar Puncture

MACROSCOPIC APPEARANCE                 MACROSCOPIC APPEARANCE

CSF Total volume: 7    ml(s)

TUBE 3                                 TUBE 1
Clear and colourless                   Faintly bloodstained

CELL COUNT:          x10^6/L           CELL COUNT:          x10^6/L
Erythrocytes         3                 Erythrocytes         114
Polymorphs           0                 Polymorphs           0
Lymphocytes          0                 Lymphocytes          0

CULTURE
No Growth After 2 Days.

COMMENT
This CSF specimen will be cultured on routine media for 48 hours.
Please contact the Microbiology registrar if either extended
culture or special media are required.
" + }, + { + "title" : "DiagnosticReport \"1115\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1115", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1115/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z764221  Z566945  Z765513  Z765914  Z986838
      Date:  28/07/11 09/03/12 10/03/12 11/03/12 05/04/12
      Time:     16:20    04:30    06:10    01:20    21:25 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               2.6H     2.7H     3.4H     3.5H     1.9H       0.8-1.3
APTT                                                   31  secs  23-36
Fibrinogen                                            3.2  g/L   2.0-5.0

12Z765513 10/03/12 06:10
Comment: Please indicate anticoagulant therapy on request form.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/152" + }, + "clinicalNotes" : "Chest Pain" + } + ], + "name" : { + "text" : "Routine Coagulation" + }, + "status" : "final", + "issued" : "2012-04-05T22:28:00Z", + "subject" : { + "reference" : "Patient/152" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968838-16258594" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:25:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z764221  Z566945  Z765513  Z765914  Z986838
      Date:  28/07/11 09/03/12 10/03/12 11/03/12 05/04/12
      Time:     16:20    04:30    06:10    01:20    21:25 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               2.6H     2.7H     3.4H     3.5H     1.9H       0.8-1.3
APTT                                                   31  secs  23-36
Fibrinogen                                            3.2  g/L   2.0-5.0

12Z765513 10/03/12 06:10
Comment: Please indicate anticoagulant therapy on request form.

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + { + "title" : "DiagnosticReport \"1116\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1116", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1116/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            143     mmol/L ( 135-145  )
Potassium         4.3     mmol/L ( 3.5-5.5  )
Chloride          106     mmol/L ( 95-110   )
HCO3               26     mmol/L ( 22-30    )
Creatinine         89     umol/L ( 49-90    )
 (Creatinine)    0.089    mmol/L ( 0.05-0.09)
Urea              8.5     mmol/L ( 2.5-8.3  )
 eGFR             53             ( SEE-BELOW)
Troponin I        0.02    ug/L   (See Below )
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/152" + }, + "clinicalNotes" : "Chest Pain" + } + ], + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T22:29:00Z", + "subject" : { + "reference" : "Patient/152" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968838-16258593" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:25:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            143     mmol/L ( 135-145  )
Potassium         4.3     mmol/L ( 3.5-5.5  )
Chloride          106     mmol/L ( 95-110   )
HCO3               26     mmol/L ( 22-30    )
Creatinine         89     umol/L ( 49-90    )
 (Creatinine)    0.089    mmol/L ( 0.05-0.09)
Urea              8.5     mmol/L ( 2.5-8.3  )
 eGFR             53             ( SEE-BELOW)
Troponin I        0.02    ug/L   (See Below )
" + }, + { + "title" : "DiagnosticReport \"1117\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1117", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1117/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z765513  Z765823  Z756914  Z165519  Z968838
  Date:  10/03/12 10/03/12 11/03/12 12/03/12 05/04/12
  Time:     06:10    19:00    01:20    06:27    21:25  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            115        *      116      109L     112L g/L       115-150
WCC           5.2               7.2      7.3      9.6  x10^9/L   4.0-11.0
PLT           144        *      164      154      172  x10^9/L   140-400
RCC          3.90              3.98     3.71L    3.83  x10^12/L  3.80-5.10
PCV          0.34L             0.35     0.32L    0.34L L/L       0.35-0.45
MCV          87.3              87.8     87.1     87.5  fL        80.0-96.0
MCH          29.5              29.2     29.3     29.3  pg        27.0-33.0
MCHC          338               332      337      335  g/L       320-360
RDW          15.6H             15.5H    15.5H    15.6H %         11.0-15.0
White Cell Differential
Neut         3.2               4.7      5.3      6.7   x10^9/L   2.0-8.0
Lymph        1.4               1.7      1.4      2.0   x10^9/L   1.2-4.0
Mono         0.4               0.6      0.5      0.7   x10^9/L   0.1-1.0
Eos          0.2               0.2      0.1      0.2   x10^9/L   0.0-0.5
Baso         0.0               0.1      0.0      0.1   x10^9/L   0.0-0.1

12Z756823 10/03/12 19:00
Comment: * Please note: no specimen received.
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/152" + }, + "clinicalNotes" : "Chest Pain" + } + ], + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T22:01:00Z", + "subject" : { + "reference" : "Patient/152" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986838-16258592" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:25:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z765513  Z765823  Z756914  Z165519  Z968838
  Date:  10/03/12 10/03/12 11/03/12 12/03/12 05/04/12
  Time:     06:10    19:00    01:20    06:27    21:25  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            115        *      116      109L     112L g/L       115-150
WCC           5.2               7.2      7.3      9.6  x10^9/L   4.0-11.0
PLT           144        *      164      154      172  x10^9/L   140-400
RCC          3.90              3.98     3.71L    3.83  x10^12/L  3.80-5.10
PCV          0.34L             0.35     0.32L    0.34L L/L       0.35-0.45
MCV          87.3              87.8     87.1     87.5  fL        80.0-96.0
MCH          29.5              29.2     29.3     29.3  pg        27.0-33.0
MCHC          338               332      337      335  g/L       320-360
RDW          15.6H             15.5H    15.5H    15.6H %         11.0-15.0
White Cell Differential
Neut         3.2               4.7      5.3      6.7   x10^9/L   2.0-8.0
Lymph        1.4               1.7      1.4      2.0   x10^9/L   1.2-4.0
Mono         0.4               0.6      0.5      0.7   x10^9/L   0.1-1.0
Eos          0.2               0.2      0.1      0.2   x10^9/L   0.0-0.5
Baso         0.0               0.1      0.0      0.1   x10^9/L   0.0-0.1

12Z756823 10/03/12 19:00
Comment: * Please note: no specimen received.
" + }, + { + "title" : "DiagnosticReport \"1118\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1118", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1118/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Specimen Type           Serum

Test performed at Friends Laboratory



COMMENT: This serum sample has been stored for 3 months.  If clinically
         indicated please send convalescent sera 2-3  weeks after
         symptom onset for Mycoplasma, Influenza, Chlamydia and Q fever
         or 4-6 weeks after symptom onset for Legionella.  More rapid
         results are available for Legionella  pneumophila and
         Pneumococcus by urinary antigen  testing, or for Influenza by
         PCR of nose/throat swabs.


" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/153" + }, + "clinicalNotes" : "Chest Pain Worse On Exercise" + } + ], + "name" : { + "text" : "Micro Sendout" + }, + "status" : "final", + "issued" : "2012-04-06T12:52:00Z", + "subject" : { + "reference" : "Patient/153" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968848-16258591" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:30:00" + }, + "summary" : "\r\n
\r\n
Specimen Type           Serum

Test performed at Friends Laboratory



COMMENT: This serum sample has been stored for 3 months.  If clinically
         indicated please send convalescent sera 2-3  weeks after
         symptom onset for Mycoplasma, Influenza, Chlamydia and Q fever
         or 4-6 weeks after symptom onset for Legionella.  More rapid
         results are available for Legionella  pneumophila and
         Pneumococcus by urinary antigen  testing, or for Influenza by
         PCR of nose/throat swabs.


" + }, + { + "title" : "DiagnosticReport \"1119\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1119", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1119/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Request No:  Z516524  Z561594  Z561539  Z516763  Z561167
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    06:18    08:02    12:24    17:03    21:26  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.36     7.37     7.32L    7.33L    7.39          7.35-7.45
pCO2              37       42       47H      46H      37  mmHg    35-45
HCO3(Std)         21L      24       23       23       23  mmol/L  22.0-30.0
Base Excess     -3.7L    -0.7     -1.6     -1.5     -2.1  mmol/L  -3.0/3.0
pO2              105H     186H     115H     344H     239H mmHg    75-100
O2 Sat            97       99       97       99       99  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        3.5      4.3      5.4      5.4      4.2  mmol/L  3.5-5.5
Sodium           145      141      137      136      134L mmol/L  135-145
Chloride         118H     113H     109      105      105  mmol/L  95-110
iCa++           1.11L    1.20     1.20     1.19     1.18  mmol/L  1.12-1.30
Glucose          5.3      7.1     10.4H     9.3H    13.8H mmol/L  3.6-7.7
Lactate          0.8      1.4      1.0      1.3      1.7  mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb        74L      81L      86L      83L      71L g/L     115-150
Reduced Hb       2.7      1.1      2.5      0.9      1.2  %       0-5
CarbOxy Hb       0.8      0.8      0.7      0.6      0.6  %       0.5-1.5
Meth    Hb       2.4H     1.6H     2.0H     2.1H     1.9H %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/124" + }, + "clinicalNotes" : "Automatic Request Registration" + } + ], + "name" : { + "text" : "Blood Gas" + }, + "status" : "final", + "issued" : "2012-04-05T21:30:00Z", + "subject" : { + "reference" : "Patient/124" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z561167-16258590" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:26:00" + }, + "summary" : "\r\n
\r\n
Request No:  Z516524  Z561594  Z561539  Z516763  Z561167
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    06:18    08:02    12:24    17:03    21:26  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.36     7.37     7.32L    7.33L    7.39          7.35-7.45
pCO2              37       42       47H      46H      37  mmHg    35-45
HCO3(Std)         21L      24       23       23       23  mmol/L  22.0-30.0
Base Excess     -3.7L    -0.7     -1.6     -1.5     -2.1  mmol/L  -3.0/3.0
pO2              105H     186H     115H     344H     239H mmHg    75-100
O2 Sat            97       99       97       99       99  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        3.5      4.3      5.4      5.4      4.2  mmol/L  3.5-5.5
Sodium           145      141      137      136      134L mmol/L  135-145
Chloride         118H     113H     109      105      105  mmol/L  95-110
iCa++           1.11L    1.20     1.20     1.19     1.18  mmol/L  1.12-1.30
Glucose          5.3      7.1     10.4H     9.3H    13.8H mmol/L  3.6-7.7
Lactate          0.8      1.4      1.0      1.3      1.7  mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb        74L      81L      86L      83L      71L g/L     115-150
Reduced Hb       2.7      1.1      2.5      0.9      1.2  %       0-5
CarbOxy Hb       0.8      0.8      0.7      0.6      0.6  %       0.5-1.5
Meth    Hb       2.4H     1.6H     2.0H     2.1H     1.9H %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + { + "title" : "DiagnosticReport \"112\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/112", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/112/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:02Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            141     mmol/L ( 135-145  )
Potassium         3.6     mmol/L ( 3.5-5.5  )
Chloride          109     mmol/L ( 95-110   )
HCO3               23     mmol/L ( 22-30    )
Creatinine         66     umol/L ( 49-90    )
 (Creatinine)    0.066    mmol/L ( 0.05-0.09)
Urea              4.0     mmol/L ( 2.5-8.3  )
 eGFR             76             ( SEE-BELOW)
C-React Prot      152     mg/L   ( <5       )
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/116" + }, + "clinicalNotes" : "Infected Tendon Sheath" + } + ], + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T23:30:00Z", + "subject" : { + "reference" : "Patient/116" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968922-16258699" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T23:30:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            141     mmol/L ( 135-145  )
Potassium         3.6     mmol/L ( 3.5-5.5  )
Chloride          109     mmol/L ( 95-110   )
HCO3               23     mmol/L ( 22-30    )
Creatinine         66     umol/L ( 49-90    )
 (Creatinine)    0.066    mmol/L ( 0.05-0.09)
Urea              4.0     mmol/L ( 2.5-8.3  )
 eGFR             76             ( SEE-BELOW)
C-React Prot      152     mg/L   ( <5       )
" + }, + { + "title" : "DiagnosticReport \"1120\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1120", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1120/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Request No:  Z561261  Z516463  Z561864  Z561765  Z516067
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    14:13    16:46    18:10    19:54    21:22  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.26L    7.36     7.40     7.36     7.24L         7.35-7.45
pCO2              26L      23L      21L      27L      44  mmHg    35-45
HCO3(Std)         14L      16L      17L      17L      18L mmol/L  22.0-30.0
Base Excess    -14.4L   -11.8L   -10.8L    -9.4L    -7.9L mmol/L  -3.0/3.0
pO2              142H     138H     136H     306H     345H mmHg    75-100
O2 Sat            99       99      100      100      100  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        5.0      5.7H     6.0H     5.6H     6.2H mmol/L  3.5-5.5
Sodium           142      140      141      138      136  mmol/L  135-145
Chloride         109      107      106      107      105  mmol/L  95-110
iCa++           0.98L    0.99L    0.98L    0.97L    0.98L mmol/L  1.12-1.30
Glucose          5.2      5.3      4.4      7.4      6.4  mmol/L  3.6-7.7
Lactate         15.0H    12.3H    11.7H     9.3H     7.5H mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb        99L     106L     109L     108L     108L g/L     130-170
Reduced Hb       1.2      0.6      0.5     -0.2L    -0.1L %       0-5
CarbOxy Hb       1.4      1.7H     1.8H     1.4      1.3  %       0.5-1.5
Meth    Hb       1.2      1.0      1.2      1.1      0.7  %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/122" + }, + "clinicalNotes" : "Automatic Request Registration" + } + ], + "name" : { + "text" : "Blood Gas" + }, + "status" : "final", + "issued" : "2012-04-05T21:26:00Z", + "subject" : { + "reference" : "Patient/122" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z561067-16258589" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:22:00" + }, + "summary" : "\r\n
\r\n
Request No:  Z561261  Z516463  Z561864  Z561765  Z516067
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    14:13    16:46    18:10    19:54    21:22  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.26L    7.36     7.40     7.36     7.24L         7.35-7.45
pCO2              26L      23L      21L      27L      44  mmHg    35-45
HCO3(Std)         14L      16L      17L      17L      18L mmol/L  22.0-30.0
Base Excess    -14.4L   -11.8L   -10.8L    -9.4L    -7.9L mmol/L  -3.0/3.0
pO2              142H     138H     136H     306H     345H mmHg    75-100
O2 Sat            99       99      100      100      100  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        5.0      5.7H     6.0H     5.6H     6.2H mmol/L  3.5-5.5
Sodium           142      140      141      138      136  mmol/L  135-145
Chloride         109      107      106      107      105  mmol/L  95-110
iCa++           0.98L    0.99L    0.98L    0.97L    0.98L mmol/L  1.12-1.30
Glucose          5.2      5.3      4.4      7.4      6.4  mmol/L  3.6-7.7
Lactate         15.0H    12.3H    11.7H     9.3H     7.5H mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb        99L     106L     109L     108L     108L g/L     130-170
Reduced Hb       1.2      0.6      0.5     -0.2L    -0.1L %       0-5
CarbOxy Hb       1.4      1.7H     1.8H     1.4      1.3  %       0.5-1.5
Meth    Hb       1.2      1.0      1.2      1.1      0.7  %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + { + "title" : "DiagnosticReport \"1121\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1121", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1121/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            141     mmol/L ( 135-145  )
Potassium         4.0     mmol/L ( 3.5-5.5  )
Chloride          111     mmol/L ( 95-110   )
HCO3               21     mmol/L ( 22-30    )
Creatinine         75     umol/L ( 64-104   )
 (Creatinine)    0.075    mmol/L ( 0.05-0.11)
Urea              7.0     mmol/L ( 2.5-8.3  )
 eGFR             89             ( SEE-BELOW)
" + }, + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T22:23:00Z", + "subject" : { + "reference" : "Patient/154" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986808-16258588" + }, + "diagnosticDateTime" : "2012-04-05T21:10:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            141     mmol/L ( 135-145  )
Potassium         4.0     mmol/L ( 3.5-5.5  )
Chloride          111     mmol/L ( 95-110   )
HCO3               21     mmol/L ( 22-30    )
Creatinine         75     umol/L ( 64-104   )
 (Creatinine)    0.075    mmol/L ( 0.05-0.11)
Urea              7.0     mmol/L ( 2.5-8.3  )
 eGFR             89             ( SEE-BELOW)
" + }, + { + "title" : "DiagnosticReport \"1122\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1122", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1122/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:19Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z069574  Z616341  Z968385  Z968583  Z986808
  Date:  28/10/11 02/11/11 04/04/12 05/04/12 05/04/12
  Time:     11:10    13:00    21:25    06:15    21:10  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            134      133      156      155      121L g/L       130-170
WCC           7.0     11.6H    12.6H    12.8H     8.7  x10^9/L   4.0-11.0
PLT           298      315      339      341      283  x10^9/L   140-400
RCC          4.35L    4.31L    5.10     5.03     3.90L x10^12/L  4.50-5.70
PCV          0.40     0.40     0.47     0.46     0.36L L/L       0.40-0.50
MCV          91.5     92.1     91.8     92.3     91.6  fL        80.0-96.0
MCH          30.7     30.8     30.5     30.9     31.0  pg        27.0-33.0
MCHC          336      335      333      335      339  g/L       320-360
RDW          15.2H    15.2H    14.8     14.5     14.4  %         11.0-15.0
White Cell Differential
Neut         4.7      8.8H    10.8H     9.1H     6.2   x10^9/L   2.0-8.0
Lymph        1.7      1.8      1.1L     0.5L     1.7   x10^9/L   1.2-4.0
Mono         0.4      1.0      0.6      0.6      0.8   x10^9/L   0.1-1.0
Eos          0.0      0.0      0.1      0.0      0.1   x10^9/L   0.0-0.5
Baso         0.1      0.0      0.1      0.0      0.0   x10^9/L   0.0-0.1
Bands                                   2.6H           x10^9/L   0.0-0.5

11Z661341 02/11/11 13:00
Comment: Note: mild neutrophilia. Instrument differential and
         parameters reported.

12Z968583 05/04/12 06:15
Film Comment : Mild neutrophilia with toxic changes and a moderate left
               shift. Manual differential. Red cells are mainly
               normocytic normochromic with occasional elongated cells.
               Platelets appear normal.
Conclusion: ? Infection / inflammation. repeat FBE may be of value.

12Z986808 05/04/12 21:10
Comment: Please note fall in haemoglobin and platelet count since
         the previous examination. ?Rehydration. Suggest repeat.
" + }, + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T21:35:00Z", + "subject" : { + "reference" : "Patient/154" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968808-16258587" + }, + "diagnosticDateTime" : "2012-04-05T21:10:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z069574  Z616341  Z968385  Z968583  Z986808
  Date:  28/10/11 02/11/11 04/04/12 05/04/12 05/04/12
  Time:     11:10    13:00    21:25    06:15    21:10  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            134      133      156      155      121L g/L       130-170
WCC           7.0     11.6H    12.6H    12.8H     8.7  x10^9/L   4.0-11.0
PLT           298      315      339      341      283  x10^9/L   140-400
RCC          4.35L    4.31L    5.10     5.03     3.90L x10^12/L  4.50-5.70
PCV          0.40     0.40     0.47     0.46     0.36L L/L       0.40-0.50
MCV          91.5     92.1     91.8     92.3     91.6  fL        80.0-96.0
MCH          30.7     30.8     30.5     30.9     31.0  pg        27.0-33.0
MCHC          336      335      333      335      339  g/L       320-360
RDW          15.2H    15.2H    14.8     14.5     14.4  %         11.0-15.0
White Cell Differential
Neut         4.7      8.8H    10.8H     9.1H     6.2   x10^9/L   2.0-8.0
Lymph        1.7      1.8      1.1L     0.5L     1.7   x10^9/L   1.2-4.0
Mono         0.4      1.0      0.6      0.6      0.8   x10^9/L   0.1-1.0
Eos          0.0      0.0      0.1      0.0      0.1   x10^9/L   0.0-0.5
Baso         0.1      0.0      0.1      0.0      0.0   x10^9/L   0.0-0.1
Bands                                   2.6H           x10^9/L   0.0-0.5

11Z661341 02/11/11 13:00
Comment: Note: mild neutrophilia. Instrument differential and
         parameters reported.

12Z968583 05/04/12 06:15
Film Comment : Mild neutrophilia with toxic changes and a moderate left
               shift. Manual differential. Red cells are mainly
               normocytic normochromic with occasional elongated cells.
               Platelets appear normal.
Conclusion: ? Infection / inflammation. repeat FBE may be of value.

12Z986808 05/04/12 21:10
Comment: Please note fall in haemoglobin and platelet count since
         the previous examination. ?Rehydration. Suggest repeat.
" + }, + { + "title" : "DiagnosticReport \"1123\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1123", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1123/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:20Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            133     mmol/L ( 135-145  )
Potassium         3.7     mmol/L ( 3.5-5.5  )
Chloride           99     mmol/L ( 95-110   )
HCO3               25     mmol/L ( 22-30    )
Creatinine        175     umol/L ( 49-90    )
 (Creatinine)    0.175    mmol/L ( 0.05-0.09)
Urea              9.1     mmol/L ( 2.5-8.3  )
 eGFR             28             ( SEE-BELOW)
" + }, + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T22:23:00Z", + "subject" : { + "reference" : "Patient/155" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986818-16258586" + }, + "diagnosticDateTime" : "2012-04-05T20:10:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            133     mmol/L ( 135-145  )
Potassium         3.7     mmol/L ( 3.5-5.5  )
Chloride           99     mmol/L ( 95-110   )
HCO3               25     mmol/L ( 22-30    )
Creatinine        175     umol/L ( 49-90    )
 (Creatinine)    0.175    mmol/L ( 0.05-0.09)
Urea              9.1     mmol/L ( 2.5-8.3  )
 eGFR             28             ( SEE-BELOW)
" + }, + { + "title" : "DiagnosticReport \"1124\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1124", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1124/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:20Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            133     mmol/L ( 135-145  )
Potassium         3.7     mmol/L ( 3.5-5.5  )
Chloride           99     mmol/L ( 95-110   )
HCO3               25     mmol/L ( 22-30    )
Creatinine        175     umol/L ( 49-90    )
 (Creatinine)    0.175    mmol/L ( 0.05-0.09)
Urea              9.1     mmol/L ( 2.5-8.3  )
 eGFR             28             ( SEE-BELOW)
" + }, + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T22:23:00Z", + "subject" : { + "reference" : "Patient/155" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968818-16258586" + }, + "diagnosticDateTime" : "2012-04-05T20:10:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            133     mmol/L ( 135-145  )
Potassium         3.7     mmol/L ( 3.5-5.5  )
Chloride           99     mmol/L ( 95-110   )
HCO3               25     mmol/L ( 22-30    )
Creatinine        175     umol/L ( 49-90    )
 (Creatinine)    0.175    mmol/L ( 0.05-0.09)
Urea              9.1     mmol/L ( 2.5-8.3  )
 eGFR             28             ( SEE-BELOW)
" + }, + { + "title" : "DiagnosticReport \"1125\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1125", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1125/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:20Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z376489  Z868657  Z868982  Z986405  Z968818
  Date:  03/04/12 03/04/12 04/04/12 05/04/12 05/04/12
  Time:     09:38    16:45    03:45    02:35    20:10  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb             95L      84L      97L      93L      81L g/L       115-150
WCC           7.8     11.4H     8.1      9.1      6.8  x10^9/L   4.0-11.0
PLT           127L     142      110L     123L     125L x10^9/L   140-400
RCC          3.22L    2.90L    3.29L    3.16L    2.75L x10^12/L  3.80-5.10
PCV          0.27L    0.24L    0.28L    0.27L    0.23L L/L       0.35-0.45
MCV          85.1     84.0     85.1     86.3     85.1  fL        80.0-96.0
MCH          29.5     29.1     29.4     29.4     29.3  pg        27.0-33.0
MCHC          346      346      345      340      344  g/L       320-360
RDW          14.2     14.3     14.9     14.3     15.0  %         11.0-15.0
White Cell Differential
Neut         6.4      8.1H     6.5      7.6      5.2   x10^9/L   2.0-8.0
Lymph        0.9L     1.6      1.0L     0.8L     1.1L  x10^9/L   1.2-4.0
Mono         0.4      1.0      0.5      0.6      0.5   x10^9/L   0.1-1.0
Eos          0.0      0.1      0.0      0.1      0.1   x10^9/L   0.0-0.5
Baso         0.0      0.0      0.0      0.0      0.0   x10^9/L   0.0-0.1
Bands                 0.2                              x10^9/L   0.0-0.5
Meta                  0.3H                             x10^9/L   0.0
NRBC                     1H                            /100WBCs  0
NRBC Abs              0.1H                             x10^9/L   0

12Z868657 03/04/12 16:45
Film Comment : Manual differential. Mild neutrophilia with slight left
               shift. A rare nucleated red blood cell seen and increased
               rouleaux. Mild thrombocytopenia.
Conclusion: Please note fall in haemoglobin since the previous
            examination. ? any infection / inflammation.
            No clinical information provided.
" + }, + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T21:36:00Z", + "subject" : { + "reference" : "Patient/155" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968818-16258585" + }, + "diagnosticDateTime" : "2012-04-05T20:10:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z376489  Z868657  Z868982  Z986405  Z968818
  Date:  03/04/12 03/04/12 04/04/12 05/04/12 05/04/12
  Time:     09:38    16:45    03:45    02:35    20:10  Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb             95L      84L      97L      93L      81L g/L       115-150
WCC           7.8     11.4H     8.1      9.1      6.8  x10^9/L   4.0-11.0
PLT           127L     142      110L     123L     125L x10^9/L   140-400
RCC          3.22L    2.90L    3.29L    3.16L    2.75L x10^12/L  3.80-5.10
PCV          0.27L    0.24L    0.28L    0.27L    0.23L L/L       0.35-0.45
MCV          85.1     84.0     85.1     86.3     85.1  fL        80.0-96.0
MCH          29.5     29.1     29.4     29.4     29.3  pg        27.0-33.0
MCHC          346      346      345      340      344  g/L       320-360
RDW          14.2     14.3     14.9     14.3     15.0  %         11.0-15.0
White Cell Differential
Neut         6.4      8.1H     6.5      7.6      5.2   x10^9/L   2.0-8.0
Lymph        0.9L     1.6      1.0L     0.8L     1.1L  x10^9/L   1.2-4.0
Mono         0.4      1.0      0.5      0.6      0.5   x10^9/L   0.1-1.0
Eos          0.0      0.1      0.0      0.1      0.1   x10^9/L   0.0-0.5
Baso         0.0      0.0      0.0      0.0      0.0   x10^9/L   0.0-0.1
Bands                 0.2                              x10^9/L   0.0-0.5
Meta                  0.3H                             x10^9/L   0.0
NRBC                     1H                            /100WBCs  0
NRBC Abs              0.1H                             x10^9/L   0

12Z868657 03/04/12 16:45
Film Comment : Manual differential. Mild neutrophilia with slight left
               shift. A rare nucleated red blood cell seen and increased
               rouleaux. Mild thrombocytopenia.
Conclusion: Please note fall in haemoglobin since the previous
            examination. ? any infection / inflammation.
            No clinical information provided.
" + }, + { + "title" : "DiagnosticReport \"1126\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1126", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1126/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:20Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Anti-Factor Xa Assay (Plasma)
Heparin Level by Anti-Xa          0.07   U/mL

Anti-Factor Xa Comment:
   Reference range for Anti-Xa level depends upon route, time, dose and
   reason for anticoagulation.
   Therapeutic anticoagulation with LMWH (such as Enoxaparin) generally does
   not require routine monitoring. However, anti-Xa levels are recommended
   for patients on LMWH requiring dose adjustment in settings of (1) renal
   impairment, (2) obesity and (3) pregnancy.  To assist interpretation of
   therapeutic ranges, anti-Xa levels should be collected four hours after
   the third dose.  For less common indications such a patients at high risk
   of bleeding, and interpretation of results, please contact the on-call
   laboratory Haematology registrar or Haematologist via ACME switchboard.

Tests of Hypercoagulability (Plasma)
Antithrombin (Functional)         88     %      (80-120)
" + }, + "name" : { + "text" : "Special Coagulation" + }, + "status" : "final", + "issued" : "2012-04-05T22:07:00Z", + "subject" : { + "reference" : "Patient/155" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986818-16258584" + }, + "diagnosticDateTime" : "2012-04-05T20:10:00" + }, + "summary" : "\r\n
\r\n
Anti-Factor Xa Assay (Plasma)
Heparin Level by Anti-Xa          0.07   U/mL

Anti-Factor Xa Comment:
   Reference range for Anti-Xa level depends upon route, time, dose and
   reason for anticoagulation.
   Therapeutic anticoagulation with LMWH (such as Enoxaparin) generally does
   not require routine monitoring. However, anti-Xa levels are recommended
   for patients on LMWH requiring dose adjustment in settings of (1) renal
   impairment, (2) obesity and (3) pregnancy.  To assist interpretation of
   therapeutic ranges, anti-Xa levels should be collected four hours after
   the third dose.  For less common indications such a patients at high risk
   of bleeding, and interpretation of results, please contact the on-call
   laboratory Haematology registrar or Haematologist via ACME switchboard.

Tests of Hypercoagulability (Plasma)
Antithrombin (Functional)         88     %      (80-120)
" + }, + { + "title" : "DiagnosticReport \"1127\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1127", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1127/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:20Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z367489  Z886657  Z868982  Z968405  Z986818
      Date:  03/04/12 03/04/12 04/04/12 05/04/12 05/04/12
      Time:     09:38    16:45    03:45    02:35    20:10 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.2      1.2      1.3      1.3      1.3        0.8-1.3
APTT               74H      70H      59H      64H      66H secs  23-36
Fibrinogen        6.5H     6.7H     6.4H     7.3H     6.2H g/L   2.0-5.0

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + "name" : { + "text" : "Routine Coagulation" + }, + "status" : "final", + "issued" : "2012-04-05T21:48:00Z", + "subject" : { + "reference" : "Patient/155" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968818-16258583" + }, + "diagnosticDateTime" : "2012-04-05T20:10:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z367489  Z886657  Z868982  Z968405  Z986818
      Date:  03/04/12 03/04/12 04/04/12 05/04/12 05/04/12
      Time:     09:38    16:45    03:45    02:35    20:10 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.2      1.2      1.3      1.3      1.3        0.8-1.3
APTT               74H      70H      59H      64H      66H secs  23-36
Fibrinogen        6.5H     6.7H     6.4H     7.3H     6.2H g/L   2.0-5.0

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + { + "title" : "DiagnosticReport \"1128\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1128", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1128/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Specimen Type:  Urine

Legionella Antigen by Immunochromatography               : NOT Detected

S.pneumoniae Antigen by Immunochromatography             : NOT Detected


GENERAL COMMENT:

LEGIONELLA URINARY ANTIGEN:
Presumptive negative for Legionella pneumophila  serogroup 1
antigen in urine. Infection due to  Legionella cannot be ruled out
since other serogroups  and species may cause disease.
Antigen may not be  present in urine in early infection.
Please send another urine if clinically indicated.

STREPTOCOCCUS PNEUMONIAE ANTIGEN:
Presumptive  negative for pneumococcal pneumonia.

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/153" + }, + "clinicalNotes" : "Chest Pain Worse On Exercise" + } + ], + "name" : { + "text" : "Internal Serology" + }, + "status" : "final", + "issued" : "2012-04-10T12:51:00Z", + "subject" : { + "reference" : "Patient/153" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z986828-16258582" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:17:00" + }, + "summary" : "\r\n
\r\n
Specimen Type:  Urine

Legionella Antigen by Immunochromatography               : NOT Detected

S.pneumoniae Antigen by Immunochromatography             : NOT Detected


GENERAL COMMENT:

LEGIONELLA URINARY ANTIGEN:
Presumptive negative for Legionella pneumophila  serogroup 1
antigen in urine. Infection due to  Legionella cannot be ruled out
since other serogroups  and species may cause disease.
Antigen may not be  present in urine in early infection.
Please send another urine if clinically indicated.

STREPTOCOCCUS PNEUMONIAE ANTIGEN:
Presumptive  negative for pneumococcal pneumonia.

" + }, + { + "title" : "DiagnosticReport \"1129\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1129", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1129/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
SERUM/PLASMA
Sodium            137     mmol/L ( 135-145  )
Potassium         4.6     mmol/L ( 3.5-5.5  )
Chloride          106     mmol/L ( 95-110   )
HCO3               23     mmol/L ( 22-30    )
Creatinine        161     umol/L ( 64-104   )
 (Creatinine)    0.161    mmol/L ( 0.05-0.11)
Urea             16.4     mmol/L ( 2.5-8.3  )
 eGFR             37             ( SEE-BELOW)
" + }, + "name" : { + "text" : "General Biochemistry" + }, + "status" : "final", + "issued" : "2012-04-05T22:22:00Z", + "subject" : { + "reference" : "Patient/156" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968897-16258581" + }, + "diagnosticDateTime" : "2012-04-05T21:05:00" + }, + "summary" : "\r\n
\r\n
SERUM/PLASMA
Sodium            137     mmol/L ( 135-145  )
Potassium         4.6     mmol/L ( 3.5-5.5  )
Chloride          106     mmol/L ( 95-110   )
HCO3               23     mmol/L ( 22-30    )
Creatinine        161     umol/L ( 64-104   )
 (Creatinine)    0.161    mmol/L ( 0.05-0.11)
Urea             16.4     mmol/L ( 2.5-8.3  )
 eGFR             37             ( SEE-BELOW)
" + }, + { + "title" : "DiagnosticReport \"113\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/113", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/113/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:02Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z986922
  Date:  05/04/12
  Time:     23:30                                      Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            123                                      g/L       115-150
WCC           9.7                                      x10^9/L   4.0-11.0
PLT           217                                      x10^9/L   140-400
RCC          3.93                                      x10^12/L  3.80-5.10
PCV          0.36                                      L/L       0.35-0.45
MCV          91.1                                      fL        80.0-96.0
MCH          31.3                                      pg        27.0-33.0
MCHC          344                                      g/L       320-360
RDW          13.2                                      %         11.0-15.0
White Cell Differential
Neut         7.2                                       x10^9/L   2.0-8.0
Lymph        1.9                                       x10^9/L   1.2-4.0
Mono         0.6                                       x10^9/L   0.1-1.0
Eos          0.0                                       x10^9/L   0.0-0.5
Baso         0.0                                       x10^9/L   0.0-0.1
" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/116" + }, + "clinicalNotes" : "Infected Tendon Sheath" + } + ], + "name" : { + "text" : "FBE & Routine Haem" + }, + "status" : "final", + "issued" : "2012-04-05T23:30:00Z", + "subject" : { + "reference" : "Patient/116" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968922-16258698" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T23:30:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Req No:   Z986922
  Date:  05/04/12
  Time:     23:30                                      Units    Ref Range
         ________ ________ ________ ________ ________  ________ _________
Full Blood Count (Whole Blood)
Hb            123                                      g/L       115-150
WCC           9.7                                      x10^9/L   4.0-11.0
PLT           217                                      x10^9/L   140-400
RCC          3.93                                      x10^12/L  3.80-5.10
PCV          0.36                                      L/L       0.35-0.45
MCV          91.1                                      fL        80.0-96.0
MCH          31.3                                      pg        27.0-33.0
MCHC          344                                      g/L       320-360
RDW          13.2                                      %         11.0-15.0
White Cell Differential
Neut         7.2                                       x10^9/L   2.0-8.0
Lymph        1.9                                       x10^9/L   1.2-4.0
Mono         0.6                                       x10^9/L   0.1-1.0
Eos          0.0                                       x10^9/L   0.0-0.5
Baso         0.0                                       x10^9/L   0.0-0.1
" + }, + { + "title" : "DiagnosticReport \"1130\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1130", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1130/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z996578
SPECIMEN
Specimen Type : Sputum


MICROSCOPY

GRAM STAIN
Macroscopic Description                   Mucoid
Pus:Epithelial Cell Ratio                 <25:10
Pus Cells                                 Occasional
Squamous Epithelial Cells                 ++
Gram positive cocci                       +
Gram positive bacilli                     +
Gram negative bacilli                     +
yeasts                                    Occasional

 Standard bacterial culture is not indicated as the ratio
 of pus to epithelial cells, or the bacteria seen in the
 Gram stain indicate salivary contamination.
" + }, + "name" : { + "text" : "Respiratory M/C/S" + }, + "status" : "final", + "issued" : "2012-04-06T14:19:00Z", + "subject" : { + "reference" : "Patient/157" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968887-16258579" + }, + "diagnosticDateTime" : "2012-04-05T21:10:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z996578
SPECIMEN
Specimen Type : Sputum


MICROSCOPY

GRAM STAIN
Macroscopic Description                   Mucoid
Pus:Epithelial Cell Ratio                 <25:10
Pus Cells                                 Occasional
Squamous Epithelial Cells                 ++
Gram positive cocci                       +
Gram positive bacilli                     +
Gram negative bacilli                     +
yeasts                                    Occasional

 Standard bacterial culture is not indicated as the ratio
 of pus to epithelial cells, or the bacteria seen in the
 Gram stain indicate salivary contamination.
" + }, + { + "title" : "DiagnosticReport \"1131\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1131", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1131/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Request No:  Z516566  Z561599  Z561862  Z516564  Z561866
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    09:24    12:42    15:58    17:46    21:08  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.32L    7.37     7.37     7.36     7.38          7.35-7.45
pCO2              35       34L      34L      35       33L mmHg    35-45
HCO3(Std)         18L      20L      20L      20L      20L mmol/L  22.0-30.0
Base Excess     -7.3L    -5.1L    -5.0L    -5.3L    -4.8L mmol/L  -3.0/3.0
pO2              129H     112H     117H      95       81  mmHg    75-100
O2 Sat            99       98       99       98       96  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        4.4      3.9      4.6      4.3      4.2  mmol/L  3.5-5.5
Sodium           135      134L     135      137      135  mmol/L  135-145
Chloride         110      110      110      110      109  mmol/L  95-110
iCa++           1.06L    1.05L    1.08L    1.09L    1.08L mmol/L  1.12-1.30
Glucose          8.7H     9.0H     7.6      6.7     10.3H mmol/L  3.6-7.7
Lactate          2.5H     2.1H     2.8H     2.6H     2.0H mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb        80L      79L      80L      81L      81L g/L     115-150
Reduced Hb       1.3      1.7      1.1      2.4      3.7  %       0-5
CarbOxy Hb       0.7      0.6      0.7      0.6      0.6  %       0.5-1.5
Meth    Hb       1.1      1.6H     1.1      0.8      1.1  %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/158" + }, + "clinicalNotes" : "Automatic Request Registration" + } + ], + "name" : { + "text" : "Blood Gas" + }, + "status" : "final", + "issued" : "2012-04-05T21:12:00Z", + "subject" : { + "reference" : "Patient/158" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z561866-16258578" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:08:00" + }, + "summary" : "\r\n
\r\n
Request No:  Z516566  Z561599  Z561862  Z516564  Z561866
      Date: 05/04/12 05/04/12 05/04/12 05/04/12 05/04/12          Arterial
      Time:    09:24    12:42    15:58    17:46    21:08  Units   Ref Range
            -------- -------- -------- -------- --------  ------  ---------
BLOOD GASES
Temperature     37.0     37.0     37.0     37.0     37.0  Deg. C
pH              7.32L    7.37     7.37     7.36     7.38          7.35-7.45
pCO2              35       34L      34L      35       33L mmHg    35-45
HCO3(Std)         18L      20L      20L      20L      20L mmol/L  22.0-30.0
Base Excess     -7.3L    -5.1L    -5.0L    -5.3L    -4.8L mmol/L  -3.0/3.0
pO2              129H     112H     117H      95       81  mmHg    75-100
O2 Sat            99       98       99       98       96  %       95-100

ELECTROLYTES (Whole Blood)
Potassium        4.4      3.9      4.6      4.3      4.2  mmol/L  3.5-5.5
Sodium           135      134L     135      137      135  mmol/L  135-145
Chloride         110      110      110      110      109  mmol/L  95-110
iCa++           1.06L    1.05L    1.08L    1.09L    1.08L mmol/L  1.12-1.30
Glucose          8.7H     9.0H     7.6      6.7     10.3H mmol/L  3.6-7.7
Lactate          2.5H     2.1H     2.8H     2.6H     2.0H mmol/L  0.2-1.8

BLOOD CO-OXIMETRY
Total   Hb        80L      79L      80L      81L      81L g/L     115-150
Reduced Hb       1.3      1.7      1.1      2.4      3.7  %       0-5
CarbOxy Hb       0.7      0.6      0.7      0.6      0.6  %       0.5-1.5
Meth    Hb       1.1      1.6H     1.1      0.8      1.1  %       0-1.5

Note: Reference Ranges shown are for arterial blood only.
      Venous blood ranges for pH pCO2 pO2 are:
      pH     7.31 - 7.41
      pCO2    40  -  50  mmHg
      pO2     30  -  50  mmHg

" + }, + { + "title" : "DiagnosticReport \"1132\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1132", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1132/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
THYROID FUNCTION
TSH                       2.52       mIU/L   ( 0.1-4.0  )



" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/135" + }, + "clinicalNotes" : "Chest Pain Fi" + } + ], + "name" : { + "text" : "Endo / Nutrition" + }, + "status" : "final", + "issued" : "2012-04-05T21:58:00Z", + "subject" : { + "reference" : "Patient/135" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968704-16258577" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T16:52:00" + }, + "summary" : "\r\n
\r\n
THYROID FUNCTION
TSH                       2.52       mIU/L   ( 0.1-4.0  )



" + }, + { + "title" : "DiagnosticReport \"1133\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1133", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1133/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z736744
SPECIMEN
Specimen Type : Urine In/Out Catheter


CHEMISTRY
pH              5.5
Protein         TRACE
Specific Grav.  1.018
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      +


MICROSCOPY
Leucocytes                    5          x10^6/L ( <2x10^6/L )
Red Blood Cells               Nil        x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     Nil








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + "name" : { + "text" : "Urine M/C/S" + }, + "status" : "final", + "issued" : "2012-04-07T08:55:00Z", + "subject" : { + "reference" : "Patient/159" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968867-16258576" + }, + "diagnosticDateTime" : "2012-04-05T20:20:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z736744
SPECIMEN
Specimen Type : Urine In/Out Catheter


CHEMISTRY
pH              5.5
Protein         TRACE
Specific Grav.  1.018
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      +


MICROSCOPY
Leucocytes                    5          x10^6/L ( <2x10^6/L )
Red Blood Cells               Nil        x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     Nil








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + { + "title" : "DiagnosticReport \"1134\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1134", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1134/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z736734
SPECIMEN
Specimen Type : Urine Midstream


CHEMISTRY
pH              5.5
Protein         +
Specific Grav.  1.025
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      TRACE


MICROSCOPY
Leucocytes                    28         x10^6/L ( <2x10^6/L )
Red Blood Cells               6          x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     ++








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + "contained" : [ + { + "resourceType" : "DiagnosticOrder", + "id" : "req", + "subject" : { + "reference" : "Patient/139" + }, + "clinicalNotes" : "Collapsed Low BP" + } + ], + "name" : { + "text" : "Urine M/C/S" + }, + "status" : "final", + "issued" : "2012-04-07T08:55:00Z", + "subject" : { + "reference" : "Patient/139" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968877-16258575" + }, + "requestDetail" : [ + { + "reference" : "#req" + } + ], + "diagnosticDateTime" : "2012-04-05T21:00:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z736734
SPECIMEN
Specimen Type : Urine Midstream


CHEMISTRY
pH              5.5
Protein         +
Specific Grav.  1.025
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      TRACE


MICROSCOPY
Leucocytes                    28         x10^6/L ( <2x10^6/L )
Red Blood Cells               6          x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     ++








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + { + "title" : "DiagnosticReport \"1135\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1135", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1135/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:21Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
Lab No      : Z736724
SPECIMEN
Specimen Type : Urine Type Not Stated


CHEMISTRY
pH              5.0
Protein         NEGATIVE
Specific Grav.  1.014
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      NEGATIVE


MICROSCOPY
Leucocytes                    1          x10^6/L ( <2x10^6/L )
Red Blood Cells               3          x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     Nil








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + "name" : { + "text" : "Urine M/C/S" + }, + "status" : "final", + "issued" : "2012-04-07T08:55:00Z", + "subject" : { + "reference" : "Patient/160" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968857-16258574" + }, + "diagnosticDateTime" : "2012-04-05T20:45:00" + }, + "summary" : "\r\n
\r\n
Lab No      : Z736724
SPECIMEN
Specimen Type : Urine Type Not Stated


CHEMISTRY
pH              5.0
Protein         NEGATIVE
Specific Grav.  1.014
Blood           NEGATIVE
Glucose         NEGATIVE
Leucocytes      NEGATIVE


MICROSCOPY
Leucocytes                    1          x10^6/L ( <2x10^6/L )
Red Blood Cells               3          x10^6/L ( <13x10^6/L )
Squamous Epithelial Cells     Nil








STANDARD BACTERIAL CULTURE
No Growth -Detection limit 10^7 CFU/L

" + }, + { + "title" : "DiagnosticReport \"1136\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1136", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/DiagnosticReport/1136/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-03-10T11:56:22Z", + "author" : [ + { + "name" : "service" + } + ], + "published" : "2014-03-22T15:37:12Z", + "content" : { + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z176645  Z868279  Z868875  Z986450  Z968847
      Date:  01/04/12 03/04/12 04/04/12 05/04/12 05/04/12
      Time:     22:00    02:00    00:30    00:10    20:59 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.0      1.0      1.0      1.1      1.1        0.8-1.3
APTT               28       26       28       27       25  secs  23-36
Fibrinogen        6.8H     7.8H     7.9H     8.9H     8.0H g/L   2.0-5.0

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + }, + "name" : { + "text" : "Routine Coagulation" + }, + "status" : "final", + "issued" : "2012-04-05T21:27:00Z", + "subject" : { + "reference" : "Patient/120" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "12Z968847-16258573" + }, + "diagnosticDateTime" : "2012-04-05T20:59:00" + }, + "summary" : "\r\n
\r\n
CUMULATIVE REPORT
Request No:   Z176645  Z868279  Z868875  Z986450  Z968847
      Date:  01/04/12 03/04/12 04/04/12 05/04/12 05/04/12
      Time:     22:00    02:00    00:30    00:10    20:59 Units   Ref.
             -------- -------- -------- -------- -------- ------ -----
Coagulation (Plasma)
INR               1.0      1.0      1.0      1.1      1.1        0.8-1.3
APTT               28       26       28       27       25  secs  23-36
Fibrinogen        6.8H     7.8H     7.9H     8.9H     8.0H g/L   2.0-5.0

APTT Therapeutic range for IV Heparin therapy = 60-85 seconds
From 9.12.2010 APTT normal range 23 - 36 seconds.
" + } + ] +} diff --git a/hapi-fhir-structures-dstu/src/test/resources/atom-document-large.xml b/hapi-fhir-structures-dstu/src/test/resources/atom-document-large.xml new file mode 100644 index 00000000000..8b96d72cdd0 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/atom-document-large.xml @@ -0,0 +1,843 @@ + + Search on resources in collection 'Patient' + urn:uuid:8b8428a5-ba56-4fc7-b176-36d13346c1ad + 2014-03-06T22:09:58.9121174Z + + Spark MatchBox Search Engine + + 676 + + + + + + + Patient resource with id 3216379 + http://spark.furore.com/fhir/Patient/3216379 + 2014-03-06T18:07:52.2209263Z + 2014-03-06T18:07:52.2209263Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + + + + + + Patient resource with id 3212416 + http://spark.furore.com/fhir/Patient/3212416 + 2014-01-18T19:48:05.7634661Z + 2014-01-18T19:48:05.747866Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + + + + Patient resource with id 3212417 + http://spark.furore.com/fhir/Patient/3212417 + 2014-01-18T19:48:40.9572917Z + 2014-01-18T19:48:40.9416916Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + + + + Patient resource with id 3212429 + http://spark.furore.com/fhir/Patient/3212429 + 2014-01-18T19:52:14.7410621Z + 2014-01-18T19:52:14.6786617Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + + + + http://spark.furore.com/fhir/Patient/3212430 + 2014-01-18T19:52:16.6442743Z + + + + + + + + + + + + + + + + + + + + + http://spark.furore.com/fhir/Patient/3212433 + 2014-01-18T19:52:17.5490801Z + + + + + + + + + + + + + + + + + + + + + Patient resource with id 3212435 + http://spark.furore.com/fhir/Patient/3212435 + 2014-01-18T19:52:18.7658879Z + 2014-01-18T19:52:18.7658879Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + + + + Patient Resource + http://spark.furore.com/fhir/Patient/3212446 + 2014-01-18T19:55:50.8346474Z + + + + + + + +
Parkerson, Parkie
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ +
+
+ +
Parkerson, Parkie
+
+
+ + Patient Resource + http://spark.furore.com/fhir/Patient/3212492 + 2014-01-18T22:09:21.1526936Z + + + + + + + +
Parkerson, Parkie
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ +
+
+ +
Parkerson, Parkie
+
+
+ + patient record + http://spark.furore.com/fhir/Patient/3212516 + 2014-01-18T22:30:06.8604936Z + + + + + + + +
Person DOE, John, M, dob: 27/05/1956
+
+ + + + + + + + + + + +
+
+ +
Person DOE, John, M, dob: 27/05/1956
+
+
+ + Patient Resource + http://spark.furore.com/fhir/Patient/3212576 + 2014-01-18T22:47:32.8716936Z + + + + + + + +
Parkerson, Parkie
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ +
+
+ +
Parkerson, Parkie
+
+
+ + Patient Resource + http://spark.furore.com/fhir/Composition/3212638 + 2014-01-18T23:16:43.9026936Z + + + + + + + +
Parkerson, Parkie
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ +
+
+ +
Parkerson, Parkie
+
+
+ + Patient Resource + http://spark.furore.com/fhir/Patient/3212673 + 2014-01-18T23:43:42.9527548Z + + + + + + + +
Parkerson, Parkie
+
+ + + + + + + + + + + + + + + + +
+ + + + + +
+ +
+
+ +
Parkerson, Parkie
+
+
+ + Patient resource with id 3212861 + http://spark.furore.com/fhir/Patient/3212861 + 2014-01-19T15:06:57.8105834Z + 2014-01-19T15:06:57.8105834Z + + (unauthenticated) + + + + + + + +
+ BizTalk Test +
+
+ + + + + + + + + + + + +
+ + +
+ + + + +
+
+ +
+ BizTalk Test +
+
+
+ + Patient resource with id 3213112 + http://spark.furore.com/fhir/Patient/3213112 + 2014-01-19T16:17:08.4218784Z + 2014-01-19T16:17:08.4218784Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + +
+ + + + +
+
+
+
+ + Patient resource with id 3213341 + http://spark.furore.com/fhir/Patient/3213341 + 2014-01-19T16:29:22.0804724Z + 2014-01-19T16:29:22.0648726Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+
+
+
+ + Patient resource with id 3213417 + http://spark.furore.com/fhir/Patient/3213417 + 2014-01-19T16:33:17.1694584Z + 2014-01-19T16:33:17.1538586Z + + (unauthenticated) + + + + + + + + + + + + + +
+ + + + + +
+ +
+
+
+ + Patient + http://spark.furore.com/fhir/Patient/3213445 + 2014-01-19T16:39:43.3113078Z + + + + + + + Isabella Isa Jones + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+
+ + + + +
+
+ + Isabella Isa Jones + +
+ + Patient resource with id 3213586 + http://spark.furore.com/fhir/Patient/3213586 + 2014-01-19T16:41:54.9432766Z + 2014-01-19T16:41:54.9432766Z + + (unauthenticated) + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+
+
+
+ + Patient + http://spark.furore.com/fhir/Patient/3213739 + 2014-01-19T16:51:12.1772766Z + + + + + + + Isabella Isa Jones + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+
+ + + + +
+
+ + Isabella Isa Jones + +
+
\ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/bundle.json b/hapi-fhir-structures-dstu/src/test/resources/bundle.json new file mode 100644 index 00000000000..8a833758f17 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/bundle.json @@ -0,0 +1,370 @@ +{ + "resourceType" : "Bundle", + "title" : "History for Patient", + "id" : "urn:uuid:a0d5d4cd-387c-46c4-89f9-4b3060237f", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/", + "rel" : "fhir-base" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740", + "rel" : "self" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740&search-offset=0&_count=5", + "rel" : "first" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740&search-offset=5&_count=5", + "rel" : "next" + }, + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740&search-offset=1775&_count=5", + "rel" : "last" + } + ], + "updated" : "2014-06-20T20:22:09Z", + "totalResults" : "1779", + "entry" : [ + { + "title" : "Patient \"84239339\" Version \"2\"", + "id" : "http://fhir.healthintersections.com.au/open/Patient/84239339", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/84239339/_history/2", + "rel" : "self" + } + ], + "updated" : "2014-06-20T20:18:52Z", + "author" : [ + { + "name" : "199.71.174.200" + } + ], + "published" : "2014-06-20T20:22:09Z", + "content" : { + "resourceType" : "Patient", + "text" : { + "status" : "generated", + "div" : "
Nuclear, Neville_test SSN: 444111234
" + }, + "identifier" : [ + { + "label" : "SSN", + "system" : "http://hl7.org/fhir/sid/us-ssn", + "value" : "444111234" + } + ], + "name" : [ + { + "use" : "official", + "family" : [ + "Nuclear" + ], + "given" : [ + "Neville_test" + ] + } + ], + "telecom" : [ + { + "system" : "phone", + "value" : "555-555-5001", + "use" : "work" + } + ], + "gender" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v3/AdministrativeGender", + "code" : "M" + } + ] + }, + "address" : [ + { + "use" : "home", + "line" : [ + "6666 Home Street" + ] + } + ], + "managingOrganization" : { + "reference" : "Organization/hl7" + }, + "active" : true + }, + "summary" : "
Nuclear, Neville_test SSN: 444111234
" + }, + { + "title" : "Patient \"84239340\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/Patient/84239340", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/84239340/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-06-20T20:18:16Z", + "author" : [ + { + "name" : "199.71.174.200" + } + ], + "published" : "2014-06-20T20:22:09Z", + "content" : { + "resourceType" : "Patient", + "text" : { + "status" : "generated", + "div" : "
Nuclear, Neville_test SSN: 444111234
" + }, + "identifier" : [ + { + "label" : "SSN", + "system" : "http://hl7.org/fhir/sid/us-ssn", + "value" : "444111234" + } + ], + "name" : [ + { + "use" : "official", + "family" : [ + "Nuclear" + ], + "given" : [ + "Neville_test" + ] + } + ], + "telecom" : [ + { + "system" : "phone", + "value" : "555-555-5001", + "use" : "work" + } + ], + "gender" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v3/AdministrativeGender", + "code" : "M" + } + ] + }, + "address" : [ + { + "use" : "home", + "line" : [ + "6666 Home Street" + ] + } + ], + "managingOrganization" : { + "reference" : "Organization/hl7" + }, + "active" : true + }, + "summary" : "
Nuclear, Neville_test SSN: 444111234
" + }, + { + "title" : "Patient \"84239339\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/Patient/84239339", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/84239339/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-06-20T20:17:41Z", + "author" : [ + { + "name" : "199.71.174.200" + } + ], + "published" : "2014-06-20T20:22:09Z", + "content" : { + "resourceType" : "Patient", + "text" : { + "status" : "generated", + "div" : "
Nuclear, Neville_test SSN: 444111234
" + }, + "identifier" : [ + { + "label" : "SSN", + "system" : "http://hl7.org/fhir/sid/us-ssn", + "value" : "444111234" + } + ], + "name" : [ + { + "use" : "official", + "family" : [ + "Nuclear" + ], + "given" : [ + "Neville_test" + ] + } + ], + "telecom" : [ + { + "system" : "phone", + "value" : "555-555-5001", + "use" : "work" + } + ], + "gender" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v3/AdministrativeGender", + "code" : "M" + } + ] + }, + "address" : [ + { + "use" : "home", + "line" : [ + "6666 Home Street" + ] + } + ], + "managingOrganization" : { + "reference" : "Organization/hl7" + }, + "active" : true + }, + "summary" : "
Nuclear, Neville_test SSN: 444111234
" + }, + { + "deleted" : "2014-06-20T20:15:49Z", + "id" : "http://fhir.healthintersections.com.au/open/84239337", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/patient/84239337/_history/2", + "rel" : "self" + } + ], + "author" : [ + { + "name" : "199.71.174.200" + } + ] + }, + { + "title" : "Patient \"84239338\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/Patient/84239338", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/84239338/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-06-20T19:53:53Z", + "author" : [ + { + "name" : "199.212.7.70" + } + ], + "category" : [ + { + "scheme" : "http://hl7.org/fhir/tag", + "term" : "urn:happytag", + "label" : "This is a happy resource" + } + ], + "published" : "2014-06-20T20:22:09Z", + "content" : { + "resourceType" : "Patient", + "identifier" : [ + { + "system" : "foo:bar", + "value" : "12345" + } + ], + "name" : [ + { + "family" : [ + "Smith" + ], + "given" : [ + "John" + ] + } + ] + }, + "summary" : "
--No Summary for this resource--
" + }, + { + "title" : "Patient \"84239337\" Version \"1\"", + "id" : "http://fhir.healthintersections.com.au/open/Patient/84239337", + "link" : [ + { + "href" : "http://fhir.healthintersections.com.au/open/Patient/84239337/_history/1", + "rel" : "self" + } + ], + "updated" : "2014-06-20T14:31:09Z", + "author" : [ + { + "name" : "199.71.174.200" + } + ], + "published" : "2014-06-20T20:22:09Z", + "content" : { + "resourceType" : "Patient", + "text" : { + "status" : "generated", + "div" : "
Nuclear1, Neville1. SSN: 444111234
" + }, + "identifier" : [ + { + "label" : "SSN", + "system" : "http://hl7.org/fhir/sid/us-ssn", + "value" : "444111234" + } + ], + "name" : [ + { + "use" : "official", + "family" : [ + "Nuclear1" + ], + "given" : [ + "Neville1" + ] + } + ], + "telecom" : [ + { + "system" : "phone", + "value" : "555-555-5001", + "use" : "work" + } + ], + "gender" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v3/AdministrativeGender", + "code" : "M" + } + ] + }, + "address" : [ + { + "use" : "home", + "line" : [ + "6666 Home Street" + ] + } + ], + "managingOrganization" : { + "reference" : "Organization/hl7" + }, + "active" : true + }, + "summary" : "
Nuclear1, Neville1. SSN: 444111234
" + } + ] +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/careplan-big-example.xml b/hapi-fhir-structures-dstu/src/test/resources/careplan-big-example.xml new file mode 100644 index 00000000000..a9bc69263d0 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/careplan-big-example.xml @@ -0,0 +1,302 @@ + + + +
+

Patient family is not ready to commit to goal setting at this time. Goal setting will be addressed in the future

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + g1 + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+ + + + \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/contained-diagnosticreport.json b/hapi-fhir-structures-dstu/src/test/resources/contained-diagnosticreport.json new file mode 100644 index 00000000000..237d67b5f25 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/contained-diagnosticreport.json @@ -0,0 +1,778 @@ +{ + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n
\r\n

CBC Report for Wile. E. COYOTE (MRN: 23453) issued 3-Mar 2011 11:45

\r\n \r\n
Test                  Units       Value       Reference Range
Haemoglobin           g/L         176         135 - 180
Red Cell Count        x10*12/L    5.9         4.2 - 6.0
Haematocrit                       0.55+       0.38 - 0.52
Mean Cell Volume      fL          99+         80 - 98
Mean Cell Haemoglobin pg          36+         27 - 35
Platelet Count        x10*9/L     444         150 - 450
White Cell Count      x10*9/L     4.6         4.0 - 11.0
Neutrophils           %           20 
Neutrophils           x10*9/L     0.9---      2.0 - 7.5
Lymphocytes           %           20  
Lymphocytes           x10*9/L     0.9-        1.1 - 4.0
Monocytes             %           20 
Monocytes             x10*9/L     0.9         0.2 - 1.0
Eosinophils           %           20 
Eosinophils           x10*9/L     0.92++      0.04 - 0.40
Basophils             %           20 
Basophils             x10*9/L     0.92+++     <0.21
      
\r\n

Acme Laboratory, Inc signed: Dr Pete Pathologist

" + }, + "contained" : [ + { + "resourceType" : "Observation", + "id" : "r1", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "718-7", + "display" : "Hemoglobin [Mass/volume] in Blood" + } + ], + "text" : "Haemoglobin" + }, + "valueQuantity" : { + "value" : "176", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "135", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + }, + "high" : { + "value" : "180", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r2", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "789-8", + "display" : "Erythrocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Red Cell Count" + }, + "valueQuantity" : { + "value" : "5.9", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "4.2", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + }, + "high" : { + "value" : "6.0", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r3", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "4544-3", + "display" : "Hematocrit [Volume Fraction] of Blood by Automated count" + } + ], + "text" : "Haematocrit" + }, + "valueQuantity" : { + "value" : "55", + "units" : "%" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "38", + "units" : "%" + }, + "high" : { + "value" : "52", + "units" : "%" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r4", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "787-2", + "display" : "Erythrocyte mean corpuscular volume [Entitic volume] by Automated count" + } + ], + "text" : "Mean Cell Volume" + }, + "valueQuantity" : { + "value" : "99", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "80", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + }, + "high" : { + "value" : "98", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r5", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "785-6", + "display" : "Erythrocyte mean corpuscular hemoglobin [Entitic mass] by Automated count" + } + ], + "text" : "Mean Cell Haemoglobin" + }, + "valueQuantity" : { + "value" : "36", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "27", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + }, + "high" : { + "value" : "35", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r6", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "777-3", + "display" : "Platelets [#/volume] in Blood by Automated count" + } + ], + "text" : "Platelet Count" + }, + "valueQuantity" : { + "value" : "444", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "150", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "450", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r7", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "6690-2", + "display" : "Leukocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "White Cell Count" + }, + "valueQuantity" : { + "value" : "4.6", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "4.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "11.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r8", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "770-8", + "display" : "Neutrophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Neutrophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r9", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "751-8", + "display" : "Neutrophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Neutrophils" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "LL" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "2.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "7.5", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r10", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "736-9", + "display" : "Lymphocytes/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Lymphocytes" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r11", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "731-0", + "display" : "Lymphocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Lymphocytes" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "L" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "1.1", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "4.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r12", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "5905-5", + "display" : "Monocytes/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Monocytes" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r13", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "742-7", + "display" : "Monocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Monocytes" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "0.2", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "1.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r14", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "713-8", + "display" : "Eosinophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Eosinophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r15", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "711-2", + "display" : "Eosinophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Eosinophils" + }, + "valueQuantity" : { + "value" : "0.92", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "HH" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "0.04", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "0.40", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r16", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "706-2", + "display" : "Basophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Basophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r17", + "text" : { + "status" : "empty", + "div" : "\r\n
Missing
" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "704-7", + "display" : "Basophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Basophils" + }, + "valueQuantity" : { + "value" : "0.92", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "high" : { + "value" : "0.21", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + } + ], + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "58410-2", + "display" : "Complete blood count (hemogram) panel - Blood by Automated count" + }, + { + "code" : "CBC", + "display" : "MASTER FULL BLOOD COUNT" + } + ], + "text" : "Complete Blood Count" + }, + "status" : "final", + "issued" : "2011-03-04T11:45:33+11:00", + "_issued" : { + }, + "subject" : { + "reference" : "Patient/pat2" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "5234342" + }, + "serviceCategory" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0074", + "code" : "HM" + } + ] + }, + "diagnosticDateTime" : "2011-03-04T08:30:00+11:00", + "result" : [ + { + "reference" : "#r1" + }, + { + "reference" : "#r2" + }, + { + "reference" : "#r3" + }, + { + "reference" : "#r4" + }, + { + "reference" : "#r5" + }, + { + "reference" : "#r6" + }, + { + "reference" : "#r7" + }, + { + "reference" : "#r8" + }, + { + "reference" : "#r9" + }, + { + "reference" : "#r10" + }, + { + "reference" : "#r11" + }, + { + "reference" : "#r12" + }, + { + "reference" : "#r13" + }, + { + "reference" : "#r14" + }, + { + "reference" : "#r15" + }, + { + "reference" : "#r16" + }, + { + "reference" : "#r17" + } + ], + "presentedForm" : [ + { + "contentType" : "application/pdf", + "language" : "en-AU", + "data" : "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PSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz48cGRmOlByb2R1Y2VyPkdQTCBHaG9zdHNjcmlwdCA5LjA0PC9wZGY6UHJvZHVjZXI+CjxwZGY6S2V5d29yZHM+KCk8L3BkZjpLZXl3b3Jkcz4KPC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSdlOTA4ODRhMy0zYzlhLTExZTEtMDAwMC02NDI2MDMzYWE1MCYjODsnIHhtbG5zOnhtcD0naHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyc+PHhtcDpNb2RpZnlEYXRlPjIwMTItMDEtMDlUMDg6MjU6NTQrMTE6MDA8L3htcDpNb2RpZnlEYXRlPgo8eG1wOkNyZWF0ZURhdGU+MjAxMi0wMS0wOVQwODoyNTo1NCsxMTowMDwveG1wOkNyZWF0ZURhdGU+Cjx4bXA6Q3JlYXRvclRvb2w+UERGQ3JlYXRvciBWZXJzaW9uIDEuMi4zPC94bXA6Q3JlYXRvclRvb2w+PC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSdlOTA4ODRhMy0zYzlhLTExZTEtMDAwMC02NDI2MDMzYWE1MCYjODsnIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vJyB4YXBNTTpEb2N1bWVudElEPSd1dWlkOmU5MDg4NGEzLTNjOWEtMTFlMS0wMDAwLTY0MjYwMzNhYTUwJiMxMzg7pyYjMTU3O+7SYyYjMzE7JiMxNjsnLz4KPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9J2U5MDg4NGEzLTNjOWEtMTFlMS0wMDAwLTY0MjYwMzNhYTUwJiM4OycgeG1sbnM6ZGM9J2h0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJyBkYzpmb3JtYXQ9J2FwcGxpY2F0aW9uL3BkZic+PGRjOnRpdGxlPjxyZGY6QWx0PjxyZGY6bGkgeG1sOmxhbmc9J3gtZGVmYXVsdCc+Q0JDIFJlcG9ydCBmb3IgV2lsZS4gRS4gQ09ZT1RFIChNUk46IDIzNDUzKSBpc3N1ZWQgMy1NYXIgMjAxMSAxMTo0NTwvcmRmOmxpPjwvcmRmOkFsdD48L2RjOnRpdGxlPjxkYzpjcmVhdG9yPjxyZGY6U2VxPjxyZGY6bGk+R3JhaGFtZTwvcmRmOmxpPjwvcmRmOlNlcT48L2RjOmNyZWF0b3I+PGRjOmRlc2NyaXB0aW9uPjxyZGY6U2VxPjxyZGY6bGk+KCk8L3JkZjpsaT48L3JkZjpTZXE+PC9kYzpkZXNjcmlwdGlvbj48L3JkZjpEZXNjcmlwdGlvbj4KPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSd3Jz8+CmVuZHN0cmVhbQplbmRvYmoKMiAwIG9iago8PC9Qcm9kdWNlcihHUEwgR2hvc3RzY3JpcHQgOS4wNCkKL0NyZWF0aW9uRGF0ZShEOjIwMTIwMTA5MDgyNTU0KzExJzAwJykKL01vZERhdGUoRDoyMDEyMDEwOTA4MjU1NCsxMScwMCcpCi9UaXRsZShcMzc2XDM3N1wwMDBDXDAwMEJcMDAwQ1wwMDAgXDAwMFJcMDAwZVwwMDBwXDAwMG9cMDAwclwwMDB0XDAwMCBcMDAwZlwwMDBvXDAwMHJcMDAwIFwwMDBXXDAwMGlcMDAwbFwwMDBlXDAwMC5cMDAwIFwwMDBFXDAwMC5cMDAwIFwwMDBDXDAwME9cMDAwWVwwMDBPXDAwMFRcMDAwRVwwMDAgXDAwMFwoXDAwME1cMDAwUlwwMDBOXDAwMDpcMDAwIFwwMDAyXDAwMDNcMDAwNFwwMDA1XDAwMDNcMDAwXClcMDAwIFwwMDBpXDAwMHNcMDAwc1wwMDB1XDAwMGVcMDAwZFwwMDAgXDAwMDNcMDAwLVwwMDBNXDAwMGFcMDAwclwwMDAgXDAwMDJcMDAwMFwwMDAxXDAwMDFcMDAwIFwwMDAxXDAwMDFcMDAwOlwwMDA0XDAwMDUpCi9DcmVhdG9yKFwzNzZcMzc3XDAwMFBcMDAwRFwwMDBGXDAwMENcMDAwclwwMDBlXDAwMGFcMDAwdFwwMDBvXDAwMHJcMDAwIFwwMDBWXDAwMGVcMDAwclwwMDBzXDAwMGlcMDAwb1wwMDBuXDAwMCBcMDAwMVwwMDAuXDAwMDJcMDAwLlwwMDAzKQovQXV0aG9yKFwzNzZcMzc3XDAwMEdcMDAwclwwMDBhXDAwMGhcMDAwYVwwMDBtXDAwMGUpCi9LZXl3b3JkcygpCi9TdWJqZWN0KCk+PmVuZG9iagp4cmVmCjAgMjEKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAyMTM3IDAwMDAwIG4gCjAwMDAwNjg3OTMgMDAwMDAgbiAKMDAwMDAwMjA3OCAwMDAwMCBuIAowMDAwMDAxOTM2IDAwMDAwIG4gCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMTkxNiAwMDAwMCBuIAowMDAwMDAyNjU2IDAwMDAwIG4gCjAwMDAwMDQ2ODEgMDAwMDAgbiAKMDAwMDAwMzQ3OSAwMDAwMCBuIAowMDAwMDIxNTc3IDAwMDAwIG4gCjAwMDAwMDQzMjkgMDAwMDAgbiAKMDAwMDA0MTMwNyAwMDAwMCBuIAowMDAwMDAyMjAyIDAwMDAwIG4gCjAwMDAwMDQ5MDUgMDAwMDAgbiAKMDAwMDAyMTc5MyAwMDAwMCBuIAowMDAwMDQxNTI5IDAwMDAwIG4gCjAwMDAwMDIyNTIgMDAwMDAgbiAKMDAwMDAwMjk0OCAwMDAwMCBuIAowMDAwMDAzODMxIDAwMDAwIG4gCjAwMDAwNjcwODggMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSAyMSAvUm9vdCAxIDAgUiAvSW5mbyAyIDAgUgovSUQgWzw4RDdGNzc5QTAwQzcwOTc5NTg3MDQyRjA5MkJBQjhDNj48OEQ3Rjc3OUEwMEM3MDk3OTU4NzA0MkYwOTJCQUI4QzY+XQo+PgpzdGFydHhyZWYKNjk0ODUKJSVFT0YK", + "title" : "HTML Report" + } + ] +} diff --git a/hapi-fhir-structures-dstu/src/test/resources/contained-diagnosticreport.xml b/hapi-fhir-structures-dstu/src/test/resources/contained-diagnosticreport.xml new file mode 100644 index 00000000000..4b46e4f1c9f --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/contained-diagnosticreport.xml @@ -0,0 +1,719 @@ + + + + +
+

CBC Report for Wile. E. COYOTE (MRN: 23453) issued 3-Mar 2011 11:45

+ +
Test                  Units       Value       Reference Range
Haemoglobin           g/L         176         135 - 180
Red Cell Count        x10*12/L    5.9         4.2 - 6.0
Haematocrit                       0.55+       0.38 - 0.52
Mean Cell Volume      fL          99+         80 - 98
Mean Cell Haemoglobin pg          36+         27 - 35
Platelet Count        x10*9/L     444         150 - 450
White Cell Count      x10*9/L     4.6         4.0 - 11.0
Neutrophils           %           20 
Neutrophils           x10*9/L     0.9---      2.0 - 7.5
Lymphocytes           %           20  
Lymphocytes           x10*9/L     0.9-        1.1 - 4.0
Monocytes             %           20 
Monocytes             x10*9/L     0.9         0.2 - 1.0
Eosinophils           %           20 
Eosinophils           x10*9/L     0.92++      0.04 - 0.40
Basophils             %           20 
Basophils             x10*9/L     0.92+++     <0.21
      
+

Acme Laboratory, Inc signed: Dr Pete Pathologist

+
+ + + + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + +
+
+ + + + +
Missing
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + </presentedForm> +</DiagnosticReport> \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/diagnostic-report.json b/hapi-fhir-structures-dstu/src/test/resources/diagnostic-report.json new file mode 100644 index 00000000000..13da9f64c94 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/diagnostic-report.json @@ -0,0 +1,781 @@ +{ + "resourceType" : "DiagnosticReport", + "text" : { + "status" : "generated", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\"> \r\n <h3>CBC Report for Wile. E. COYOTE (MRN: 23453) issued 3-Mar 2011 11:45</h3> \r\n <!-- you could use ab html table here, but laboratories are still \n using fixed text tables, and this will take decades to change... --> \r\n <pre> Test Units Value Reference Range Haemoglobin g/L 176 135 - 180 Red Cell Count x10*12/L 5.9 4.2 - 6.0 Haematocrit 0.55+ 0.38 - 0.52 Mean Cell Volume fL 99+ 80 - 98 Mean Cell Haemoglobin pg 36+ 27 - 35 Platelet Count x10*9/L 444 150 - 450 White Cell Count x10*9/L 4.6 4.0 - 11.0 Neutrophils % 20 Neutrophils x10*9/L 0.9--- 2.0 - 7.5 Lymphocytes % 20 Lymphocytes x10*9/L 0.9- 1.1 - 4.0 Monocytes % 20 Monocytes x10*9/L 0.9 0.2 - 1.0 Eosinophils % 20 Eosinophils x10*9/L 0.92++ 0.04 - 0.40 Basophils % 20 Basophils x10*9/L 0.92+++ <0.21 </pre> \r\n <p>Acme Laboratory, Inc signed: Dr Pete Pathologist</p> </div>" + }, + "contained" : [ + { + "resourceType" : "Observation", + "id" : "r1", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "718-7", + "display" : "Hemoglobin [Mass/volume] in Blood" + } + ], + "text" : "Haemoglobin" + }, + "valueQuantity" : { + "value" : "176", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "135", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + }, + "high" : { + "value" : "180", + "units" : "g/L", + "system" : "http://unitsofmeasure.org", + "code" : "g/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r2", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "789-8", + "display" : "Erythrocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Red Cell Count" + }, + "valueQuantity" : { + "value" : "5.9", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "4.2", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + }, + "high" : { + "value" : "6.0", + "units" : "x10*12/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*12/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r3", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "4544-3", + "display" : "Hematocrit [Volume Fraction] of Blood by Automated count" + } + ], + "text" : "Haematocrit" + }, + "valueQuantity" : { + "value" : "55", + "units" : "%" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "38", + "units" : "%" + }, + "high" : { + "value" : "52", + "units" : "%" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r4", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "787-2", + "display" : "Erythrocyte mean corpuscular volume [Entitic volume] by Automated count" + } + ], + "text" : "Mean Cell Volume" + }, + "valueQuantity" : { + "value" : "99", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "80", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + }, + "high" : { + "value" : "98", + "units" : "fL", + "system" : "http://unitsofmeasure.org", + "code" : "fL" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r5", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "785-6", + "display" : "Erythrocyte mean corpuscular hemoglobin [Entitic mass] by Automated count" + } + ], + "text" : "Mean Cell Haemoglobin" + }, + "valueQuantity" : { + "value" : "36", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "H" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "27", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + }, + "high" : { + "value" : "35", + "units" : "pg", + "system" : "http://unitsofmeasure.org", + "code" : "pg" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r6", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "777-3", + "display" : "Platelets [#/volume] in Blood by Automated count" + } + ], + "text" : "Platelet Count" + }, + "valueQuantity" : { + "value" : "444", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "150", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "450", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r7", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "6690-2", + "display" : "Leukocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "White Cell Count" + }, + "valueQuantity" : { + "value" : "4.6", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "4.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "11.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r8", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "770-8", + "display" : "Neutrophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Neutrophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r9", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "751-8", + "display" : "Neutrophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Neutrophils" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "LL" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "2.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "7.5", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r10", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "736-9", + "display" : "Lymphocytes/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Lymphocytes" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r11", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "731-0", + "display" : "Lymphocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Lymphocytes" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "L" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "1.1", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "4.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r12", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "5905-5", + "display" : "Monocytes/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Monocytes" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r13", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "742-7", + "display" : "Monocytes [#/volume] in Blood by Automated count" + } + ], + "text" : "Monocytes" + }, + "valueQuantity" : { + "value" : "0.9", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "0.2", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "1.0", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r14", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "713-8", + "display" : "Eosinophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Eosinophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r15", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "711-2", + "display" : "Eosinophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Eosinophils" + }, + "valueQuantity" : { + "value" : "0.92", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "interpretation" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0078", + "code" : "HH" + } + ] + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "low" : { + "value" : "0.04", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "high" : { + "value" : "0.40", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + }, + { + "resourceType" : "Observation", + "id" : "r16", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "706-2", + "display" : "Basophils/100 leukocytes in Blood by Automated count" + } + ], + "text" : "Basophils" + }, + "valueQuantity" : { + "value" : "20", + "units" : "%", + "system" : "http://unitsofmeasure.org", + "code" : "%" + }, + "status" : "final", + "reliability" : "ok" + }, + { + "resourceType" : "Observation", + "id" : "r17", + "text" : { + "status" : "empty", + "div" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\">Missing</div>" + }, + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "704-7", + "display" : "Basophils [#/volume] in Blood by Automated count" + } + ], + "text" : "Basophils" + }, + "valueQuantity" : { + "value" : "0.92", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + }, + "status" : "final", + "reliability" : "ok", + "referenceRange" : [ + { + "high" : { + "value" : "0.21", + "units" : "x10*9/L", + "system" : "http://unitsofmeasure.org", + "code" : "10*9/L" + } + } + ] + } + ], + "name" : { + "coding" : [ + { + "system" : "http://loinc.org", + "code" : "58410-2", + "display" : "Complete blood count (hemogram) panel - Blood by Automated count" + }, + { + "code" : "CBC", + "display" : "MASTER FULL BLOOD COUNT" + } + ], + "text" : "Complete Blood Count" + }, + "status" : "final", + "issued" : "2011-03-04T11:45:33+11:00", + "_issued" : { + }, + "subject" : { + "reference" : "Patient/pat2" + }, + "performer" : { + "reference" : "Organization/1832473e-2fe0-452d-abe9-3cdb9879522f", + "display" : "Acme Laboratory, Inc" + }, + "identifier" : { + "system" : "http://acme.com/lab/reports", + "value" : "5234342" + }, + "serviceCategory" : { + "coding" : [ + { + "system" : "http://hl7.org/fhir/v2/0074", + "code" : "HM" + } + ] + }, + "diagnosticDateTime" : "2011-03-04T08:30:00+11:00", + "result" : [ + { + "reference" : "#r1" + }, + { + "reference" : "#r2" + }, + { + "reference" : "#r3" + }, + { + "reference" : "#r4" + }, + { + "reference" : "#r5" + }, + { + "reference" : "#r6" + }, + { + "reference" : "#r7" + }, + { + "reference" : "#r8" + }, + { + "reference" : "#r9" + }, + { + "reference" : "#r10" + }, + { + "reference" : "#r11" + }, + { + "reference" : "#r12" + }, + { + "reference" : "#r13" + }, + { + "reference" : "#r14" + }, + { + "reference" : "#r15" + }, + { + "reference" : "#r16" + }, + { + "reference" : "#r17" + } + ], + "presentedForm" : [ + { + "contentType" : "application/pdf", + "language" : "en-AU", + "data" : "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PSdodHRwOi8vbnMuYWRvYmUuY29tL3BkZi8xLjMvJz48cGRmOlByb2R1Y2VyPkdQTCBHaG9zdHNjcmlwdCA5LjA0PC9wZGY6UHJvZHVjZXI+CjxwZGY6S2V5d29yZHM+KCk8L3BkZjpLZXl3b3Jkcz4KPC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSdlOTA4ODRhMy0zYzlhLTExZTEtMDAwMC02NDI2MDMzYWE1MCYjODsnIHhtbG5zOnhtcD0naHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyc+PHhtcDpNb2RpZnlEYXRlPjIwMTItMDEtMDlUMDg6MjU6NTQrMTE6MDA8L3htcDpNb2RpZnlEYXRlPgo8eG1wOkNyZWF0ZURhdGU+MjAxMi0wMS0wOVQwODoyNTo1NCsxMTowMDwveG1wOkNyZWF0ZURhdGU+Cjx4bXA6Q3JlYXRvclRvb2w+UERGQ3JlYXRvciBWZXJzaW9uIDEuMi4zPC94bXA6Q3JlYXRvclRvb2w+PC9yZGY6RGVzY3JpcHRpb24+CjxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSdlOTA4ODRhMy0zYzlhLTExZTEtMDAwMC02NDI2MDMzYWE1MCYjODsnIHhtbG5zOnhhcE1NPSdodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vJyB4YXBNTTpEb2N1bWVudElEPSd1dWlkOmU5MDg4NGEzLTNjOWEtMTFlMS0wMDAwLTY0MjYwMzNhYTUwJiMxMzg7pyYjMTU3O+7SYyYjMzE7JiMxNjsnLz4KPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9J2U5MDg4NGEzLTNjOWEtMTFlMS0wMDAwLTY0MjYwMzNhYTUwJiM4OycgeG1sbnM6ZGM9J2h0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvJyBkYzpmb3JtYXQ9J2FwcGxpY2F0aW9uL3BkZic+PGRjOnRpdGxlPjxyZGY6QWx0PjxyZGY6bGkgeG1sOmxhbmc9J3gtZGVmYXVsdCc+Q0JDIFJlcG9ydCBmb3IgV2lsZS4gRS4gQ09ZT1RFIChNUk46IDIzNDUzKSBpc3N1ZWQgMy1NYXIgMjAxMSAxMTo0NTwvcmRmOmxpPjwvcmRmOkFsdD48L2RjOnRpdGxlPjxkYzpjcmVhdG9yPjxyZGY6U2VxPjxyZGY6bGk+R3JhaGFtZTwvcmRmOmxpPjwvcmRmOlNlcT48L2RjOmNyZWF0b3I+PGRjOmRlc2NyaXB0aW9uPjxyZGY6U2VxPjxyZGY6bGk+KCk8L3JkZjpsaT48L3JkZjpTZXE+PC9kYzpkZXNjcmlwdGlvbj48L3JkZjpEZXNjcmlwdGlvbj4KPC9yZGY6UkRGPgo8L3g6eG1wbWV0YT4KICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIAo8P3hwYWNrZXQgZW5kPSd3Jz8+CmVuZHN0cmVhbQplbmRvYmoKMiAwIG9iago8PC9Qcm9kdWNlcihHUEwgR2hvc3RzY3JpcHQgOS4wNCkKL0NyZWF0aW9uRGF0ZShEOjIwMTIwMTA5MDgyNTU0KzExJzAwJykKL01vZERhdGUoRDoyMDEyMDEwOTA4MjU1NCsxMScwMCcpCi9UaXRsZShcMzc2XDM3N1wwMDBDXDAwMEJcMDAwQ1wwMDAgXDAwMFJcMDAwZVwwMDBwXDAwMG9cMDAwclwwMDB0XDAwMCBcMDAwZlwwMDBvXDAwMHJcMDAwIFwwMDBXXDAwMGlcMDAwbFwwMDBlXDAwMC5cMDAwIFwwMDBFXDAwMC5cMDAwIFwwMDBDXDAwME9cMDAwWVwwMDBPXDAwMFRcMDAwRVwwMDAgXDAwMFwoXDAwME1cMDAwUlwwMDBOXDAwMDpcMDAwIFwwMDAyXDAwMDNcMDAwNFwwMDA1XDAwMDNcMDAwXClcMDAwIFwwMDBpXDAwMHNcMDAwc1wwMDB1XDAwMGVcMDAwZFwwMDAgXDAwMDNcMDAwLVwwMDBNXDAwMGFcMDAwclwwMDAgXDAwMDJcMDAwMFwwMDAxXDAwMDFcMDAwIFwwMDAxXDAwMDFcMDAwOlwwMDA0XDAwMDUpCi9DcmVhdG9yKFwzNzZcMzc3XDAwMFBcMDAwRFwwMDBGXDAwMENcMDAwclwwMDBlXDAwMGFcMDAwdFwwMDBvXDAwMHJcMDAwIFwwMDBWXDAwMGVcMDAwclwwMDBzXDAwMGlcMDAwb1wwMDBuXDAwMCBcMDAwMVwwMDAuXDAwMDJcMDAwLlwwMDAzKQovQXV0aG9yKFwzNzZcMzc3XDAwMEdcMDAwclwwMDBhXDAwMGhcMDAwYVwwMDBtXDAwMGUpCi9LZXl3b3JkcygpCi9TdWJqZWN0KCk+PmVuZG9iagp4cmVmCjAgMjEKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAyMTM3IDAwMDAwIG4gCjAwMDAwNjg3OTMgMDAwMDAgbiAKMDAwMDAwMjA3OCAwMDAwMCBuIAowMDAwMDAxOTM2IDAwMDAwIG4gCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMTkxNiAwMDAwMCBuIAowMDAwMDAyNjU2IDAwMDAwIG4gCjAwMDAwMDQ2ODEgMDAwMDAgbiAKMDAwMDAwMzQ3OSAwMDAwMCBuIAowMDAwMDIxNTc3IDAwMDAwIG4gCjAwMDAwMDQzMjkgMDAwMDAgbiAKMDAwMDA0MTMwNyAwMDAwMCBuIAowMDAwMDAyMjAyIDAwMDAwIG4gCjAwMDAwMDQ5MDUgMDAwMDAgbiAKMDAwMDAyMTc5MyAwMDAwMCBuIAowMDAwMDQxNTI5IDAwMDAwIG4gCjAwMDAwMDIyNTIgMDAwMDAgbiAKMDAwMDAwMjk0OCAwMDAwMCBuIAowMDAwMDAzODMxIDAwMDAwIG4gCjAwMDAwNjcwODggMDAwMDAgbiAKdHJhaWxlcgo8PCAvU2l6ZSAyMSAvUm9vdCAxIDAgUiAvSW5mbyAyIDAgUgovSUQgWzw4RDdGNzc5QTAwQzcwOTc5NTg3MDQyRjA5MkJBQjhDNj48OEQ3Rjc3OUEwMEM3MDk3OTU4NzA0MkYwOTJCQUI4QzY+XQo+PgpzdGFydHhyZWYKNjk0ODUKJSVFT0YK", + "title" : "HTML Report" + } + ] + }, + "summary" : "\r\n<div xmlns=\"http://www.w3.org/1999/xhtml\"> \r\n <h3>CBC Report for Wile. E. COYOTE (MRN: 23453) issued 3-Mar 2011 11:45</h3> \r\n <!-- you could use ab html table here, but laboratories are still \n using fixed text tables, and this will take decades to change... --> \r\n <pre> Test Units Value Reference Range Haemoglobin g/L 176 135 - 180 Red Cell Count x10*12/L 5.9 4.2 - 6.0 Haematocrit 0.55+ 0.38 - 0.52 Mean Cell Volume fL 99+ 80 - 98 Mean Cell Haemoglobin pg 36+ 27 - 35 Platelet Count x10*9/L 444 150 - 450 White Cell Count x10*9/L 4.6 4.0 - 11.0 Neutrophils % 20 Neutrophils x10*9/L 0.9--- 2.0 - 7.5 Lymphocytes % 20 Lymphocytes x10*9/L 0.9- 1.1 - 4.0 Monocytes % 20 Monocytes x10*9/L 0.9 0.2 - 1.0 Eosinophils % 20 Eosinophils x10*9/L 0.92++ 0.04 - 0.40 Basophils % 20 Basophils x10*9/L 0.92+++ <0.21 </pre> \r\n <p>Acme Laboratory, Inc signed: Dr Pete Pathologist</p> </div>" + } + diff --git a/hapi-fhir-structures-dstu/src/test/resources/example-metadata.xml b/hapi-fhir-structures-dstu/src/test/resources/example-metadata.xml new file mode 100644 index 00000000000..8db5ea89748 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/example-metadata.xml @@ -0,0 +1,85 @@ +<Conformance xmlns="http://hl7.org/fhir"> + <extension url="http://hl7.org/fhir/Profile/tools-extensions#supported-system"> + <valueUri value="http://snomed.info/sct"/> + </extension> + <text> + <status value="generated"/> + <div xmlns="http://www.w3.org/1999/xhtml"> + </div> + </text> + <publisher value="Health Intersections"/> + <date value="2014-03-12T01:00:56Z"/> + <software> + <name value="Reference Server"/> + <version value="0.80-2286"/> + <releaseDate value="2013-11-03"/> + </software> + <fhirVersion value="0.80-2286"/> + <format value="application/xml+fhir"/> + <format value="application/json+fhir"/> + <rest> + <mode value="server"/> + <resource> + <type value="AdverseReaction"/> + <profile> + <reference value="http://fhir.healthintersections.com.au/open/Profile/adversereaction"/> + </profile> + <operation> + <code value="read"/> + </operation> + <operation> + <code value="vread"/> + </operation> + <operation> + <code value="search-type"/> + </operation> + <operation> + <code value="update"/> + </operation> + <operation> + <code value="history-type"/> + </operation> + <operation> + <code value="create"/> + </operation> + <operation> + <code value="delete"/> + </operation> + <operation> + <code value="history-instance"/> + </operation> + <readHistory value="true"/> + </resource> + <resource> + <type value="Alert"/> + <profile> + <reference value="http://fhir.healthintersections.com.au/open/Profile/alert"/> + </profile> + <operation> + <code value="read"/> + </operation> + <operation> + <code value="vread"/> + </operation> + <operation> + <code value="search-type"/> + </operation> + <operation> + <code value="update"/> + </operation> + <operation> + <code value="history-type"/> + </operation> + <operation> + <code value="create"/> + </operation> + <operation> + <code value="delete"/> + </operation> + <operation> + <code value="history-instance"/> + </operation> + <readHistory value="true"/> + </resource> + </rest> +</Conformance> diff --git a/hapi-fhir-structures-dstu/src/test/resources/example-patient-general.json b/hapi-fhir-structures-dstu/src/test/resources/example-patient-general.json new file mode 100644 index 00000000000..69e05527191 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/example-patient-general.json @@ -0,0 +1,149 @@ +{ + "resourceType":"Patient", + "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" + } + ], + "text":{ + "status":"generated", + "div":"<div xmlns=\"http://www.w3.org/1999/xhtml\">\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>" + }, + "identifier":[ + { + "use":"usual", + "label":"MRN", + "system":"urn:oid:1.2.36.146.595.217.0.1", + "value":"12345", + "period":{ + "start":"2001-05-06" + }, + "assigner":{ + "display":"Acme Healthcare" + } + } + ], + "name":[ + { + "use":"official", + "family":[ + "Chalmers" + ], + "given":[ + "Peter", + "James" + ] + }, + { + "use":"usual", + "given":[ + "Jim" + ] + } + ], + "telecom":[ + { + "use":"home" + }, + { + "system":"phone", + "value":"(03) 5555 6473", + "use":"work" + } + ], + "gender":{ + "coding":[ + { + "system":"http://hl7.org/fhir/v3/AdministrativeGender", + "code":"M", + "display":"Male" + } + ] + }, + "birthDate":"1974-12-25", + "deceasedBoolean":false, + "address":[ + { + "use":"home", + "line":[ + "534 Erewhon St" + ], + "city":"PleasantVille", + "state":"Vic", + "zip":"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" + }, + "active":true +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/example-patient-general.xml b/hapi-fhir-structures-dstu/src/test/resources/example-patient-general.xml new file mode 100644 index 00000000000..84018bed288 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/example-patient-general.xml @@ -0,0 +1,140 @@ +<Patient xmlns="http://hl7.org/fhir"> +<!-- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://hl7.org/fhir ./fhir-single.xsd"> --> + <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> + + <text> + <status value="generated"/> + <div xmlns="http://www.w3.org/1999/xhtml"> + <table> + <tbody> + <tr> + <td>Name</td> + <td>Peter James <b>Chalmers</b> ("Jim")</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> + + <!-- MRN assigned by ACME healthcare on 6-May 2001 --> + <identifier> + <use value="usual"/> + <label value="MRN"/> + <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> + + <!-- Peter James Chalmers, but called "Jim" --> + <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"/> + <!-- home communication details aren't known --> + </telecom> + <telecom> + <system value="phone"/> + <value value="(03) 5555 6473"/> + <use value="work"/> + </telecom> + + <!-- use FHIR code system for male / female --> + <gender> + <coding> + <system value="http://hl7.org/fhir/v3/AdministrativeGender"/> + <code value="M"/> + <display value="Male"/> + </coding> + </gender> + <birthDate value="1974-12-25"/> + <deceasedBoolean value="false"/> + + <address> + <use value="home"/> + <line value="534 Erewhon St"/> + <city value="PleasantVille"/> + <state value="Vic"/> + <zip 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"> + <!-- the "du" part is a family name prefix (VV in iso 21090) --> + <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> + + <active value="true"/> + +</Patient> \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/example-uhn-conformance.xml b/hapi-fhir-structures-dstu/src/test/resources/example-uhn-conformance.xml new file mode 100644 index 00000000000..d951057c5e2 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/example-uhn-conformance.xml @@ -0,0 +1,99 @@ +<Conformance xmlns="http://hl7.org/fhir" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://hl7.org/fhir ./fhir-single.xsd"> + <text> + + <status value="generated"/> + <div xmlns="http://www.w3.org/1999/xhtml"> + <p>This is the conformance statement for the UHN server</p> + </div> + </text> + <!-- the identifier for this conformance statement. + The identifier and version establish identifiers that other specifications etc may + use to + refer to the conformance statement that this resource represents in a logical manner + + rather than in a literal (URL) fashion + + The identifier should be globally unique - a UUID, an OID, or a URL/URI + --> + + <identifier value="urn:uhn:fhir:conformance:sail"/> + <version value="20130510"/> + <name value="ACME EHR Conformance statement"/> + <publisher value="ACME Corporation"/> + <telecom> + <system value="email"/> + <value value="wile@acme.org"/> + </telecom> + <description value="This is the FHIR conformance statement for the main EHR at ACME for the private interface + - it does not describe the public interface"/> + <date value="2012-01-04"/> + <software> + <name value="EHR"/> + <version value="0.00.020.2134"/> + </software> + + <!-- while the FHIR infrastructure is turning over prior to development, a version is + required. Note that this may be rescinded later? --> + <fhirVersion value="dstu"/> + + <!-- this system accepts unknown content in the resources --> + <acceptUnknown value="true"/> + + <!-- this system can do either xml or json. (Listing both implies full support for either, + with interconversion) --> + <format value="xml"/> + <format value="json"/> + + <!-- in a real conformance statement, it's unlikely that a single conformance statement + would declare conformance for REST, messaging and documents, though it is legal. + This example does so in order to show all the parts of a conformance statement --> + <rest> + <!-- this is a server conformance statement. Note that servers are required to provide + one of these. It can easily be edited by hand - copy this, replace the metadata + above, + delete the messaging and document stuff below, and then replace the details appropriately. + --> + <mode value="server"/> + <!-- zero or more of these - declaration of support for a resource --> + <resource> + <type value="Patient"/> + <!-- let's assume that HL7 has stood up a profile registry at http://fhir.hl7.org/fhir + - it's likely to have a registry, though this is not decided, nor is a URL decided. + + This application simply uses a profile registered directly with HL7. For the simplest + + case of a FHIR REST Server, just delete this profile reference. Profile references + do + not need to be a UUID, though a profile registry could insist that they are --> + <profile> + <reference value="http://fhir.hl7.org/base/Profile7896271d-57f6-4231-89dc-dcc91eab2416"/> + </profile> + <operation> + <code value="read"/> + </operation> + <operation> + <code value="vread"/> + </operation> + <operation> + <code value="update"/> + </operation> + <operation> + <code value="history-instance"/> + </operation> + <operation> + <code value="create"/> + </operation> + <operation> + <code value="history-type"/> + </operation> + </resource> + <operation> + <code value="transaction"/> + </operation> + <operation> + <code value="history-system"/> + </operation> + </rest> + + +</Conformance> \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/example-uhn-profile.xml b/hapi-fhir-structures-dstu/src/test/resources/example-uhn-profile.xml new file mode 100644 index 00000000000..35035131d11 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/example-uhn-profile.xml @@ -0,0 +1,23 @@ +<Profile xmlns="http://hl7.org/fhir" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://hl7.org/fhir ./fhir-single.xsd"> + + <identifier value="urn:uhn:fhir:profile:cgta" /> + <version value="0.1" /> + <name value="SAIL Object Profile" /> + <status value="draft" /> + + <structure> + <type value="Patient" /> + <name value="CGTAPatient" /> + <element> + <path value="Patient.identifier"/> + <!-- <slicing> + <discriminator value="" /> + <ordered value="true"/> + <rules value="open"/> + </slicing> --> + </element> + </structure> + + +</Profile> diff --git a/hapi-fhir-structures-dstu/src/test/resources/feed-with-list.xml b/hapi-fhir-structures-dstu/src/test/resources/feed-with-list.xml new file mode 100644 index 00000000000..9372f3699e3 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/feed-with-list.xml @@ -0,0 +1,223 @@ +<?xml version="1.0" encoding="UTF-8"?> +<feed xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://www.w3.org/2005/Atom ../../Blogs/fhir-all-xsd/fhir-atom.xsd" + xmlns="http://www.w3.org/2005/Atom"> + <title>Glucosemeter data from suresense + urn:uuid:500bee81-d973-4afe-b592-d39fe71e38 + 2014-05-28T22:12:21Z + + Aaron Jackson + + + + + + Patient details + cid:patient@bundle + 2014-05-28T22:12:21Z + + + + + +
Joe Bloggs
+
+ + + + + + + +
+
+
+ + + Practitioner + cid:practioner@bundle + 2014-05-28T22:12:21Z + + + + + +
+ + + + + + + + Medication List + cid:list1 + 2013-05-28T22:12:21Z + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Medication 1 + cid:med1 + 2013-05-29T22:12:21Z + + + + + +
Atenolol 50mg 1 mane
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + Medication 2 + cid:med2 + 2013-05-29T22:12:21Z + + + + + +
Voltaren 25mg 3 times a day
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + Medication 3 + cid:med2 + 2013-05-29T22:12:21Z + + + + + +
Voltaren 25mg 3 times a day
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+ + + \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/fhir-single.xsd b/hapi-fhir-structures-dstu/src/test/resources/fhir-single.xsd new file mode 100644 index 00000000000..c486ae52c50 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/fhir-single.xsd @@ -0,0 +1,12358 @@ + + + + + + + + + + + + + + + The base element used for all FHIR elements and resources - allows for them to be extended with extensions + + + + + An extension - additional local content. The extension URL defines it's meaning + + + + + + + + + An element defined in a FHIR resources - can have modifierExtension elements + + + + + + + An extension that modifies the meaning of the element that contains it - additional local content. The extension URL defines it's meaning + + + + + + + + + + + + + + A whole number + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + + + A date, date-time or partial date (e.g. just year or year + month). If hours and minutes are specified, a time zone SHALL be populated. The format is a union of the schema types gYear, gYearMonth, date and dateTime. Seconds may be provided but may also be ignored. Dates SHALL be valid dates. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + A string which has at least one character and no leading or trailing whitespace and where there is no whitespace other than single spaces in the contents + If the element is present, it must have either a @value, an @id referenced from the Narrative, or extensions + + + + + + + + + + + + + + + + + + A date, or partial date (e.g. just year or year + month). There is no time zone. The format is a union of the schema types gYear, gYearMonth and date. Dates SHALL be valid dates. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + A rational number with implicit precision + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + String of characters used to identify a name or a resource + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + A whole number in the range 0 to 2^64-1, optionally represented in hex, a uuid, an oid or any other combination of lower-case letters a-z, numerals, "-" and ".", with a length limit of 36 characters + If the element is present, it must have either a @value, an @id referenced from the Narrative, or extensions + + + + + + + + + + + + + A stream of bytes + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + An oid represented as a URI + If the element is present, it must have either a @value, an @id referenced from the Narrative, or extensions + + + + + + + + + + + + + + + A sequence of Unicode characters + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + Value of "true" or "false" + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + A UUID, represented as a URI + If the element is present, it must have either a @value, an @id referenced from the Narrative, or extensions + + + + + + + + + + + + + An instant in time - known at least to the second + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + Provenance information that describes the activity that led to the creation of a set of resources. This information can be used to help determine their reliability or trace where the information in them came from. The focus of the provenance resource is record keeping, audit and traceability, and not explicit statements of clinical significance. + + + + + Use to record detailed information about conditions, problems or diagnoses recognized by a clinician. There are many uses including: recording a Diagnosis during an Encounter; populating a problem List or a Summary Statement, such as a Discharge Summary. + + + + + Describes the intention of how one or more practitioners intend to deliver care for a particular patient for a period of time, possibly limited to care for a specific condition or set of conditions. + + + + + A supply - a request for something, and provision of what is supplied. + + + + + This resource identifies an instance of a manufactured thing that is used in the provision of healthcare without being substantially changed through that activity. The device may be a machine, an insert, a computer, an application, etc. This includes durable (reusable) medical equipment as well as disposable equipment used for diagnostic, treatment, and research for healthcare and public health. + + + + + A description of a query with a set of parameters. + + + + + A request to perform an action. + + + + + A formally or informally recognized grouping of people or organizations formed for the purpose of achieving some form of collective action. Includes companies, institutions, corporations, departments, community groups, healthcare practice groups, etc. + + + + + An action that is performed on a patient. This can be a physical 'thing' like an operation, or less invasive like counseling or hypnotherapy. + + + + + A homogeneous material with a definite composition. + + + + + The findings and interpretation of diagnostic tests performed on patients, groups of patients, devices, and locations, and/or specimens derived from these. The report includes clinical context such as requesting and provider information, and some mix of atomic results, images, textual and coded interpretation, and formatted representation of diagnostic reports. + + + + + Represents a defined collection of entities that may be discussed or acted upon collectively but which are not expected to act collectively and are not formally or legally recognized. I.e. A collection of entities that isn't an Organization. + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + Primarily used for identification and definition of Medication, but also covers ingredients and packaging. + + + + + The header for a message exchange that is either requesting or responding to an action. The resource(s) that are the subject of the action as well as other Information related to the action are typically transmitted in a bundle in which the MessageHeader resource instance is the first resource in the bundle. + + + + + A patient's point-of-time immunization status and recommendation with optional supporting justification. + + + + + A manifest that defines a set of documents. + + + + + Dispensing a medication to a named patient. This includes a description of the supply provided and the instructions for administering the medication. + + + + + An order for both supply of the medication and the instructions for administration of the medicine to a patient. + + + + + Describes the event of a patient being given a dose of a medication. This may be as simple as swallowing a tablet or it may be a long running infusion. + +Related resources tie this event to the authorizing prescription, and the specific encounter between patient and health care practitioner. + + + + + An interaction between a patient and healthcare provider(s) for the purpose of providing healthcare service(s) or assessing the health status of a patient. + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + A record of medication being taken by a patient, or that the medication has been given to a patient where the record is the result of a report from the patient or another clinician. + + + + + A set of information summarized from a list of other resources. + + + + + A structured set of questions and their answers. The Questionnaire may contain questions, answers or both. The questions are ordered and grouped into coherent subsets, corresponding to the structure of the grouping of the underlying questions. + + + + + A set of healthcare-related information that is assembled together into a single logical document that provides a single coherent statement of meaning, establishes its own context and that has clinical attestation with regard to who is making the statement. + + + + + Describes the data produced by a device at a point in time. + + + + + A collection of error, warning or information messages that result from a system action. + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + A photo, video, or audio recording acquired or used in healthcare. The actual content may be inline or provided by direct reference. + + + + + Significant health events and conditions for people related to the subject relevant in the context of care for the subject. + + + + + Other is a conformant for handling resource concepts not yet defined for FHIR or outside HL7's scope of interest. + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + Details and position information for a physical place where services are provided and resources and participants may be stored, found, contained or accommodated. + + + + + Measurements and simple assertions made about a patient, device or other subject. + + + + + Indicates the patient has a susceptibility to an adverse reaction upon exposure to a specified substance. + + + + + A reference to a document. + + + + + Immunization event information. + + + + + Information about a person that is involved in the care for a patient, but who is not the target of healthcare, nor has a formal responsibility in the care process. + + + + + Sample for analysis. + + + + + A response to an order. + + + + + Prospective warnings of potential issues when providing care to the patient. + + + + + A statement of relationships from one set of concepts to one or more other concept systems. + + + + + Demographics and other administrative information about a person or animal receiving care or other health-related services. + + + + + A person who is directly or indirectly involved in the provisioning of healthcare. + + + + + Records an unexpected reaction suspected to be related to the exposure of the reaction subject to a substance. + + + + + Manifest of a set of images produced in study. The set of images may include every image in the study, or it may be an incomplete sample, such as a list of key images. + + + + + A request for a diagnostic investigation service to be performed. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The base resource declaration used for all FHIR resource types - adds Narrative and xml:lang + + + + + + + The human language of the content. The value can be any valid value according to BCP-47 + + + + + Text summary of resource content (for human interpretation) + + + + + Contained, inline Resources. These resources do not have an independent existence apart from the resource that contains them - they cannot be identified independently, and nor can they have their own independent transaction scope + + + + + + + + + + Optional Extensions Element - found in all resources. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + Value of extension - may be a resource or one of a constrained set of the data types (see Extensibility in the spec for list). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A human-readable formatted text, including images. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data. + + + + + The actual narrative content, a stripped down version of XHTML. + + + + + + + + + + + The contents of the narrative are entirely generated from the structured data in the resource. + + + + + The contents of the narrative are entirely generated from the structured data in the resource and some of the content is generated from extensions. + + + + + The contents of the narrative contain additional information not found in the structured data. + + + + + the contents of the narrative are some equivalent of "No human-readable text provided for this resource". + + + + + + + The status of a resource narrative + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A time period defined by a start and end date and optionally time. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The start of the period. The boundary is inclusive. + + + + + The end of the period. If the end of the period is missing, it means that the period is ongoing. + + + + + + + + + A reference to a code defined by a terminology system. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The identification of the code system that defines the meaning of the symbol in the code. + + + + + The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged. + + + + + A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination). + + + + + A representation of the meaning of the code in the system, following the rules of the system. + + + + + Indicates that this code was chosen by a user directly - i.e. off a pick list of available items (codes or displays). + + + + + The set of possible coded values this coding was chosen from or constrained by. + + + + + + + + + A set of ordered Quantities defined by a low and high limit. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The low limit. The boundary is inclusive. + + + + + The high limit. The boundary is inclusive. + + + + + + + + + A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The value of the measured amount. The value includes an implicit precision in the presentation of the value. + + + + + How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is "<" , then the real value is < stated value. + + + + + A human-readable form of the units. + + + + + The identification of the system that provides the coded form of the unit. + + + + + A computer processable form of the units in some unit representation system. + + + + + + + + + + + The actual value is less than the given value. + + + + + The actual value is less than or equal to the given value. + + + + + The actual value is greater than or equal to the given value. + + + + + The actual value is greater than the given value. + + + + + + + How the Quantity should be understood and represented + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + For referring to data content defined in other formats. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + Identifies the type of the data in the attachment and allows a method to be chosen to interpret or render the data. Includes mime type parameters such as charset where appropriate. + + + + + The human language of the content. The value can be any valid value according to BCP 47. + + + + + The actual data of the attachment - a sequence of bytes. In XML, represented using base64. + + + + + An alternative location where the data can be accessed. + + + + + The number of bytes of data that make up this attachment. + + + + + The calculated hash of the data using SHA-1. Represented using base64. + + + + + A label or set of text to display in place of the data. + + + + + + + + + A relationship of two Quantity values - expressed as a numerator and a denominator. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The value of the numerator. + + + + + The value of the denominator. + + + + + + + + + A series of measurements taken by a device, with upper and lower limits. There may be more than one dimension in the data. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series. + + + + + The length of time between sampling times, measured in milliseconds. + + + + + A correction factor that is applied to the sampled data points before they are added to the origin. + + + + + The lower limit of detection of the measured points. This is needed if any of the data points have the value "L" (lower than detection limit). + + + + + The upper limit of detection of the measured points. This is needed if any of the data points have the value "U" (higher than detection limit). + + + + + The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once. + + + + + A series of data points which are decimal values separated by a single space (character u20). The special values "E" (error), "L" (below detection limit) and "U" (above detection limit) can also be used in place of a decimal value. + + + + + + + + + + + + + + + + + + + + + + A reference from one resource to another. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources. + + + + + Plain text narrative that identifies the resource in addition to the resource reference. + + + + + + + + + A concept that may be defined by a formal reference to a terminology or ontology or may be provided by text. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + A reference to a code defined by a terminology system. + + + + + A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user. + + + + + + + + + A technical identifier - identifies some entity uniquely and unambiguously. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The purpose of this identifier. + + + + + A text string for the identifier that can be displayed to a human so they can recognize the identifier. + + + + + Establishes the namespace in which set of possible id values is unique. + + + + + The portion of the identifier typically displayed to the user and which is unique within the context of the system. + + + + + Time period during which identifier is/was valid for use. + + + + + Organization that issued/manages the identifier. + + + + + + + + + + + the identifier recommended for display and use in real-world interactions. + + + + + the identifier considered to be most trusted for the identification of this item. + + + + + A temporary identifier. + + + + + An identifier that was assigned in secondary use - it serves to identify the object in a relative context, but cannot be consistently assigned to the same object again in a different context. + + + + + + + Identifies the purpose for this identifier, if known + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + The value of the measured amount. The value includes an implicit precision in the presentation of the value. + + + + + How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is "<" , then the real value is < stated value. + + + + + A human-readable form of the units. + + + + + The identification of the system that provides the coded form of the unit. + + + + + A computer processable form of the units in some unit representation system. + + + + + + + + + + + + + + The value of the measured amount. The value includes an implicit precision in the presentation of the value. + + + + + How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is "<" , then the real value is < stated value. + + + + + A human-readable form of the units. + + + + + The identification of the system that provides the coded form of the unit. + + + + + A computer processable form of the units in some unit representation system. + + + + + + + + + + + + + + The value of the measured amount. The value includes an implicit precision in the presentation of the value. + + + + + How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is "<" , then the real value is < stated value. + + + + + A human-readable form of the units. + + + + + The identification of the system that provides the coded form of the unit. + + + + + A computer processable form of the units in some unit representation system. + + + + + + + + + + + + + + The value of the measured amount. The value includes an implicit precision in the presentation of the value. + + + + + How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is "<" , then the real value is < stated value. + + + + + A human-readable form of the units. + + + + + The identification of the system that provides the coded form of the unit. + + + + + A computer processable form of the units in some unit representation system. + + + + + + + + + + + + + + The value of the measured amount. The value includes an implicit precision in the presentation of the value. + + + + + How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is "<" , then the real value is < stated value. + + + + + A human-readable form of the units. + + + + + The identification of the system that provides the coded form of the unit. + + + + + A computer processable form of the units in some unit representation system. + + + + + + + + + + Specifies an event that may occur multiple times. Schedules are used for to reord when things are expected or requested to occur. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + Identifies specific time periods when the event should occur. + + + + + Identifies a repeating pattern to the intended time periods. + + + + + + + + + Specifies an event that may occur multiple times. Schedules are used for to reord when things are expected or requested to occur. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + Indicates how often the event should occur. + + + + + Identifies the occurrence of daily life that determines timing. + + + + + How long each repetition should last. + + + + + The units of time for the duration. + + + + + A total count of the desired number of repetitions. + + + + + When to stop repeating the schedule. + + + + + + + + + + + event occurs [duration] before the hour of sleep (or trying to). + + + + + event occurs [duration] after waking. + + + + + event occurs [duration] before a meal (from the Latin ante cibus). + + + + + event occurs [duration] before breakfast (from the Latin ante cibus matutinus). + + + + + event occurs [duration] before lunch (from the Latin ante cibus diurnus). + + + + + event occurs [duration] before dinner (from the Latin ante cibus vespertinus). + + + + + event occurs [duration] after a meal (from the Latin post cibus). + + + + + event occurs [duration] after breakfast (from the Latin post cibus matutinus). + + + + + event occurs [duration] after lunch (from the Latin post cibus diurnus). + + + + + event occurs [duration] after dinner (from the Latin post cibus vespertinus). + + + + + + + Real world event that the schedule relates to + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + second. + + + + + minute. + + + + + hour. + + + + + day. + + + + + week. + + + + + month. + + + + + year. + + + + + + + A unit of time (units from UCUM) + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + All kinds of technology mediated contact details for a person or organization, including telephone, email, etc. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + Telecommunications form for contact - what communications system is required to make use of the contact. + + + + + The actual contact details, in a form that is meaningful to the designated communication system (i.e. phone number or email address). + + + + + Identifies the purpose for the address. + + + + + Time period when the contact was/is in use. + + + + + + + + + + + The value is a telephone number used for voice calls. Use of full international numbers starting with + is recommended to enable automatic dialing support but not required. + + + + + The value is a fax machine. Use of full international numbers starting with + is recommended to enable automatic dialing support but not required. + + + + + The value is an email address. + + + + + The value is a url. This is intended for various personal contacts including blogs, Twitter, Facebook, etc. Do not use for email addresses. + + + + + + + Telecommunications form for contact + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + A communication contact at a home; attempted contacts for business purposes might intrude privacy and chances are one will contact family or other household members instead of the person one wishes to call. Typically used with urgent cases, or if no other contacts are available. + + + + + An office contact. First choice for business related contacts during business hours. + + + + + A temporary contact. The period can provide more detailed information. + + + + + This contact is no longer in use (or was never correct, but retained for records). + + + + + A telecommunication device that moves and stays with its owner. May have characteristics of all other use codes, suitable for urgent matters, not the first choice for routine business. + + + + + + + Location, type or status of telecommunications address indicating use + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + There is a variety of postal address formats defined around the world. This format defines a superset that is the basis for all addresses around the world. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + The purpose of this address. + + + + + A full text representation of the address. + + + + + This component contains the house number, apartment number, street name, street direction, +P.O. Box number, delivery hints, and similar address information. + + + + + The name of the city, town, village or other community or delivery center. + + + + + Sub-unit of a country with limited sovereignty in a federally organized country. A code may be used if codes are in common use (i.e. US 2 letter state codes). + + + + + A postal code designating a region defined by the postal service. + + + + + Country - a nation as commonly understood or generally accepted. + + + + + Time period when address was/is in use. + + + + + + + + + + + A communication address at a home. + + + + + An office address. First choice for business related contacts during business hours. + + + + + A temporary address. The period can provide more detailed information. + + + + + This address is no longer in use (or was never correct, but retained for records). + + + + + + + The use of an address + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A human's name with the ability to identify parts and usage. + If the element is present, it must have a value for at least one of the defined elements, an @id referenced from the Narrative, or extensions + + + + + + + Identifies the purpose for this name. + + + + + A full text representation of the name. + + + + + The part of a name that links to the genealogy. In some cultures (e.g. Eritrea) the family name of a son is the first name of his father. + + + + + Given name. + + + + + Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the start of the name. + + + + + Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the end of the name. + + + + + Indicates the period of time when this name was valid for the named person. + + + + + + + + + + + Known as/conventional/the one you normally use. + + + + + The formal name as registered in an official (government) registry, but which name might not be commonly used. May be called "legal name". + + + + + A temporary name. Name.period can provide more detailed information. This may also be used for temporary names assigned at birth or in emergency situations. + + + + + A name that is used to address the person in an informal manner, but is not part of their formal or usual name. + + + + + Anonymous assigned name, alias, or pseudonym (used to protect a person's identity for privacy reasons). + + + + + This name is no longer in use (or was never correct, but retained for records). + + + + + A name used prior to marriage. Marriage naming customs vary greatly around the world. This name use is for use by applications that collect and store "maiden" names. Though the concept of maiden name is often gender specific, the use of this term is not gender specific. The use of this term does not imply any particular history for a person's name, nor should the maiden name be determined algorithmically. + + + + + + + The use of a human name + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + This is the current reference for this document. + + + + + This reference has been superseded by another reference. + + + + + This reference was created in error. + + + + + + + + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Search parameter SHALL be a number (a whole number, or a decimal). + + + + + Search parameter is on a date/time. The date format is the standard XML format, though other formats may be supported. + + + + + Search parameter is a simple string, like a name part. Search is case-insensitive and accent-insensitive. May match just the start of a string. String parameters may contain spaces. + + + + + Search parameter on a coded element or identifier. May be used to search through the text, displayname, code and code/codesystem (for codes) and label, system and key (for identifier). Its value is either a string or a pair of namespace and value, separated by a "|", depending on the modifier used. + + + + + A reference to another resource. + + + + + A composite search parameter that combines a search on two values together. + + + + + A search parameter that searches on a quantity. + + + + + + + + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + This valueset is still under development. + + + + + This valueset is ready for normal use. + + + + + This valueset has been withdrawn or superceded and should no longer be used. + + + + + + + + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + + + + + + + + + + + + + Records an unexpected reaction suspected to be related to the exposure of the reaction subject to a substance. + + + + + Records an unexpected reaction suspected to be related to the exposure of the reaction subject to a substance. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + This records identifiers associated with this reaction that are defined by business processed and/ or used to refer to it when a direct URL reference to the resource itself is not appropriate (e.g. in CDA documents, or in written / printed documentation). + + + + + The date (and possibly time) when the reaction began. + + + + + The subject of the adverse reaction. + + + + + If true, indicates that no reaction occurred. + + + + + Identifies the individual responsible for the information in the reaction record. + + + + + The signs and symptoms that were observed as part of the reaction. + + + + + An exposure to a substance that preceded a reaction occurrence. + + + + + + + + + Records an unexpected reaction suspected to be related to the exposure of the reaction subject to a substance. + + + + + + + Indicates the specific sign or symptom that was observed. + + + + + The severity of the sign or symptom. + + + + + + + + + Records an unexpected reaction suspected to be related to the exposure of the reaction subject to a substance. + + + + + + + Identifies the initial date of the exposure that is suspected to be related to the reaction. + + + + + The type of exposure: Drug Administration, Immunization, Coincidental. + + + + + A statement of how confident that the recorder was that this exposure caused the reaction. + + + + + Substance that is presumed to have caused the adverse reaction. + + + + + + + + + + + Severe complications arose due to the reaction. + + + + + Serious inconvenience to the subject. + + + + + Moderate inconvenience to the subject. + + + + + Minor inconvenience to the subject. + + + + + + + The severity of an adverse reaction. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Drug Administration. + + + + + Immunization. + + + + + In the same area as the substance. + + + + + + + The type of exposure that resulted in an adverse reaction + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Likely that this specific exposure caused the reaction. + + + + + Unlikely that this specific exposure caused the reaction - the exposure is being linked to for information purposes. + + + + + It has been confirmed that this exposure was one of the causes of the reaction. + + + + + It is unknown whether this exposure had anything to do with the reaction. + + + + + + + How likely is it that the given exposure caused a reaction + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Prospective warnings of potential issues when providing care to the patient. + + + + + Prospective warnings of potential issues when providing care to the patient. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifier assigned to the alert for external use (outside the FHIR environment). + + + + + Allows an alert to be divided into different categories like clinical, administrative etc. + + + + + Supports basic workflow. + + + + + The person who this alert concerns. + + + + + The person or device that created the alert. + + + + + The textual component of the alert to display to the user. + + + + + + + + + + + A current alert that should be displayed to a user. A system may use the category to determine which roles should view the alert. + + + + + The alert does not need to be displayed any more. + + + + + The alert was added in error, and should no longer be displayed. + + + + + + + Indicates whether this alert is active and needs to be displayed to a user, or whether it is no longer needed or entered in error + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Indicates the patient has a susceptibility to an adverse reaction upon exposure to a specified substance. + + + + + Indicates the patient has a susceptibility to an adverse reaction upon exposure to a specified substance. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + This records identifiers associated with this allergy/intolerance concern that are defined by business processed and/ or used to refer to it when a direct URL reference to the resource itself is not appropriate (e.g. in CDA documents, or in written / printed documentation). + + + + + Criticality of the sensitivity. + + + + + Type of the sensitivity. + + + + + Date when the sensitivity was recorded. + + + + + Status of the sensitivity. + + + + + The patient who has the allergy or intolerance. + + + + + Indicates who has responsibility for the record. + + + + + The substance that causes the sensitivity. + + + + + Reactions associated with the sensitivity. + + + + + Observations that confirm or refute the sensitivity. + + + + + + + + + + + A suspected sensitivity to a substance. + + + + + The sensitivity has been confirmed and is active. + + + + + The sensitivity has been shown to never have existed. + + + + + The sensitivity used to exist but no longer does. + + + + + + + The status of the adverse sensitivity + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Likely to result in death if re-exposed. + + + + + Likely to result in reactions that will need to be treated if re-exposed. + + + + + Likely to result in reactions that will inconvenience the subject. + + + + + Not likely to result in any inconveniences for the subject. + + + + + + + The criticality of an adverse sensitivity + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Allergic Reaction. + + + + + Non-Allergic Reaction. + + + + + Unknown type. + + + + + + + The type of an adverse sensitivity + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Describes the intention of how one or more practitioners intend to deliver care for a particular patient for a period of time, possibly limited to care for a specific condition or set of conditions. + + + + + Describes the intention of how one or more practitioners intend to deliver care for a particular patient for a period of time, possibly limited to care for a specific condition or set of conditions. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + This records identifiers associated with this care plan that are defined by business processed and/ or used to refer to it when a direct URL reference to the resource itself is not appropriate (e.g. in CDA documents, or in written / printed documentation). + + + + + Identifies the patient/subject whose intended care is described by the plan. + + + + + Indicates whether the plan is currently being acted upon, represents future intentions or is now just historical record. + + + + + Indicates when the plan did (or is intended to) come into effect and end. + + + + + Identifies the most recent date on which the plan has been revised. + + + + + Identifies the conditions/problems/concerns/diagnoses/etc. whose management and/or mitigation are handled by this plan. + + + + + Identifies all people and organizations who are expected to be involved in the care envisioned by this plan. + + + + + Describes the intended objective(s) of carrying out the Care Plan. + + + + + Identifies a planned action to occur as part of the plan. For example, a medication to be used, lab tests to perform, self-monitoring, education, etc. + + + + + General notes about the care plan not covered elsewhere. + + + + + + + + + Describes the intention of how one or more practitioners intend to deliver care for a particular patient for a period of time, possibly limited to care for a specific condition or set of conditions. + + + + + + + Indicates specific responsibility of an individual within the care plan. E.g. "Primary physician", "Team coordinator", "Caregiver", etc. + + + + + The specific person or organization who is participating/expected to participate in the care plan. + + + + + + + + + Describes the intention of how one or more practitioners intend to deliver care for a particular patient for a period of time, possibly limited to care for a specific condition or set of conditions. + + + + + + + Human-readable description of a specific desired objective of the care plan. + + + + + Indicates whether the goal has been reached and is still considered relevant. + + + + + Any comments related to the goal. + + + + + The identified conditions that this goal relates to - the condition that caused it to be created, or that it is intended to address. + + + + + + + + + Describes the intention of how one or more practitioners intend to deliver care for a particular patient for a period of time, possibly limited to care for a specific condition or set of conditions. + + + + + + + Internal reference that identifies the goals that this activity is intended to contribute towards meeting. + + + + + Identifies what progress is being made for the specific activity. + + + + + If true, indicates that the described activity is one that must NOT be engaged in when following the plan. + + + + + Resources that describe follow-on actions resulting from the plan, such as drug prescriptions, encounter records, appointments, etc. + + + + + Notes about the execution of the activity. + + + + + The details of the proposed activity represented in a specific resource. + + + + + A simple summary of details suitable for a general care plan system (e.g. form driven) that doesn't know about specific resources such as procedure etc. + + + + + + + + + Describes the intention of how one or more practitioners intend to deliver care for a particular patient for a period of time, possibly limited to care for a specific condition or set of conditions. + + + + + + + High-level categorization of the type of activity in a care plan. + + + + + Detailed description of the type of activity. E.g. What lab test, what procedure, what kind of encounter. + + + + + The period, timing or frequency upon which the described activity is to occur. + + + + + + + + Identifies the facility where the activity will occur. E.g. home, hospital, specific clinic, etc. + + + + + Identifies who's expected to be involved in the activity. + + + + + Identifies the food, drug or other product being consumed or supplied in the activity. + + + + + Identifies the quantity expected to be consumed in a given day. + + + + + Identifies the quantity expected to be supplied. + + + + + This provides a textual description of constraints on the activity occurrence, including relation to other activities. It may also include objectives, pre-conditions and end-conditions. Finally, it may convey specifics about the activity such as body site, method, route, etc. + + + + + + + + + + + The plan is in development or awaiting use but is not yet intended to be acted upon. + + + + + The plan is intended to be followed and used as part of patient care. + + + + + The plan is no longer in use and is not expected to be followed or used in patient care. + + + + + + + Indicates whether the plan is currently being acted upon, represents future intentions or is now just historical record. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Plan for the patient to consume food of a specified nature. + + + + + Plan for the patient to consume/receive a drug, vaccine or other product. + + + + + Plan to meet or communicate with the patient (in-patient, out-patient, phone call, etc.). + + + + + Plan to capture information about a patient (vitals, labs, diagnostic images, etc.). + + + + + Plan to modify the patient in some way (surgery, physiotherapy, education, counseling, etc.). + + + + + Plan to provide something to the patient (medication, medical supply, etc.). + + + + + Some other form of action. + + + + + + + High-level categorization of the type of activity in a care plan. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The goal is being sought but has not yet been reached. (Also applies if goal was reached in the past but there has been regression and goal is being sought again). + + + + + The goal has been met and no further action is needed. + + + + + The goal has been met, but ongoing activity is needed to sustain the goal objective. + + + + + The goal is no longer being sought. + + + + + + + Indicates whether the goal has been met and is still being targeted + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Activity is planned but no action has yet been taken. + + + + + Appointment or other booking has occurred but activity has not yet begun. + + + + + Activity has been started but is not yet complete. + + + + + Activity was started but has temporarily ceased with an expectation of resumption at a future time. + + + + + The activities have been completed (more or less) as planned. + + + + + The activities have been ended prior to completion (perhaps even before they were started). + + + + + + + Indicates where the activity is at in its overall life cycle + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A set of healthcare-related information that is assembled together into a single logical document that provides a single coherent statement of meaning, establishes its own context and that has clinical attestation with regard to who is making the statement. + + + + + A set of healthcare-related information that is assembled together into a single logical document that provides a single coherent statement of meaning, establishes its own context and that has clinical attestation with regard to who is making the statement. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Logical Identifier for the composition, assigned when created. This identifier stays constant as the composition is changed over time. + + + + + The composition editing time, when the composition was last logically changed by the author. + + + + + Specifies the particular kind of composition (e.g. History and Physical, Discharge Summary, Progress Note). This usually equates to the purpose of making the composition. + + + + + A categorization for the type of the composition. This may be implied by or derived from the code specified in the Composition Type. + + + + + Official human-readable label for the composition. + + + + + The workflow/clinical status of this composition. The status is a marker for the clinical standing of the document. + + + + + The code specifying the level of confidentiality of the Composition. + + + + + Who or what the composition is about. The composition can be about a person, (patient or healthcare practitioner), a device (I.e. machine) or even a group of subjects (such as a document about a herd of livestock, or a set of patients that share a common exposure). + + + + + Identifies who is responsible for the information in the composition. (Not necessarily who typed it in.). + + + + + A participant who has attested to the accuracy of the composition/document. + + + + + Identifies the organization or group who is responsible for ongoing maintenance of and access to the composition/document information. + + + + + The main event/act/item, such as a colonoscopy or an appendectomy, being documented. + + + + + Describes the clinical encounter or type of care this documentation is associated with. + + + + + The root of the sections that make up the composition. + + + + + + + + + A set of healthcare-related information that is assembled together into a single logical document that provides a single coherent statement of meaning, establishes its own context and that has clinical attestation with regard to who is making the statement. + + + + + + + The type of attestation the authenticator offers. + + + + + When composition was attested by the party. + + + + + Who attested the composition in the specified way. + + + + + + + + + A set of healthcare-related information that is assembled together into a single logical document that provides a single coherent statement of meaning, establishes its own context and that has clinical attestation with regard to who is making the statement. + + + + + + + This list of codes represents the main clinical acts, such as a colonoscopy or an appendectomy, being documented. In some cases, the event is inherent in the typeCode, such as a "History and Physical Report" in which the procedure being documented is necessarily a "History and Physical" act. + + + + + The period of time covered by the documentation. There is no assertion that the documentation is a complete representation for this period, only that it documents events during this time. + + + + + Full details for the event(s) the composition/documentation consents. + + + + + + + + + A set of healthcare-related information that is assembled together into a single logical document that provides a single coherent statement of meaning, establishes its own context and that has clinical attestation with regard to who is making the statement. + + + + + + + The heading for this particular section. This will be part of the rendered content for the document. + + + + + A code identifying the kind of content contained within the section. + + + + + Identifies the primary subject of the section. + + + + + Identifies the discrete data that provides the content for the section. + + + + + A nested sub-section within this section. + + + + + + + + + + + This is a preliminary composition or document (also known as initial or interim). The content may be incomplete or unverified. + + + + + The composition or document is complete and verified by an appropriate person, and no further work is planned. + + + + + The composition or document has been modified subsequent to being released as "final", and is complete and verified by an authorized person. The modifications added new information to the composition or document, but did not revise existing content. + + + + + The composition or document has been modified subsequent to being released as "final", and is complete and verified by an authorized person. + + + + + The composition or document was originally created/issued in error, and this is an amendment that marks that the entire series should not be considered as valid. + + + + + + + The workflow/clinical status of the composition + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The person authenticated the content in their personal capacity. + + + + + The person authenticated the content in their professional capacity. + + + + + The person authenticated the content and accepted legal responsibility for its content. + + + + + The organization authenticated the content as consistent with their policies and procedures. + + + + + + + The way in which a person authenticated a composition + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A statement of relationships from one set of concepts to one or more other concept systems. + + + + + A statement of relationships from one set of concepts to one or more other concept systems. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The identifier that is used to identify this concept map when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI). + + + + + The identifier that is used to identify this version of the concept map when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp. + + + + + A free text natural language name describing the concept map. + + + + + The name of the individual or organization that published the concept map. + + + + + Contacts of the publisher to assist a user in finding and communicating with the publisher. + + + + + A free text natural language description of the use of the concept map - reason for definition, conditions of use, etc. + + + + + A copyright statement relating to the concept map and/or its contents. + + + + + The status of the concept map. + + + + + This ConceptMap was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage. + + + + + The date that the concept map status was last changed. + + + + + The source value set that specifies the concepts that are being mapped. + + + + + The target value set provides context to the mappings. Note that the mapping is made between concepts, not between value sets, but the value set provides important context about how the concept mapping choices are made. + + + + + Mappings for a concept from the source valueset. + + + + + + + + + A statement of relationships from one set of concepts to one or more other concept systems. + + + + + + + System that defines the concept being mapped. + + + + + Identifies concept being mapped. + + + + + A set of additional dependencies for this mapping to hold. This mapping is only applicable if the specified concept can be resolved, and it has the specified value. + + + + + A concept from the target value set that this concept maps to. + + + + + + + + + A statement of relationships from one set of concepts to one or more other concept systems. + + + + + + + A reference to a specific concept that holds a coded value. This can be an element in a FHIR resource, or a specific reference to a data element in a different specification (e.g. v2) or a general reference to a kind of data field, or a reference to a value set with an appropriately narrow definition. + + + + + System for a concept in the referenced concept. + + + + + Code for a concept in the referenced concept. + + + + + + + + + A statement of relationships from one set of concepts to one or more other concept systems. + + + + + + + System of the target. + + + + + Code that identifies the target concept. + + + + + equal | equivalent | wider | subsumes | narrower | specialises | inexact | unmatched | disjoint. + + + + + Description of status/issues in mapping. + + + + + A set of additional outcomes from this mapping to other value sets. To properly execute this mapping, the specified value set must be mapped to some data element or source that is in context. The mapping may still be useful without a place for the additional data elements, but the equivalence cannot be relied on. + + + + + + + + + + + The definitions of the concepts are exactly the same (i.e. only grammatical differences) and structural implications of meaning are identifical or irrelevant (i.e. intensionally identical). + + + + + The definitions of the concepts mean the same thing (including when structural implications of meaning are considered) (i.e. extensionally identical). + + + + + The target mapping is wider in meaning than the source concept. + + + + + The target mapping subsumes the meaning of the source concept (e.g. the source is-a target). + + + + + The target mapping is narrower in meaning that the source concept. The sense in which the mapping is narrower SHALL be described in the comments in this case, and applications should be careful when atempting to use these mappings operationally. + + + + + The target mapping specialises the meaning of the source concept (e.g. the target is-a source). + + + + + The target mapping overlaps with the source concept, but both source and target cover additional meaning. The sense in which the mapping is narrower SHALL be described in the comments in this case, and applications should be careful when atempting to use these mappings operationally. + + + + + There is no match for this concept in the destination concept system. + + + + + This is an explicit assertion that there is no mapping between the source and target concept. + + + + + + + The degree of equivalence between concepts + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Use to record detailed information about conditions, problems or diagnoses recognized by a clinician. There are many uses including: recording a Diagnosis during an Encounter; populating a problem List or a Summary Statement, such as a Discharge Summary. + + + + + Use to record detailed information about conditions, problems or diagnoses recognized by a clinician. There are many uses including: recording a Diagnosis during an Encounter; populating a problem List or a Summary Statement, such as a Discharge Summary. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + This records identifiers associated with this condition that are defined by business processed and/ or used to refer to it when a direct URL reference to the resource itself is not appropriate (e.g. in CDA documents, or in written / printed documentation). + + + + + Indicates the patient who the condition record is associated with. + + + + + Encounter during which the condition was first asserted. + + + + + Person who takes responsibility for asserting the existence of the condition as part of the electronic record. + + + + + Estimated or actual date the condition/problem/diagnosis was first detected/suspected. + + + + + Identification of the condition, problem or diagnosis. + + + + + A category assigned to the condition. E.g. complaint | symptom | finding | diagnosis. + + + + + The clinical status of the condition. + + + + + The degree of confidence that this condition is correct. + + + + + A subjective assessment of the severity of the condition as evaluated by the clinician. + + + + + Estimated or actual date the condition began, in the opinion of the clinician. + + + + + + + The date or estimated date that the condition resolved or went into remission. This is called "abatement" because of the many overloaded connotations associated with "remission" or "resolution" - Conditions are never really resolved, but they can abate. + + + + + + + + Clinical stage or grade of a condition. May include formal severity assessments. + + + + + Supporting Evidence / manifestations that are the basis on which this condition is suspected or confirmed. + + + + + The anatomical location where this condition manifests itself. + + + + + Further conditions, problems, diagnoses, procedures or events that are related in some way to this condition, or the substance that caused/triggered this Condition. + + + + + Additional information about the Condition. This is a general notes/comments entry for description of the Condition, its diagnosis and prognosis. + + + + + + + + + Use to record detailed information about conditions, problems or diagnoses recognized by a clinician. There are many uses including: recording a Diagnosis during an Encounter; populating a problem List or a Summary Statement, such as a Discharge Summary. + + + + + + + A simple summary of the stage such as "Stage 3". The determination of the stage is disease-specific. + + + + + Reference to a formal record of the evidence on which the staging assessment is based. + + + + + + + + + Use to record detailed information about conditions, problems or diagnoses recognized by a clinician. There are many uses including: recording a Diagnosis during an Encounter; populating a problem List or a Summary Statement, such as a Discharge Summary. + + + + + + + A manifestation or symptom that led to the recording of this condition. + + + + + Links to other relevant information, including pathology reports. + + + + + + + + + Use to record detailed information about conditions, problems or diagnoses recognized by a clinician. There are many uses including: recording a Diagnosis during an Encounter; populating a problem List or a Summary Statement, such as a Discharge Summary. + + + + + + + Code that identifies the structural location. + + + + + Detailed anatomical location information. + + + + + + + + + Use to record detailed information about conditions, problems or diagnoses recognized by a clinician. There are many uses including: recording a Diagnosis during an Encounter; populating a problem List or a Summary Statement, such as a Discharge Summary. + + + + + + + The type of relationship that this condition has to the related item. + + + + + Code that identifies the target of this relationship. The code takes the place of a detailed instance target. + + + + + Target of the relationship. + + + + + + + + + + + This is a tentative diagnosis - still a candidate that is under consideration. + + + + + The patient is being treated on the basis that this is the condition, but it is still not confirmed. + + + + + There is sufficient diagnostic and/or clinical evidence to treat this as a confirmed condition. + + + + + This condition has been ruled out by diagnostic and clinical evidence. + + + + + + + The clinical status of the Condition or diagnosis + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + this condition follows the identified condition/procedure/substance and is a consequence of it. + + + + + this condition follows the identified condition/procedure/substance, but it is not known whether they are causually linked. + + + + + + + The type of relationship between a condition and its related item + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The identifier that is used to identify this conformance statement when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI). + + + + + The identifier that is used to identify this version of the conformance statement when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp. + + + + + A free text natural language name identifying the conformance statement. + + + + + Name of Organization publishing this conformance statement. + + + + + Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc. + + + + + A free text natural language description of the conformance statement and its use. Typically, this is used when the profile describes a desired rather than an actual solution, for example as a formal expression of requirements as part of an RFP. + + + + + The status of this conformance statement. + + + + + A flag to indicate that this conformance statement is authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage. + + + + + The date when the conformance statement was published. + + + + + Software that is covered by this conformance statement. It is used when the profile describes the capabilities of a particular software version, independent of an installation. + + + + + Identifies a specific implementation instance that is described by the conformance statement - i.e. a particular installation, rather than the capabilities of a software program. + + + + + The version of the FHIR specification on which this conformance statement is based. + + + + + A flag that indicates whether the application accepts unknown elements as part of a resource. + + + + + A list of the formats supported by this implementation. + + + + + A list of profiles supported by the system. For a server, "supported by the system" means the system hosts/produces a set of recourses, conformant to a particular profile, and allows its clients to search using this profile and to find appropriate data. For a client, it means the system will search by this profile and process data according to the guidance implicit in the profile. + + + + + A definition of the restful capabilities of the solution, if any. + + + + + A description of the messaging capabilities of the solution. + + + + + A document definition. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + Name software is known by. + + + + + The version identifier for the software covered by this statement. + + + + + Date this version of the software released. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + Information about the specific installation that this conformance statement relates to. + + + + + A base URL for the implementation. This forms the base for REST interfaces as well as the mailbox and document interfaces. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + Identifies whether this portion of the statement is describing ability to initiate or receive restful operations. + + + + + Information about the system's restful capabilities that apply across all applications, such as security. + + + + + Information about security of implementation. + + + + + A specification of the restful capabilities of the solution for a specific resource type. + + + + + A specification of restful operations supported by the system. + + + + + Definition of a named query and its parameters and their meaning. + + + + + A list of profiles that this server implements for accepting documents in the mailbox. If this list is empty, then documents are not accepted. The base specification has the profile identifier "http://hl7.org/fhir/documents/mailbox". Other specifications can declare their own identifier for this purpose. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + Server adds CORS headers when responding to requests - this enables javascript applications to yuse the server. + + + + + Types of security services are supported/required by the system. + + + + + General description of how security works. + + + + + Certificates associated with security profiles. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + Mime type for certificate. + + + + + Actual certificate. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + A type of resource exposed via the restful interface. + + + + + A specification of the profile that describes the solution's support for the resource, including any constraints on cardinality, bindings, lengths or other limitations. + + + + + Identifies a restful operation supported by the solution. + + + + + A flag for whether the server is able to return past versions as part of the vRead operation. + + + + + A flag to indicate that the server allows the client to create new identities on the server. If the update operation is used (client) or allowed (server) to a new location where a resource doesn't already exist. This means that the server allows the client to create new identities on the server. + + + + + A list of _include values supported by the server. + + + + + Additional search parameters for implementations to support and/or make use of. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + Coded identifier of the operation, supported by the system resource. + + + + + Guidance specific to the implementation of this operation, such as 'delete is a logical delete' or 'updates are only allowed with version id' or 'creates permitted from pre-authorized certificates only'. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + The name of the search parameter used in the interface. + + + + + A formal reference to where this parameter was first defined, so that a client can be confident of the meaning of the search parameter. + + + + + The type of value a search parameter refers to, and how the content is interpreted. + + + + + This allows documentation of any distinct behaviors about how the search parameter is used. For example, text matching algorithms. + + + + + Types of resource (if a resource is referenced). + + + + + Chained names supported. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + A coded identifier of the operation, supported by the system. + + + + + Guidance specific to the implementation of this operation, such as limitations on the kind of transactions allowed, or information about system wide search is implemented. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + The name of a query, which is used in the _query parameter when the query is called. + + + + + Identifies the custom query, defined either in FHIR core or another profile. + + + + + Additional information about how the query functions in this particular implementation. + + + + + Identifies which of the parameters for the named query are supported. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + An address to which messages and/or replies are to be sent. + + + + + Length if the receiver's reliable messaging cache (if a receiver) or how long the cache length on the receiver should be (if a sender). + + + + + Documentation about the system's messaging capabilities for this endpoint not otherwise documented by the conformance statement. For example, process for becoming an authorized messaging exchange partner. + + + + + A description of the solution's support for an event at this end point. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + A coded identifier of a supported messaging event. + + + + + The impact of the content of the message. + + + + + The mode of this event declaration - whether application is sender or receiver. + + + + + A list of the messaging transport protocol(s) identifiers, supported by this endpoint. + + + + + A resource associated with the event. This is the resource that defines the event. + + + + + Information about the request for this event. + + + + + Information about the response for this event. + + + + + Guidance on how this event is handled, such as internal system trigger points, business rules, etc. + + + + + + + + + A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation. + + + + + + + Mode of this document declaration - whether application is producer or consumer. + + + + + A description of how the application supports or uses the specified document profile. For example, when are documents created, what action is taken with consumed documents, etc. + + + + + A constraint on a resource used in the document. + + + + + + + + + + + The application produces documents of the specified type. + + + + + The application consumes documents of the specified type. + + + + + + + Whether the application produces or consumes documents + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The application acts as a server for this resource. + + + + + The application acts as a client for this resource. + + + + + + + The mode of a RESTful conformance statement + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The application sends requests and receives responses. + + + + + The application receives requests and sends responses. + + + + + + + The mode of a message conformance statement + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The message represents/requests a change that should not be processed more than once. E.g. Making a booking for an appointment. + + + + + The message represents a response to query for current information. Retrospective processing is wrong and/or wasteful. + + + + + The content is not necessarily intended to be current, and it can be reprocessed, though there may be version issues created by processing old notifications. + + + + + + + The impact of the content of a message + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Operations supported by REST at the type or instance level + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + This conformance statement is still under development. + + + + + This conformance statement is ready for use in production systems. + + + + + This conformance statement has been withdrawn or superceded and should no longer be used. + + + + + + + The status of this conformance statement + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Operations supported by REST at the system level + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + This resource identifies an instance of a manufactured thing that is used in the provision of healthcare without being substantially changed through that activity. The device may be a machine, an insert, a computer, an application, etc. This includes durable (reusable) medical equipment as well as disposable equipment used for diagnostic, treatment, and research for healthcare and public health. + + + + + This resource identifies an instance of a manufactured thing that is used in the provision of healthcare without being substantially changed through that activity. The device may be a machine, an insert, a computer, an application, etc. This includes durable (reusable) medical equipment as well as disposable equipment used for diagnostic, treatment, and research for healthcare and public health. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifiers assigned to this device by various organizations. The most likely organizations to assign identifiers are the manufacturer and the owner, though regulatory agencies may also assign an identifier. The identifiers identify the particular device, not the kind of device. + + + + + A kind of this device. + + + + + A name of the manufacturer. + + + + + The "model" - an identifier assigned by the manufacturer to identify the product by its type. This number is shared by the all devices sold as the same type. + + + + + The version of the device, if the device has multiple releases under the same model, or if the device is software or carries firmware. + + + + + Date of expiry of this device (if applicable). + + + + + FDA Mandated Unique Device Identifier. Use the human readable information (the content that the user sees, which is sometimes different to the exact syntax represented in the barcode) - see http://www.fda.gov/MedicalDevices/DeviceRegulationandGuidance/UniqueDeviceIdentification/default.htm. + + + + + Lot number assigned by the manufacturer. + + + + + An organization that is responsible for the provision and ongoing maintenance of the device. + + + + + The resource may be found in a literal location (i.e. GPS coordinates), a logical place (i.e. "in/with the patient"), or a coded location. + + + + + Patient information, if the resource is affixed to a person. + + + + + Contact details for an organization or a particular human that is responsible for the device. + + + + + A network address on which the device may be contacted directly. + + + + + + + + + Describes the data produced by a device at a point in time. + + + + + Describes the data produced by a device at a point in time. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The point in time that the values are reported. + + + + + An identifier assigned to this observation bu the source device that made the observation. + + + + + Identification information for the device that is the source of the data. + + + + + The subject of the measurement. + + + + + A medical-related subsystem of a medical device. + + + + + + + + + Describes the data produced by a device at a point in time. + + + + + + + Describes the compartment. + + + + + Groups together physiological measurement data and derived data. + + + + + + + + + Describes the data produced by a device at a point in time. + + + + + + + Describes the channel. + + + + + A piece of measured or derived data that is reported by the machine. + + + + + + + + + Describes the data produced by a device at a point in time. + + + + + + + The data for the metric. + + + + + + + + + A request for a diagnostic investigation service to be performed. + + + + + A request for a diagnostic investigation service to be performed. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Who or what the investigation is to be performed on. This is usually a human patient, but diagnostic tests can also be requested on animals, groups of humans or animals, devices such as dialysis machines, or even locations (typically for environmental scans). + + + + + The practitioner that holds legal responsibility for ordering the investigation. + + + + + Identifiers assigned to this order by the order or by the receiver. + + + + + An encounter that provides additional informaton about the healthcare context in which this request is made. + + + + + An explanation or justification for why this diagnostic investigation is being requested. + + + + + One or more specimens that the diagnostic investigation is about. + + + + + The status of the order. + + + + + The clinical priority associated with this order. + + + + + A summary of the events of interest that have occurred as the request is processed. E.g. when the order was made, various processing steps (specimens received), when it was completed. + + + + + The specific diagnostic investigations that are requested as part of this request. Sometimes, there can only be one item per request, but in most contexts, more than one investigation can be requested. + + + + + + + + + A request for a diagnostic investigation service to be performed. + + + + + + + The status for the event. + + + + + Additional information about the event that occurred - e.g. if the status remained unchanged. + + + + + The date/time at which the event occurred. + + + + + The person who was responsible for performing or recording the action. + + + + + + + + + A request for a diagnostic investigation service to be performed. + + + + + + + A code that identifies a particular diagnostic investigation, or panel of investigations, that have been requested. + + + + + If the item is related to a specific speciment. + + + + + Anatomical location where the request test should be performed. + + + + + The status of this individual item within the order. + + + + + A summary of the events of interest that have occurred as this item of the request is processed. + + + + + + + + + + + The request has been placed. + + + + + The receiving system has received the order, but not yet decided whether it will be performed. + + + + + The receiving system has accepted the order, but work has not yet commenced. + + + + + The work to fulfill the order is happening. + + + + + The work is complete, and the outcomes are being reviewed for approval. + + + + + The work has been complete, the report(s) released, and no further work is planned. + + + + + The request has been held by originating system/user request. + + + + + The receiving system has declined to fulfill the request. + + + + + The diagnostic investigation was attempted, but due to some procedural error, it could not be completed. + + + + + + + The status of a diagnostic order + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The order has a normal priority. + + + + + The order should be urgently. + + + + + The order is time-critical. + + + + + The order should be acted on as soon as possible. + + + + + + + The clinical priority of a diagnostic order + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + The findings and interpretation of diagnostic tests performed on patients, groups of patients, devices, and locations, and/or specimens derived from these. The report includes clinical context such as requesting and provider information, and some mix of atomic results, images, textual and coded interpretation, and formatted representation of diagnostic reports. + + + + + The findings and interpretation of diagnostic tests performed on patients, groups of patients, devices, and locations, and/or specimens derived from these. The report includes clinical context such as requesting and provider information, and some mix of atomic results, images, textual and coded interpretation, and formatted representation of diagnostic reports. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + A code or name that describes this diagnostic report. + + + + + The status of the diagnostic report as a whole. + + + + + The date and/or time that this version of the report was released from the source diagnostic service. + + + + + The subject of the report. Usually, but not always, this is a patient. However diagnostic services also perform analyses on specimens collected from a variety of other sources. + + + + + The diagnostic service that is responsible for issuing the report. + + + + + The local ID assigned to the report by the order filler, usually by the Information System of the diagnostic service provider. + + + + + Details concerning a test requested. + + + + + The section of the diagnostic service that performs the examination e.g. biochemistry, hematology, MRI. + + + + + The time or time-period the observed values are related to. This is usually either the time of the procedure or of specimen collection(s), but very often the source of the date/time is not known, only the date/time itself. + + + + + + + Details about the specimens on which this Disagnostic report is based. + + + + + Observations that are part of this diagnostic report. Observations can be simple name/value pairs (e.g. "atomic" results), or they can be grouping observations that include references to other members of the group (e.g. "panels"). + + + + + One or more links to full details of any imaging performed during the diagnostic investigation. Typically, this is imaging performed by DICOM enabled modalities, but this is not required. A fully enabled PACS viewer can use this information to provide views of the source images. + + + + + A list of key images associated with this report. The images are generally created during the diagnostic process, and may be directly of the patient, or of treated specimens (i.e. slides of interest). + + + + + Concise and clinically contextualized narrative interpretation of the diagnostic report. + + + + + Codes for the conclusion. + + + + + Rich text representation of the entire result as issued by the diagnostic service. Multiple formats are allowed but they SHALL be semantically equivalent. + + + + + + + + + The findings and interpretation of diagnostic tests performed on patients, groups of patients, devices, and locations, and/or specimens derived from these. The report includes clinical context such as requesting and provider information, and some mix of atomic results, images, textual and coded interpretation, and formatted representation of diagnostic reports. + + + + + + + A comment about the image. Typically, this is used to provide an explanation for why the image is included, or to draw the viewer's attention to important features. + + + + + Reference to the image source. + + + + + + + + + + + The existence of the report is registered, but there is nothing yet available. + + + + + This is a partial (e.g. initial, interim or preliminary) report: data in the report may be incomplete or unverified. + + + + + The report is complete and verified by an authorized person. + + + + + The report has been modified subsequent to being Final, and is complete and verified by an authorized person. + + + + + The report has been modified subsequent to being Final, and is complete and verified by an authorized person, and data has been changed. + + + + + The report has been modified subsequent to being Final, and is complete and verified by an authorized person. New content has been added, but existing content hasn't changed. + + + + + The report is unavailable because the measurement was not started or not completed (also sometimes called "aborted"). + + + + + The report has been withdrawn following previous Final release. + + + + + + + The status of the diagnostic report as a whole + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A manifest that defines a set of documents. + + + + + A manifest that defines a set of documents. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + A single identifier that uniquely identifies this manifest. Principally used to refer to the manifest in non-FHIR contexts. + + + + + Other identifiers associated with the document, including version independent, source record and workflow related identifiers. + + + + + Who or what the set of documents is about. The documents can be about a person, (patient or healthcare practitioner), a device (i.e. machine) or even a group of subjects (such as a document about a herd of farm animals, or a set of patients that share a common exposure). If the documents cross more than one subject, then more than one subject is allowed here (unusual use case). + + + + + A patient, practitioner, or organization for which this set of documents is intended. + + + + + Specifies the kind of this set of documents (e.g. Patient Summary, Discharge Summary, Prescription, etc.). The type of a set of documents may be the same as one of the documents in it - especially if there is only one - but it may be wider. + + + + + Identifies who is responsible for adding the information to the document. + + + + + When the document manifest was created for submission to the server (not necessarily the same thing as the actual resource last modified time, since it may be modified, replicated etc). + + + + + Identifies the source system, application, or software that produced the document manifest. + + + + + The status of this document manifest. + + + + + Whether this document manifest replaces another. + + + + + Human-readable description of the source document. This is sometimes known as the "title". + + + + + A code specifying the level of confidentiality of this set of Documents. + + + + + The list of resources that describe the parts of this document reference. Usually, these would be document references, but direct references to binary attachments and images are also allowed. + + + + + + + + + A reference to a document. + + + + + A reference to a document. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Document identifier as assigned by the source of the document. This identifier is specific to this version of the document. This unique identifier may be used elsewhere to identify this version of the document. + + + + + Other identifiers associated with the document, including version independent, source record and workflow related identifiers. + + + + + Who or what the document is about. The document can be about a person, (patient or healthcare practitioner), a device (I.e. machine) or even a group of subjects (such as a document about a herd of farm animals, or a set of patients that share a common exposure). + + + + + Specifies the particular kind of document (e.g. Patient Summary, Discharge Summary, Prescription, etc.). + + + + + A categorization for the type of the document. This may be implied by or derived from the code specified in the Document Type. + + + + + Identifies who is responsible for adding the information to the document. + + + + + Identifies the organization or group who is responsible for ongoing maintenance of and access to the document. + + + + + A reference to a domain or server that manages policies under which the document is accessed and/or made available. + + + + + Which person or organization authenticates that this document is valid. + + + + + When the document was created. + + + + + When the document reference was created. + + + + + The status of this document reference. + + + + + The status of the underlying document. + + + + + Relationships that this document has with other document references that already exist. + + + + + Human-readable description of the source document. This is sometimes known as the "title". + + + + + A code specifying the level of confidentiality of the XDS Document. + + + + + The primary language in which the source document is written. + + + + + The mime type of the source document. + + + + + An identifier that identifies that the format and content of the document conforms to additional rules beyond the base format indicated in the mimeType. + + + + + The size of the source document this reference refers to in bytes. + + + + + A hash of the source document to ensure that changes have not occurred. + + + + + A url at which the document can be accessed. + + + + + A description of a service call that can be used to retrieve the document. + + + + + The clinical context in which the document was prepared. + + + + + + + + + A reference to a document. + + + + + + + The type of relationship that this document has with anther document. + + + + + The target document of this relationship. + + + + + + + + + A reference to a document. + + + + + + + The type of the service that can be used to access the documents. + + + + + Where the service end-point is located. + + + + + A list of named parameters that is used in the service call. + + + + + + + + + A reference to a document. + + + + + + + The name of a parameter. + + + + + The value of the named parameter. + + + + + + + + + A reference to a document. + + + + + + + This list of codes represents the main clinical acts, such as a colonoscopy or an appendectomy, being documented. In some cases, the event is inherent in the typeCode, such as a "History and Physical Report" in which the procedure being documented is necessarily a "History and Physical" act. + + + + + The time period over which the service that is described by the document was provided. + + + + + The kind of facility where the patient was seen. + + + + + + + + + + + This document logically replaces or supercedes the target document. + + + + + This document was generated by transforming the target document (e.g. format or language conversion). + + + + + This document is a signature of the target document. + + + + + This document adds additional information to the target document. + + + + + + + The type of relationship between documents + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + An interaction between a patient and healthcare provider(s) for the purpose of providing healthcare service(s) or assessing the health status of a patient. + + + + + An interaction between a patient and healthcare provider(s) for the purpose of providing healthcare service(s) or assessing the health status of a patient. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifier(s) by which this encounter is known. + + + + + planned | in progress | onleave | finished | cancelled. + + + + + inpatient | outpatient | ambulatory | emergency +. + + + + + Specific type of encounter (e.g. e-mail consultation, surgical day-care, skilled nursing, rehabilitation). + + + + + The patient present at the encounter. + + + + + The main practitioner responsible for providing the service. + + + + + The start and end time of the encounter. + + + + + Quantity of time the encounter lasted. This excludes the time during leaves of absence. + + + + + Reason the encounter takes place, expressed as a code. For admissions, this can be used for a coded admission diagnosis. + + + + + Reason the encounter takes place, as specified using information from another resource. For admissions, this is the admission diagnosis. + + + + + Indicates the urgency of the encounter. + + + + + Details about an admission to a clinic. + + + + + List of locations at which the patient has been. + + + + + Department or team providing care. + + + + + Another Encounter of which this encounter is a part of (administratively or in time). + + + + + + + + + An interaction between a patient and healthcare provider(s) for the purpose of providing healthcare service(s) or assessing the health status of a patient. + + + + + + + Role of participant in encounter. + + + + + Persons involved in the encounter other than the patient. + + + + + + + + + An interaction between a patient and healthcare provider(s) for the purpose of providing healthcare service(s) or assessing the health status of a patient. + + + + + + + Pre-admission identifier. + + + + + The location from which the patient came before admission. + + + + + From where patient was admitted (physician referral, transfer). + + + + + Period during which the patient was admitted. + + + + + Where the patient stays during this encounter. + + + + + Dietary restrictions for the patient. + + + + + Special courtesies (VIP, board member). + + + + + Wheelchair, translator, stretcher, etc. + + + + + Location to which the patient is discharged. + + + + + Category or kind of location after discharge. + + + + + The final diagnosis given a patient before release from the hospital after all testing, surgery, and workup are complete. + + + + + Whether this hospitalization is a readmission. + + + + + + + + + An interaction between a patient and healthcare provider(s) for the purpose of providing healthcare service(s) or assessing the health status of a patient. + + + + + + + The bed that is assigned to the patient. + + + + + Period during which the patient was assigned the bed. + + + + + + + + + An interaction between a patient and healthcare provider(s) for the purpose of providing healthcare service(s) or assessing the health status of a patient. + + + + + + + The location where the encounter takes place. + + + + + Time period during which the patient was present at the location. + + + + + + + + + + + An encounter during which the patient is hospitalized and stays overnight. + + + + + An encounter during which the patient is not hospitalized overnight. + + + + + An encounter where the patient visits the practitioner in his/her office, e.g. a G.P. visit. + + + + + An encounter where the patient needs urgent care. + + + + + An encounter where the practitioner visits the patient at his/her home. + + + + + An encounter taking place outside the regular environment for giving care. + + + + + An encounter where the patient needs more prolonged treatment or investigations than outpatients, but who do not need to stay in the hospital overnight. + + + + + An encounter that takes place where the patient and practitioner do not physically meet but use electronic means for contact. + + + + + + + Classification of the encounter + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The Encounter has not yet started. + + + + + The Encounter has begun and the patient is present / the practitioner and the patient are meeting. + + + + + The Encounter has begun, but the patient is temporarily on leave. + + + + + The Encounter has ended. + + + + + The Encounter has ended before it has begun. + + + + + + + Current state of the encounter + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Significant health events and conditions for people related to the subject relevant in the context of care for the subject. + + + + + Significant health events and conditions for people related to the subject relevant in the context of care for the subject. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + This records identifiers associated with this family history record that are defined by business processes and/ or used to refer to it when a direct URL reference to the resource itself is not appropriate (e.g. in CDA documents, or in written / printed documentation). + + + + + The person who this history concerns. + + + + + Conveys information about family history not specific to individual relations. + + + + + The related person. Each FamilyHistory resource contains the entire family history for a single person. + + + + + + + + + Significant health events and conditions for people related to the subject relevant in the context of care for the subject. + + + + + + + This will either be a name or a description. E.g. "Aunt Susan", "my cousin with the red hair". + + + + + The type of relationship this person has to the patient (father, mother, brother etc.). + + + + + The actual or approximate date of birth of the relative. + + + + + + + + If this resource is indicating that the related person is deceased, then an indicator of whether the person is deceased (yes) or not (no) or the age or age range or description of age at death - can be indicated here. If the reason for death is known, then it can be indicated in the outcome code of the condition - in this case the deceased property should still be set. + + + + + + + + + + This property allows a non condition-specific note to the made about the related person. Ideally, the note would be in the condition property, but this is not always possible. + + + + + The significant Conditions (or condition) that the family member had. This is a repeating section to allow a system to represent more than one condition per resource, though there is nothing stopping multiple resources - one per condition. + + + + + + + + + Significant health events and conditions for people related to the subject relevant in the context of care for the subject. + + + + + + + The actual condition specified. Could be a coded condition (like MI or Diabetes) or a less specific string like 'cancer' depending on how much is known about the condition and the capabilities of the creating system. + + + + + Indicates what happened as a result of this condition. If the condition resulted in death, deceased date is captured on the relation. + + + + + Either the age of onset, range of approximate age or descriptive string can be recorded. For conditions with multiple occurrences, this describes the first known occurrence. + + + + + + + + An area where general notes can be placed about this specific condition. + + + + + + + + + Represents a defined collection of entities that may be discussed or acted upon collectively but which are not expected to act collectively and are not formally or legally recognized. I.e. A collection of entities that isn't an Organization. + + + + + Represents a defined collection of entities that may be discussed or acted upon collectively but which are not expected to act collectively and are not formally or legally recognized. I.e. A collection of entities that isn't an Organization. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + A unique business identifier for this group. + + + + + Identifies the broad classification of the kind of resources the group includes. + + + + + If true, indicates that the resource refers to a specific group of real individuals. If false, the group defines a set of intended individuals. + + + + + Provides a specific type of resource the group includes. E.g. "cow", "syringe", etc. + + + + + A label assigned to the group for human identification and communication. + + + + + A count of the number of resource instances that are part of the group. + + + + + Identifies the traits shared by members of the group. + + + + + Identifies the resource instances that are members of the group. + + + + + + + + + Represents a defined collection of entities that may be discussed or acted upon collectively but which are not expected to act collectively and are not formally or legally recognized. I.e. A collection of entities that isn't an Organization. + + + + + + + A code that identifies the kind of trait being asserted. + + + + + The value of the trait that holds (or does not hold - see 'exclude') for members of the group. + + + + + + + + + If true, indicates the characteristic is one that is NOT held by members of the group. + + + + + + + + + + + Group contains "person" Patient resources. + + + + + Group contains "animal" Patient resources. + + + + + Group contains healthcare practitioner resources. + + + + + Group contains Device resources. + + + + + Group contains Medication resources. + + + + + Group contains Substance resources. + + + + + + + Types of resources that are part of group + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Manifest of a set of images produced in study. The set of images may include every image in the study, or it may be an incomplete sample, such as a list of key images. + + + + + Manifest of a set of images produced in study. The set of images may include every image in the study, or it may be an incomplete sample, such as a list of key images. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Date and Time the study took place. + + + + + Who the images are of. + + + + + Formal identifier for the study. + + + + + Accession Number. + + + + + Other identifiers for the study. + + + + + A list of the diagnostic orders that resulted in this imaging study being performed. + + + + + A list of all the Series.ImageModality values that are actual acquisition modalities, i.e. those in the DICOM Context Group 29 (value set OID 1.2.840.10008.6.1.19). + + + + + The requesting/referring physician. + + + + + Availability of study (online, offline or nearline). + + + + + WADO-RS URI where Study is available. + + + + + Number of Series in Study. + + + + + Number of SOP Instances in Study. + + + + + Diagnoses etc provided with request. + + + + + Type of procedure performed. + + + + + Who read study and interpreted the images. + + + + + Institution-generated description or classification of the Study (component) performed. + + + + + Each study has one or more series of image instances. + + + + + + + + + Manifest of a set of images produced in study. The set of images may include every image in the study, or it may be an incomplete sample, such as a list of key images. + + + + + + + The number of this series in the overall sequence. + + + + + The modality of this series sequence. + + + + + Formal identifier for this series. + + + + + A description of the series. + + + + + Sequence that contains attributes from the. + + + + + Availability of series (online, offline or nearline). + + + + + WADO-RS URI where Series is available. + + + + + Body part examined. See DICOM Part 16 Annex L for the mapping from DICOM to Snomed. + + + + + When the series started. + + + + + A single image taken from a patient. + + + + + + + + + Manifest of a set of images produced in study. The set of images may include every image in the study, or it may be an incomplete sample, such as a list of key images. + + + + + + + The number of this image in the series. + + + + + Formal identifier for this image. + + + + + DICOM Image type. + + + + + Type of instance (image etc) (0004,1430). + + + + + Description (0070,0080 | 0040,A043 > 0008,0104 | 0042,0010 | 0008,0008). + + + + + WADO-RS url where image is available. + + + + + A FHIR resource with content for this instance. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Type of acquired image data in the instance + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Resources are immediately available,. + + + + + Resources need to be retrieved by manual intervention. + + + + + Resources need to be retrieved from relatively slow media. + + + + + Resources cannot be retrieved. + + + + + + + Availability of the resource + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Type of data in the instance + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Immunization event information. + + + + + Immunization event information. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + A unique identifier assigned to this adverse reaction record. + + + + + Date vaccine administered or was to be administered. + + + + + Vaccine that was administered or was to be administered. + + + + + The patient to whom the vaccine was to be administered. + + + + + Indicates if the vaccination was refused. + + + + + True if this administration was reported rather than directly administered. + + + + + Clinician who administered the vaccine. + + + + + Clinician who ordered the vaccination. + + + + + Name of vaccine manufacturer. + + + + + The service delivery location where the vaccine administration occurred. + + + + + Lot number of the vaccine product. + + + + + Date vaccine batch expires. + + + + + Body site where vaccine was administered. + + + + + The path by which the vaccine product is taken into the body. + + + + + The quantity of vaccine product that was administered. + + + + + Reasons why a vaccine was administered or refused. + + + + + Categorical data indicating that an adverse event is associated in time to an immunization. + + + + + Contains information about the protocol(s) under which the vaccine was administered. + + + + + + + + + Immunization event information. + + + + + + + Reasons why a vaccine was administered. + + + + + Refusal or exemption reasons. + + + + + + + + + Immunization event information. + + + + + + + Date of reaction to the immunization. + + + + + Details of the reaction. + + + + + Self-reported indicator. + + + + + + + + + Immunization event information. + + + + + + + Nominal position in a series. + + + + + Contains the description about the protocol under which the vaccine was administered. + + + + + Indicates the authority who published the protocol? E.g. ACIP. + + + + + One possible path to achieve presumed immunity against a disease - within the context of an authority. + + + + + The recommended number of doses to achieve immunity. + + + + + The targeted disease. + + + + + Indicates if the immunization event should "count" against the protocol. + + + + + Provides an explanation as to why a immunization event should or should not count against the protocol. + + + + + + + + + A patient's point-of-time immunization status and recommendation with optional supporting justification. + + + + + A patient's point-of-time immunization status and recommendation with optional supporting justification. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + A unique identifier assigned to this particular recommendation record. + + + + + The patient who is the subject of the profile. + + + + + Vaccine administration recommendations. + + + + + + + + + A patient's point-of-time immunization status and recommendation with optional supporting justification. + + + + + + + The date the immunization recommendation was created. + + + + + Vaccine that pertains to the recommendation. + + + + + This indicates the next recommended dose number (e.g. dose 2 is the next recommended dose). + + + + + Vaccine administration status. + + + + + Vaccine date recommendations - e.g. earliest date to administer, latest date to administer, etc. + + + + + Contains information about the protocol under which the vaccine was administered. + + + + + Immunization event history that supports the status and recommendation. + + + + + Patient Information that supports the status and recommendation. This includes patient observations, adverse reactions and allergy/intolerance information. + + + + + + + + + A patient's point-of-time immunization status and recommendation with optional supporting justification. + + + + + + + Date classification of recommendation - e.g. earliest date to give, latest date to give, etc. + + + + + Date recommendation. + + + + + + + + + A patient's point-of-time immunization status and recommendation with optional supporting justification. + + + + + + + Indicates the nominal position in a series of the next dose. This is the recommended dose number as per a specified protocol. + + + + + Contains the description about the protocol under which the vaccine was administered. + + + + + Indicates the authority who published the protocol? E.g. ACIP. + + + + + One possible path to achieve presumed immunity against a disease - within the context of an authority. + + + + + + + + + A set of information summarized from a list of other resources. + + + + + A set of information summarized from a list of other resources. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifier for the List assigned for business purposes outside the context of FHIR. + + + + + This code defines the purpose of the list - why it was created. + + + + + The common subject (or patient) of the resources that are in the list, if there is one. + + + + + The entity responsible for deciding what the contents of the list were. + + + + + The date that the list was prepared. + + + + + Whether items in the list have a meaningful order. + + + + + How this list was prepared - whether it is a working list that is suitable for being maintained on an ongoing basis, or if it represents a snapshot of a list of items from another source, or whether it is a prepared list where items may be marked as added, modified or deleted. + + + + + Entries in this list. + + + + + If the list is empty, why the list is empty. + + + + + + + + + A set of information summarized from a list of other resources. + + + + + + + The flag allows the system constructing the list to make one or more statements about the role and significance of the item in the list. + + + + + True if this item is marked as deleted in the list. + + + + + When this item was added to the list. + + + + + A reference to the actual resource from which data was derived. + + + + + + + + + + + This list is the master list, maintained in an ongoing fashion with regular updates as the real world list it is tracking changes. + + + + + This list was prepared as a snapshot. It should not be assumed to be current. + + + + + The list is prepared as a statement of changes that have been made or recommended. + + + + + + + The processing mode that applies to this list + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Details and position information for a physical place where services are provided and resources and participants may be stored, found, contained or accommodated. + + + + + Details and position information for a physical place where services are provided and resources and participants may be stored, found, contained or accommodated. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Unique code or number identifying the location to its users. + + + + + Name of the location as used by humans. Does not need to be unique. + + + + + Description of the Location, which helps in finding or referencing the place. + + + + + Indicates the type of function performed at the location. + + + + + The contact details of communication devices available at the location. This can include phone numbers, fax numbers, mobile numbers, email addresses and web sites. + + + + + Physical location. + + + + + Physical form of the location, e.g. building, room, vehicle, road. + + + + + The absolute geographic location of the Location, expressed in a KML compatible manner (see notes below for KML). + + + + + The organization that is responsible for the provisioning and upkeep of the location. + + + + + active | suspended | inactive. + + + + + Another Location which this Location is physically part of. + + + + + Indicates whether a resource instance represents a specific location or a class of locations. + + + + + + + + + Details and position information for a physical place where services are provided and resources and participants may be stored, found, contained or accommodated. + + + + + + + Longitude. The value domain and the interpretation are the same as for the text of the longitude element in KML (see notes below). + + + + + Latitude. The value domain and the interpretation are the same as for the text of the latitude element in KML (see notes below). + + + + + Altitude. The value domain and the interpretation are the same as for the text of the altitude element in KML (see notes below). + + + + + + + + + + + The location is operational. + + + + + The location is temporarily closed. + + + + + The location is no longer used. + + + + + + + Indicates whether the location is still in use + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The Location resource represents a specific instance of a Location. + + + + + The Location represents a class of Locations. + + + + + + + Indicates whether a resource instance represents a specific location or a class of locations + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A photo, video, or audio recording acquired or used in healthcare. The actual content may be inline or provided by direct reference. + + + + + A photo, video, or audio recording acquired or used in healthcare. The actual content may be inline or provided by direct reference. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Whether the media is a photo (still image), an audio recording, or a video recording. + + + + + Details of the type of the media - usually, how it was acquired (what type of device). If images sourced from a DICOM system, are wrapped in a Media resource, then this is the modality. + + + + + Identifiers associated with the image - these may include identifiers for the image itself, identifiers for the context of its collection (e.g. series ids) and context ids such as accession numbers or other workflow identifiers. + + + + + When the media was originally recorded. For video and audio, if the length of the recording is not insignificant, this is the end of the recording. + + + + + Who/What this Media is a record of. + + + + + The person who administered the collection of the image. + + + + + The name of the imaging view e.g Lateral or Antero-posterior (AP). + + + + + The name of the device / manufacturer of the device that was used to make the recording. + + + + + Height of the image in pixels(photo/video). + + + + + Width of the image in pixels (photo/video). + + + + + The number of frames in a photo. This is used with a multi-page fax, or an imaging acquisition context that takes multiple slices in a single image, or an animated gif. If there is more than one frame, this SHALL have a value in order to alert interface software that a multi-frame capable rendering widget is required. + + + + + The length of the recording in seconds - for audio and video. + + + + + The actual content of the media - inline or by direct reference to the media source file. + + + + + + + + + + + The media consists of one or more unmoving images, including photographs, computer-generated graphs and charts, and scanned documents. + + + + + The media consists of a series of frames that capture a moving image. + + + + + The media consists of a sound recording. + + + + + + + Whether the Media is a photo, video, or audio + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Primarily used for identification and definition of Medication, but also covers ingredients and packaging. + + + + + Primarily used for identification and definition of Medication, but also covers ingredients and packaging. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The common/commercial name of the medication absent information such as strength, form, etc. E.g. Acetaminophen, Tylenol 3, etc. The fully coordinated name is communicated as the display of Medication.code. + + + + + A code (or set of codes) that identify this medication. Usage note: This could be a standard drug code such as a drug regulator code, RxNorm code, SNOMED CT code, etc. It could also be a local formulary code, optionally with translations to the standard drug codes. + + + + + Set to true if the item is attributable to a specific manufacturer (even if we don't know who that is). + + + + + Describes the details of the manufacturer. + + + + + Medications are either a single administrable product or a package that contains one or more products. + + + + + Information that only applies to products (not packages). + + + + + Information that only applies to packages (not products). + + + + + + + + + Primarily used for identification and definition of Medication, but also covers ingredients and packaging. + + + + + + + Describes the form of the item. Powder; tables; carton. + + + + + Identifies a particular constituent of interest in the product. + + + + + + + + + Primarily used for identification and definition of Medication, but also covers ingredients and packaging. + + + + + + + The actual ingredient - either a substance (simple ingredient) or another medication. + + + + + Specifies how many (or how much) of the items there are in this Medication. E.g. 250 mg per tablet. + + + + + + + + + Primarily used for identification and definition of Medication, but also covers ingredients and packaging. + + + + + + + The kind of container that this package comes as. + + + + + A set of components that go to make up the described item. + + + + + + + + + Primarily used for identification and definition of Medication, but also covers ingredients and packaging. + + + + + + + Identifies one of the items in the package. + + + + + The amount of the product that is in the package. + + + + + + + + + + + The medication is a product. + + + + + The medication is a package - a contained group of one of more products. + + + + + + + Whether the medication is a product or a package + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Describes the event of a patient being given a dose of a medication. This may be as simple as swallowing a tablet or it may be a long running infusion. + +Related resources tie this event to the authorizing prescription, and the specific encounter between patient and health care practitioner. + + + + + Describes the event of a patient being given a dose of a medication. This may be as simple as swallowing a tablet or it may be a long running infusion. + +Related resources tie this event to the authorizing prescription, and the specific encounter between patient and health care practitioner. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + External identifier - FHIR will generate its own internal IDs (probably URLs) which do not need to be explicitly managed by the resource. The identifier here is one that would be used by another non-FHIR system - for example an automated medication pump would provide a record each time it operated; an administration while the patient was off the ward might be made with a different system and entered after the event. Particularly important if these records have to be updated. + + + + + Will generally be set to show that the administration has been completed. For some long running administrations such as infusions it is possible for an administration to be started but not completed or it may be paused while some other process is under way. + + + + + The person or animal to whom the medication was given. + + + + + The individual who was responsible for giving the medication to the patient. + + + + + The visit or admission the or other contact between patient and health care provider the medication administration was performed as part of. + + + + + The original request, instruction or authority to perform the administration. + + + + + Set this to true if the record is saying that the medication was NOT administered. + + + + + A code indicating why the administration was not performed. + + + + + An interval of time during which the administration took place. For many administrations, such as swallowing a tablet the lower and upper values of the interval will be the same. + + + + + Identifies the medication that was administered. This is either a link to a resource representing the details of the medication or a simple attribute carrying a code that identifies the medication from a known list of medications. + + + + + The device used in administering the medication to the patient. E.g. a particular infusion pump. + + + + + Provides details of how much of the medication was administered. + + + + + + + + + Describes the event of a patient being given a dose of a medication. This may be as simple as swallowing a tablet or it may be a long running infusion. + +Related resources tie this event to the authorizing prescription, and the specific encounter between patient and health care practitioner. + + + + + + + The timing schedule for giving the medication to the patient. This may be a single time point (using dateTime) or it may be a start and end dateTime (Period). + + + + + + + If set to true or if specified as a CodeableConcept, indicates that the medication is only taken when needed within the specified schedule rather than at every scheduled dose. If a CodeableConcept is present, it indicates the pre-condition for taking the Medication. + + + + + + + A coded specification of the anatomic site where the medication first entered the body. E.g. "left arm". + + + + + A code specifying the route or physiological path of administration of a therapeutic agent into or onto the patient. E.g. topical, intravenous, etc. + + + + + A coded value indicating the method by which the medication was introduced into or onto the body. Most commonly used for injections. Examples: Slow Push; Deep IV. + +Terminologies used often pre-coordinate this term with the route and or form of administration. + + + + + The amount of the medication given at one administration event. Use this value when the administration is essentially an instantaneous event such as a swallowing a tablet or giving an injection. + + + + + Identifies the speed with which the medication was introduced into the patient. Typically the rate for an infusion e.g. 200ml in 2 hours. May also expressed as a rate per unit of time such as 100ml per hour - the duration is then not specified, or is specified in the quantity. + + + + + The maximum total quantity of a therapeutic substance that was administered to the patient over the specified period of time. E.g. 1000mg in 24 hours. + + + + + + + + + + + The administration has started but has not yet completed. + + + + + Actions implied by the administration have been temporarily halted, but are expected to continue later. May also be called "suspended". + + + + + All actions that are implied by the administration have occurred. + + + + + The administration was entered in error and therefore nullified. + + + + + Actions implied by the administration have been permanently halted, before all of them occurred. + + + + + + + A set of codes indicating the current status of a MedicationAdministration + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Dispensing a medication to a named patient. This includes a description of the supply provided and the instructions for administering the medication. + + + + + Dispensing a medication to a named patient. This includes a description of the supply provided and the instructions for administering the medication. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifier assigned by the dispensing facility - this is an identifier assigned outside FHIR. + + + + + A code specifying the state of the set of dispense events. + + + + + A link to a resource representing the person to whom the medication will be given. + + + + + The individual responsible for dispensing the medication. + + + + + Indicates the medication order that is being dispensed against. + + + + + Indicates the details of the dispense event such as the days supply and quantity of medication dispensed. + + + + + Indicates whether or not substitution was made as part of the dispense. In some cases substitution will be expected but doesn't happen, in other cases substitution is not expected but does happen. This block explains what substitition did or did not happen and why. + + + + + + + + + Dispensing a medication to a named patient. This includes a description of the supply provided and the instructions for administering the medication. + + + + + + + Identifier assigned by the dispensing facility. This is an identifier assigned outside FHIR. + + + + + A code specifying the state of the dispense event. + + + + + Indicates the type of dispensing event that is performed. Examples include: Trial Fill, Completion of Trial, Partial Fill, Emergency Fill, Samples, etc. + + + + + The amount of medication that has been dispensed. Includes unit of measure. + + + + + Identifies the medication being administered. This is either a link to a resource representing the details of the medication or a simple attribute carrying a code that identifies the medication from a known list of medications. + + + + + The time when the dispensed product was packaged and reviewed. + + + + + The time the dispensed product was provided to the patient or their representative. + + + + + Identification of the facility/location where the medication was shipped to, as part of the dispense event. + + + + + Identifies the person who picked up the medication. This will usually be a patient or their carer, but some cases exist where it can be a healthcare professional. + + + + + Indicates how the medication is to be used by the patient. + + + + + + + + + Dispensing a medication to a named patient. This includes a description of the supply provided and the instructions for administering the medication. + + + + + + + Additional instructions such as "Swallow with plenty of water" which may or may not be coded. + + + + + The timing schedule for giving the medication to the patient. The Schedule data type allows many different expressions, for example. "Every 8 hours"; "Three times a day"; "1/2 an hour before breakfast for 10 days from 23-Dec 2011:"; "15 Oct 2013, 17 Oct 2013 and 1 Nov 2013". + + + + + + + + If set to true or if specified as a CodeableConcept, indicates that the medication is only taken when needed within the specified schedule rather than at every scheduled dose. If a CodeableConcept is present, it indicates the pre-condition for taking the Medication. + + + + + + + A coded specification of the anatomic site where the medication first enters the body. + + + + + A code specifying the route or physiological path of administration of a therapeutic agent into or onto a subject. + + + + + A coded value indicating the method by which the medication is introduced into or onto the body. Most commonly used for injections. Examples: Slow Push; Deep IV. + +Terminologies used often pre-coordinate this term with the route and or form of administration. + + + + + The amount of therapeutic or other substance given at one administration event. + + + + + Identifies the speed with which the substance is introduced into the subject. Typically the rate for an infusion. 200ml in 2 hours. + + + + + The maximum total quantity of a therapeutic substance that may be administered to a subject over the period of time, e.g. 1000mg in 24 hours. + + + + + + + + + Dispensing a medication to a named patient. This includes a description of the supply provided and the instructions for administering the medication. + + + + + + + A code signifying whether a different drug was dispensed from what was prescribed. + + + + + Indicates the reason for the substitution of (or lack of substitution) from what was prescribed. + + + + + The person or organization that has primary responsibility for the substitution. + + + + + + + + + + + The dispense has started but has not yet completed. + + + + + Actions implied by the administration have been temporarily halted, but are expected to continue later. May also be called "suspended". + + + + + All actions that are implied by the dispense have occurred. + + + + + The dispense was entered in error and therefore nullified. + + + + + Actions implied by the dispense have been permanently halted, before all of them occurred. + + + + + + + A code specifying the state of the dispense event. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + An order for both supply of the medication and the instructions for administration of the medicine to a patient. + + + + + An order for both supply of the medication and the instructions for administration of the medicine to a patient. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + External identifier - one that would be used by another non-FHIR system - for example a re-imbursement system might issue its own id for each prescription that is created. This is particularly important where FHIR only provides part of an erntire workflow process where records have to be tracked through an entire system. + + + + + The date (and perhaps time) when the prescription was written. + + + + + A code specifying the state of the order. Generally this will be active or completed state. + + + + + A link to a resource representing the person to whom the medication will be given. + + + + + The healthcare professional responsible for authorizing the prescription. + + + + + A link to a resource that identifies the particular occurrence of contact between patient and health care provider. + + + + + Can be the reason or the indication for writing the prescription. + + + + + + + Identifies the medication being administered. This is either a link to a resource representing the details of the medication or a simple attribute carrying a code that identifies the medication from a known list of medications. + + + + + Indicates how the medication is to be used by the patient. + + + + + Deals with details of the dispense part of the order. + + + + + Indicates whether or not substitution can or should be part of the dispense. In some cases substitution must happen, in other cases substitution must not happen, and in others it does not matter. This block explains the prescriber's intent. If nothing is specified substitution may be done. + + + + + + + + + An order for both supply of the medication and the instructions for administration of the medicine to a patient. + + + + + + + Free text dosage instructions for cases where the instructions are too complex to code. + + + + + Additional instructions such as "Swallow with plenty of water" which may or may not be coded. + + + + + The timing schedule for giving the medication to the patient. The Schedule data type allows many different expressions, for example. "Every 8 hours"; "Three times a day"; "1/2 an hour before breakfast for 10 days from 23-Dec 2011:"; "15 Oct 2013, 17 Oct 2013 and 1 Nov 2013". + + + + + + + + If set to true or if specified as a CodeableConcept, indicates that the medication is only taken when needed within the specified schedule rather than at every scheduled dose. If a CodeableConcept is present, it indicates the pre-condition for taking the Medication. + + + + + + + A coded specification of the anatomic site where the medication first enters the body. + + + + + A code specifying the route or physiological path of administration of a therapeutic agent into or onto a patient. + + + + + A coded value indicating the method by which the medication is introduced into or onto the body. Most commonly used for injections. Examples: Slow Push; Deep IV. + +Terminologies used often pre-coordinate this term with the route and or form of administration. + + + + + The amount of therapeutic or other substance given at one administration event. + + + + + Identifies the speed with which the substance is introduced into the subject. Typically the rate for an infusion. 200ml in 2 hours. + + + + + The maximum total quantity of a therapeutic substance that may be administered to a subject over the period of time. E.g. 1000mg in 24 hours. + + + + + + + + + An order for both supply of the medication and the instructions for administration of the medicine to a patient. + + + + + + + Identifies the medication that is to be dispensed. This may be a more specifically defined than the medicationPrescription.medication . This is either a link to a resource representing the details of the medication or a simple attribute carrying a code that identifies the medication from a known list of medications. + + + + + Design Comments: This indicates the validity period of a prescription (stale dating the Prescription) +It reflects the prescriber perspective for the validity of the prescription. Dispenses must not be made against the prescription outside of this period. The lower-bound of the Dispensing Window signifies the earliest date that the prescription can be filled for the first time. If an upper-bound is not specified then the Prescription is open-ended or will default to a stale-date based on regulations. +Rationale: Indicates when the Prescription becomes valid, and when it ceases to be a dispensable Prescription. + + + + + An integer indicating the number of repeats of the Dispense. +UsageNotes: For example, the number of times the prescribed quantity is to be supplied including the initial standard fill. + + + + + The amount that is to be dispensed. + + + + + Identifies the period time over which the supplied product is expected to be used, or the length of time the dispense is expected to last. +In some situations, this attribute may be used instead of quantity to identify the amount supplied by how long it is expected to last, rather than the physical quantity issued, e.g. 90 days supply of medication (based on an ordered dosage) When possible, it is always better to specify quantity, as this tends to be more precise. expectedSupplyDuration will always be an estimate that can be influenced by external factors. + + + + + + + + + An order for both supply of the medication and the instructions for administration of the medicine to a patient. + + + + + + + A code signifying whether a different drug should be dispensed from what was prescribed. + + + + + Indicates the reason for the substitution, or why substitution must or must not be performed. + + + + + + + + + + + The prescription is 'actionable', but not all actions that are implied by it have occurred yet. + + + + + Actions implied by the prescription have been temporarily halted, but are expected to continue later. May also be called "suspended". + + + + + All actions that are implied by the prescription have occurred (this will rarely be made explicit). + + + + + The prescription was entered in error and therefore nullified. + + + + + Actions implied by the prescription have been permanently halted, before all of them occurred. + + + + + The prescription was replaced by a newer one, which encompasses all the information in the previous one. + + + + + + + A code specifying the state of the prescribing event. Describes the lifecycle of the prescription. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A record of medication being taken by a patient, or that the medication has been given to a patient where the record is the result of a report from the patient or another clinician. + + + + + A record of medication being taken by a patient, or that the medication has been given to a patient where the record is the result of a report from the patient or another clinician. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + External identifier - FHIR will generate its own internal IDs (probably URLs) which do not need to be explicitly managed by the resource. The identifier here is one that would be used by another non-FHIR system - for example an automated medication pump would provide a record each time it operated; an administration while the patient was off the ward might be made with a different system and entered after the event. Particularly important if these records have to be updated. + + + + + The person or animal who is /was taking the medication. + + + + + Set this to true if the record is saying that the medication was NOT taken. + + + + + A code indicating why the medication was not taken. + + + + + The interval of time during which it is being asserted that the patient was taking the medication. + + + + + Identifies the medication being administered. This is either a link to a resource representing the details of the medication or a simple attribute carrying a code that identifies the medication from a known list of medications. + + + + + An identifier or a link to a resource that identifies a device used in administering the medication to the patient. + + + + + Indicates how the medication is/was used by the patient. + + + + + + + + + A record of medication being taken by a patient, or that the medication has been given to a patient where the record is the result of a report from the patient or another clinician. + + + + + + + The timing schedule for giving the medication to the patient. The Schedule data type allows many different expressions, for example. "Every 8 hours"; "Three times a day"; "1/2 an hour before breakfast for 10 days from 23-Dec 2011:"; "15 Oct 2013, 17 Oct 2013 and 1 Nov 2013". + + + + + If set to true or if specified as a CodeableConcept, indicates that the medication is only taken when needed within the specified schedule rather than at every scheduled dose. If a CodeableConcept is present, it indicates the pre-condition for taking the Medication. + + + + + + + A coded specification of the anatomic site where the medication first enters the body. + + + + + A code specifying the route or physiological path of administration of a therapeutic agent into or onto a subject. + + + + + A coded value indicating the method by which the medication is introduced into or onto the body. Most commonly used for injections. Examples: Slow Push; Deep IV. + +Terminologies used often pre-coordinate this term with the route and or form of administration. + + + + + The amount of therapeutic or other substance given at one administration event. + + + + + Identifies the speed with which the substance is introduced into the subject. Typically the rate for an infusion. 200ml in 2 hours. + + + + + The maximum total quantity of a therapeutic substance that may be administered to a subject over the period of time. E.g. 1000mg in 24 hours. + + + + + + + + + The header for a message exchange that is either requesting or responding to an action. The resource(s) that are the subject of the action as well as other Information related to the action are typically transmitted in a bundle in which the MessageHeader resource instance is the first resource in the bundle. + + + + + The header for a message exchange that is either requesting or responding to an action. The resource(s) that are the subject of the action as well as other Information related to the action are typically transmitted in a bundle in which the MessageHeader resource instance is the first resource in the bundle. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The identifier of this message. + + + + + The time that the message was sent. + + + + + Code that identifies the event this message represents and connects it with it's definition. Events defined as part of the FHIR specification have the system value "http://hl7.org/fhir/message-type". + + + + + Information about the message that this message is a response to. Only present if this message is a response. + + + + + The source application from which this message originated. + + + + + The destination application which the message is intended for. + + + + + The person or device that performed the data entry leading to this message. Where there is more than one candidate, pick the most proximal to the message. Can provide other enterers in extensions. + + + + + The logical author of the message - the person or device that decided the described event should happen. Where there is more than one candidate, pick the most proximal to the MessageHeader. Can provide other authors in extensions. + + + + + Allows data conveyed by a message to be addressed to a particular person or department when routing to a specific application isn't sufficient. + + + + + The person or organization that accepts overall responsibility for the contents of the message. The implication is that the message event happened under the policies of the responsible party. + + + + + Coded indication of the cause for the event - indicates a reason for the occurance of the event that is a focus of this message. + + + + + The actual data of the message - a reference to the root/focus class of the event. + + + + + + + + + The header for a message exchange that is either requesting or responding to an action. The resource(s) that are the subject of the action as well as other Information related to the action are typically transmitted in a bundle in which the MessageHeader resource instance is the first resource in the bundle. + + + + + + + The id of the message that this message is a response to. + + + + + Code that identifies the type of response to the message - whether it was successful or not, and whether it should be resent or not. + + + + + Full details of any issues found in the message. + + + + + + + + + The header for a message exchange that is either requesting or responding to an action. The resource(s) that are the subject of the action as well as other Information related to the action are typically transmitted in a bundle in which the MessageHeader resource instance is the first resource in the bundle. + + + + + + + Human-readable name for the target system. + + + + + May include configuration or other information useful in debugging. + + + + + Can convey versions of multiple systems in situations where a message passes through multiple hands. + + + + + An e-mail, phone, website or other contact point to use to resolve issues with message communications. + + + + + Identifies the routing target to send acknowledgements to. + + + + + + + + + The header for a message exchange that is either requesting or responding to an action. The resource(s) that are the subject of the action as well as other Information related to the action are typically transmitted in a bundle in which the MessageHeader resource instance is the first resource in the bundle. + + + + + + + Human-readable name for the source system. + + + + + Identifies the target end system in situations where the initial message transmission is to an intermediary system. + + + + + Indicates where the message should be routed to. + + + + + + + + + + + The message was accepted and processed without error. + + + + + Some internal unexpected error occurred - wait and try again. Note - this is usually used for things like database unavailable, which may be expected to resolve, though human intervention may be required. + + + + + The message was rejected because of some content in it. There is no point in re-sending without change. The response narrative SHALL describe what the issue is. + + + + + + + The kind of response to a message + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Measurements and simple assertions made about a patient, device or other subject. + + + + + Measurements and simple assertions made about a patient, device or other subject. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Describes what was observed. Sometimes this is called the observation "code". + + + + + The information determined as a result of making the observation, if the information has a simple value. + + + + + + + + + + + + The assessment made based on the result of the observation. + + + + + May include statements about significant, unexpected or unreliable values, or information about the source of the value where this may be relevant to the interpretation of the result. + + + + + The time or time-period the observed value is asserted as being true. For biological subjects - e.g. human patients - this is usually called the "physiologically relevant time". This is usually either the time of the procedure or of specimen collection, but very often the source of the date/time is not known, only the date/time itself. + + + + + + + Date/Time this was made available. + + + + + The status of the result value. + + + + + An estimate of the degree to which quality issues have impacted on the value reported. + + + + + Indicates where on the subject's body the observation was made. + + + + + Indicates the mechanism used to perform the observation. + + + + + A unique identifier for the simple observation. + + + + + The thing the observation is being made about. + + + + + The specimen that was used when this observation was made. + + + + + Who was responsible for asserting the observed value as "true". + + + + + Guidance on how to interpret the value by comparison to a normal or recommended range. + + + + + Related observations - either components, or previous observations, or statements of derivation. + + + + + + + + + Measurements and simple assertions made about a patient, device or other subject. + + + + + + + The value of the low bound of the reference range. If this is omitted, the low bound of the reference range is assumed to be meaningless. E.g. <2.3. + + + + + The value of the high bound of the reference range. If this is omitted, the high bound of the reference range is assumed to be meaningless. E.g. >5. + + + + + Code for the meaning of the reference range. + + + + + The age at which this reference range is applicable. This is a neonatal age (e.g. number of weeks at term) if the meaning says so. + + + + + + + + + Measurements and simple assertions made about a patient, device or other subject. + + + + + + + A code specifying the kind of relationship that exists with the target observation. + + + + + A reference to the observation that is related to this observation. + + + + + + + + + + + The result has no reliability concerns. + + + + + An early estimate of value; measurement is still occurring. + + + + + An early estimate of value; processing is still occurring. + + + + + The observation value should be treated with care. + + + + + The result has been generated while calibration is occurring. + + + + + The observation could not be completed because of an error. + + + + + No observation value was available. + + + + + + + Codes that provide an estimate of the degree to which quality issues have impacted on the value of an observation + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The existence of the observation is registered, but there is no result yet available. + + + + + This is an initial or interim observation: data may be incomplete or unverified. + + + + + The observation is complete and verified by an authorized person. + + + + + The observation has been modified subsequent to being Final, and is complete and verified by an authorized person. + + + + + The observation is unavailable because the measurement was not started or not completed (also sometimes called "aborted"). + + + + + The observation has been withdrawn following previous Final release. + + + + + + + Codes providing the status of an observation + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The target observation is a component of this observation (e.g. Systolic and Diastolic Blood Pressure). + + + + + This observation is a group observation (e.g. a battery, a panel of tests, a set of vital sign measurements) that includes the target as a member of the group. + + + + + The target observation is part of the information from which this observation value is derived (e.g. calculated anion gap, Apgar score). + + + + + This observation follows the target observation (e.g. timed tests such as Glucose Tolerance Test). + + + + + This observation replaces a previous observation (i.e. a revised value). The target observation is now obsolete. + + + + + The value of the target observation qualifies (refines) the semantics of the source observation (e.g. a lipaemia measure target from a plasma measure). + + + + + The value of the target observation interferes (degardes quality, or prevents valid observation) with the semantics of the source observation (e.g. a hemolysis measure target from a plasma potassium measure which has no value). + + + + + + + Codes specifying how two observations are related + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A collection of error, warning or information messages that result from a system action. + + + + + A collection of error, warning or information messages that result from a system action. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + An error, warning or information message that results from a system action. + + + + + + + + + A collection of error, warning or information messages that result from a system action. + + + + + + + Indicates whether the issue indicates a variation from successful processing. + + + + + A code indicating the type of error, warning or information message. + + + + + Additional description of the issue. + + + + + A simple XPath limited to element names, repetition indicators and the default child access that identifies one of the elements in the resource that caused this issue to be raised. + + + + + + + + + + + The issue caused the action to fail, and no further checking could be performed. + + + + + The issue is sufficiently important to cause the action to fail. + + + + + The issue is not important enough to cause the action to fail, but may cause it to be performed suboptimally or in a way that is not as desired. + + + + + The issue has no relation to the degree of success of the action. + + + + + + + How the issue affects the success of the action + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A request to perform an action. + + + + + A request to perform an action. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifiers assigned to this order by the orderer or by the receiver. + + + + + When the order was made. + + + + + Patient this order is about. + + + + + Who initiated the order. + + + + + Who is intended to fulfill the order. + + + + + Text - why the order was made. + + + + + + + If required by policy. + + + + + When order should be fulfilled. + + + + + What action is being ordered. + + + + + + + + + A request to perform an action. + + + + + + + Code specifies when request should be done. The code may simply be a priority code. + + + + + A formal schedule. + + + + + + + + + A response to an order. + + + + + A response to an order. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifiers assigned to this order. The identifiers are usually assigned by the system responding to the order, but they may be provided or added to by other systems. + + + + + A reference to the order that this is in response to. + + + + + The date and time at which this order response was made (created/posted). + + + + + The person, organization, or device credited with making the response. + + + + + A reference to an authority policy that is the reason for the response. Usually this is used when the order is rejected, to provide a reason for rejection. + + + + + + + What this response says about the status of the original order. + + + + + Additional description about the response - e.g. a text description provided by a human user when making decisions about the order. + + + + + Links to resources that provide details of the outcome of performing the order. E.g. Diagnostic Reports in a response that is made to an order that referenced a diagnostic order. + + + + + + + + + + + The order is known, but no processing has occurred at this time. + + + + + The order is undergoing initial processing to determine whether it will be accepted (usually this involves human review). + + + + + The order was rejected because of a workflow/business logic reason. + + + + + The order was unable to be processed because of a technical error (i.e. unexpected error). + + + + + The order has been accepted, and work is in progress. + + + + + Processing the order was halted at the initiators request. + + + + + The order has been cancelled and replaced by another. + + + + + Processing the order was stopped because of some workflow/business logic reason. + + + + + The order has been completed. + + + + + + + The status of the response to an order + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A formally or informally recognized grouping of people or organizations formed for the purpose of achieving some form of collective action. Includes companies, institutions, corporations, departments, community groups, healthcare practice groups, etc. + + + + + A formally or informally recognized grouping of people or organizations formed for the purpose of achieving some form of collective action. Includes companies, institutions, corporations, departments, community groups, healthcare practice groups, etc. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifier for the organization that is used to identify the organization across multiple disparate systems. + + + + + A name associated with the organization. + + + + + The kind of organization that this is. + + + + + A contact detail for the organization. + + + + + An address for the organization. + + + + + The organization of which this organization forms a part. + + + + + Contact for the organization for a certain purpose. + + + + + Location(s) the organization uses to provide services. + + + + + Whether the organization's record is still in active use. + + + + + + + + + A formally or informally recognized grouping of people or organizations formed for the purpose of achieving some form of collective action. Includes companies, institutions, corporations, departments, community groups, healthcare practice groups, etc. + + + + + + + Indicates a purpose for which the contact can be reached. + + + + + A name associated with the contact. + + + + + A contact detail (e.g. a telephone number or an email address) by which the party may be contacted. + + + + + Visiting or postal addresses for the contact. + + + + + Administrative Gender - the gender that the person is considered to have for administration and record keeping purposes. + + + + + + + + + Other is a conformant for handling resource concepts not yet defined for FHIR or outside HL7's scope of interest. + + + + + Other is a conformant for handling resource concepts not yet defined for FHIR or outside HL7's scope of interest. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifier assigned to the resource for business purposes, outside the context of FHIR. + + + + + Identifies the 'type' of resource - equivalent to the resource name for other resources. + + + + + Identifies the patient, practitioner, device or any other resource that is the "focus" of this resoruce. + + + + + Indicates who was responsible for creating the resource instance. + + + + + Identifies when the resource was first created. + + + + + + + + + Demographics and other administrative information about a person or animal receiving care or other health-related services. + + + + + Demographics and other administrative information about a person or animal receiving care or other health-related services. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + An identifier that applies to this person as a patient. + + + + + A name associated with the individual. + + + + + A contact detail (e.g. a telephone number or an email address) by which the individual may be contacted. + + + + + Administrative Gender - the gender that the patient is considered to have for administration and record keeping purposes. + + + + + The date and time of birth for the individual. + + + + + Indicates if the individual is deceased or not. + + + + + + + Addresses for the individual. + + + + + This field contains a patient's most recent marital (civil) status. + + + + + Indicates whether the patient is part of a multiple or indicates the actual birth order. + + + + + + + Image of the person. + + + + + A contact party (e.g. guardian, partner, friend) for the patient. + + + + + This element has a value if the patient is an animal. + + + + + Languages which may be used to communicate with the patient about his or her health. + + + + + Patient's nominated care provider. + + + + + Organization that is the custodian of the patient record. + + + + + Link to another patient resource that concerns the same actual person. + + + + + Whether this patient record is in active use. + + + + + + + + + Demographics and other administrative information about a person or animal receiving care or other health-related services. + + + + + + + The nature of the relationship between the patient and the contact person. + + + + + A name associated with the person. + + + + + A contact detail for the person, e.g. a telephone number or an email address. + + + + + Address for the contact person. + + + + + Administrative Gender - the gender that the person is considered to have for administration and record keeping purposes. + + + + + Organization on behalf of which the contact is acting or for which the contact is working. + + + + + + + + + Demographics and other administrative information about a person or animal receiving care or other health-related services. + + + + + + + Identifies the high level categorization of the kind of animal. + + + + + Identifies the detailed categorization of the kind of animal. + + + + + Indicates the current state of the animal's reproductive organs. + + + + + + + + + Demographics and other administrative information about a person or animal receiving care or other health-related services. + + + + + + + The other patient resource that the link refers to. + + + + + The type of link between this patient resource and another patient resource. + + + + + + + + + + + The patient resource containing this link must no longer be used. The link points forward to another patient resource that must be used in lieu of the patient resource that contains the link. + + + + + The patient resource containing this link is in use and valid but not considered the main source of information about a patient. The link points forward to another patient resource that should be consulted to retrieve additional patient information. + + + + + The patient resource containing this link is in use and valid, but points to another patient resource that is known to contain data about the same person. Data in this resource might overlap or contradict information found in the other patient resource. This link does not indicate any relative importance of the resources concerned, and both should be regarded as equally valid. + + + + + + + The type of link between this patient resource and another patient resource. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A person who is directly or indirectly involved in the provisioning of healthcare. + + + + + A person who is directly or indirectly involved in the provisioning of healthcare. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + An identifier that applies to this person in this role. + + + + + A name associated with the person. + + + + + A contact detail for the practitioner, e.g. a telephone number or an email address. + + + + + The postal address where the practitioner can be found or visited or to which mail can be delivered. + + + + + Administrative Gender - the gender that the person is considered to have for administration and record keeping purposes. + + + + + The date and time of birth for the practitioner. + + + + + Image of the person. + + + + + The organization that the practitioner represents. + + + + + Roles which this practitioner is authorized to perform for the organization. + + + + + Specific specialty of the practitioner. + + + + + The period during which the person is authorized to act as a practitioner in these role(s) for the organization. + + + + + The location(s) at which this practitioner provides care. + + + + + Qualifications obtained by training and certification. + + + + + A language the practitioner is able to use in patient communication. + + + + + + + + + A person who is directly or indirectly involved in the provisioning of healthcare. + + + + + + + Coded representation of the qualification. + + + + + Period during which the qualification is valid. + + + + + Organization that regulates and issues the qualification. + + + + + + + + + An action that is performed on a patient. This can be a physical 'thing' like an operation, or less invasive like counseling or hypnotherapy. + + + + + An action that is performed on a patient. This can be a physical 'thing' like an operation, or less invasive like counseling or hypnotherapy. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + This records identifiers associated with this procedure that are defined by business processed and/ or used to refer to it when a direct URL reference to the resource itself is not appropriate (e.g. in CDA documents, or in written / printed documentation). + + + + + The person on whom the procedure was performed. + + + + + The specific procedure that is performed. Use text if the exact nature of the procedure can't be coded. + + + + + Detailed and structured anatomical location information. Multiple locations are allowed - e.g. multiple punch biopsies of a lesion. + + + + + The reason why the procedure was performed. This may be due to a Condition, may be coded entity of some type, or may simply be present as text. + + + + + Limited to 'real' people rather than equipment. + + + + + The dates over which the procedure was performed. Allows a period to support complex procedures that span more that one date, and also allows for the length of the procedure to be captured. + + + + + The encounter during which the procedure was performed. + + + + + What was the outcome of the procedure - did it resolve reasons why the procedure was performed?. + + + + + This could be a histology result. There could potentially be multiple reports - e.g. if this was a procedure that made multiple biopsies. + + + + + Any complications that occurred during the procedure, or in the immediate post-operative period. These are generally tracked separately from the notes, which typically will describe the procedure itself rather than any 'post procedure' issues. + + + + + If the procedure required specific follow up - e.g. removal of sutures. The followup may be represented as a simple note, or potentially could be more complex in which case the CarePlan resource can be used. + + + + + Procedures may be related to other items such as procedures or medications. For example treating wound dehiscence following a previous procedure. + + + + + Any other notes about the procedure - e.g. the operative notes. + + + + + + + + + An action that is performed on a patient. This can be a physical 'thing' like an operation, or less invasive like counseling or hypnotherapy. + + + + + + + The practitioner who was involved in the procedure. + + + + + E.g. surgeon, anaethetist, endoscopist. + + + + + + + + + An action that is performed on a patient. This can be a physical 'thing' like an operation, or less invasive like counseling or hypnotherapy. + + + + + + + The nature of the relationship. + + + + + The related item - e.g. a procedure. + + + + + + + + + + + This procedure had to be performed because of the related one. + + + + + This procedure caused the related one to be performed. + + + + + + + The nature of the relationship with this procedure + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The identifier that is used to identify this profile when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI). + + + + + The identifier that is used to identify this version of the profile when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp. + + + + + A free text natural language name identifying the Profile. + + + + + Details of the individual or organization who accepts responsibility for publishing the profile. + + + + + Contact details to assist a user in finding and communicating with the publisher. + + + + + A free text natural language description of the profile and its use. + + + + + A set of terms from external terminologies that may be used to assist with indexing and searching of templates. + + + + + The status of the profile. + + + + + This profile was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage. + + + + + The date that this version of the profile was published. + + + + + The Scope and Usage that this profile was created to meet. + + + + + The version of the FHIR specification on which this profile is based. + + + + + An external specification that the content is mapped to. + + + + + A constraint statement about what contents a resource or data type may have. + + + + + An extension defined as part of the profile. + + + + + Definition of a named query and its parameters and their meaning. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + An Internal id that is used to identify this mapping set when specific mappings are made. + + + + + A URI that identifies the specification that this mapping is expressed to. + + + + + A name for the specification that is being mapped to. + + + + + Comments about this mapping, including version notes, issues, scope limitations, and other important notes for usage. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + The Resource or Data type being described. + + + + + The name of this resource constraint statement (to refer to it from other resource constraints - from Profile.structure.element.definition.type.profile). + + + + + This definition of a profile on a structure is published as a formal statement. Some structural definitions might be defined purely for internal use within the profile, and not intended to be used outside that context. + + + + + Human summary: why describe this resource?. + + + + + Captures constraints on each element within the resource. + + + + + Additional search parameters for implementations to support and/or make use of. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + The path identifies the element and is expressed as a "."-separated list of ancestor elements, beginning with the name of the resource. + + + + + Codes that define how this element is represented in instances, when the deviation varies from the normal case. + + + + + The name of this element definition (to refer to it from other element definitions using Profile.structure.element.definition.nameReference). This is a unique name referring to a specific set of constraints applied to this element. One use of this is to provide a name to different slices of the same element. + + + + + Indicates that the element is sliced into a set of alternative definitions (there are multiple definitions on a single element in the base resource). The set of slices is any elements that come after this in the element sequence that have the same path, until a shorter path occurs (the shorter path terminates the set). + + + + + Definition of the content of the element to provide a more specific definition than that contained for the element in the base resource. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + Designates which child element is used to discriminate between the slices when processing an instance. The value of the child element in the instance SHALL completely distinguish which slice the element in the resource matches based on the allowed values for that element in each of the slices. + + + + + If the matching elements have to occur in the same order as defined in the profile. + + + + + Whether additional slices are allowed or not. When the slices are ordered, profile authors can also say that additional slices are only allowed at the end. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + A concise definition that is shown in the generated XML format that summarizes profiles (used throughout the specification). + + + + + The definition SHALL be consistent with the base definition, but convey the meaning of the element in the particular context of use of the resource. + + + + + Comments about the use of the element, including notes about how to use the data properly, exceptions to proper use, etc. + + + + + Explains why this element is needed and why it's been constrained as it has. + + + + + Identifies additional names by which this element might also be known. + + + + + The minimum number of times this element SHALL appear in the instance. + + + + + The maximum number of times this element is permitted to appear in the instance. + + + + + The data type or resource that the value of this element is permitted to be. + + + + + Identifies the name of a slice defined elsewhere in the profile whose constraints should be applied to the current element. + + + + + Specifies a primitive value that SHALL hold for this element in the instance. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + An example value for this element. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Indicates the shortest length that SHALL be supported by conformant instances without truncation. + + + + + A reference to an invariant that may make additional statements about the cardinality or value in the instance. + + + + + Formal constraints such as co-occurrence and other constraints that can be computationally evaluated within the context of the instance. + + + + + If true, conformant resource authors SHALL be capable of providing a value for the element and resource consumers SHALL be capable of extracting and doing something useful with the data element. If false, the element may be ignored and not supported. + + + + + If true, the value of this element affects the interpretation of the element or resource that contains it, and the value of the element cannot be ignored. Typically, this is used for status, negation and qualification codes. The effect of this is that the element cannot be ignored by systems: they SHALL either recognize the element and process it, and/or a pre-determination has been made that it is not relevant to their particular system. + + + + + Binds to a value set if this element is coded (code, Coding, CodeableConcept). + + + + + Identifies a concept from an external specification that roughly corresponds to this element. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + Name of Data type or Resource. + + + + + Identifies a profile that SHALL hold for resources or datatypes referenced as the type of this element. Can be a local reference - to another structure in this profile, or a reference to a structure in another profile. + + + + + If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + Allows identification of which elements have their cardinalities impacted by the constraint. Will not be referenced for constraints that do not affect cardinality. + + + + + Used to label the constraint in OCL or in short displays incapable of displaying the full human description. + + + + + Identifies the impact constraint violation has on the conformance of the instance. + + + + + Text that can be used to describe the constraint in messages identifying that the constraint has been violated. + + + + + XPath expression of constraint. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + A descriptive name for this - can be useful for generating implementation artifacts. + + + + + If true, then conformant systems may use additional codes or (where the data type permits) text alone to convey concepts not covered by the set of codes identified in the binding. If false, then conformant systems are constrained to the provided codes alone. + + + + + Indicates the degree of conformance expectations associated with this binding. + + + + + Describes the intended use of this particular set of codes. + + + + + Points to the value set or external definition that identifies the set of codes to be used. + + + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + An internal reference to the definition of a mapping. + + + + + Expresses what part of the target specification corresponds to this element. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + The name of the standard or custom search parameter. + + + + + The type of value a search parameter refers to, and how the content is interpreted. + + + + + A specification for search parameters. For standard parameters, provides additional information on how the parameter is used in this solution. For custom parameters, provides a description of what the parameter does. + + + + + An XPath expression that returns a set of elements for the search parameter. + + + + + Types of resource (if a resource is referenced). + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + A unique code (within the profile) used to identify the extension. + + + + + Defined so that applications can use this name when displaying the value of the extension to the user. + + + + + Identifies the type of context to which the extension applies. + + + + + Identifies the types of resource or data type elements to which the extension can be applied. + + + + + Definition of the extension and its content. + + + + + + + + + A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions. + + + + + + + The name of a query, which is used in the URI from Conformance statements declaring use of the query. Typically this will also be the name for the _query parameter when the query is called, though in some cases it may be aliased by a server to avoid collisions. + + + + + Description of the query - the functionality it offers, and considerations about how it functions and to use it. + + + + + A parameter of a named query. + + + + + + + + + + + Only codes in the specified set are allowed. If the binding is extensible, other codes may be used for concepts not covered by the bound set of codes. + + + + + For greater interoperability, implementers are strongly encouraged to use the bound set of codes, however alternate codes may be used in derived profiles and implementations if necessary without being considered non-conformant. + + + + + The codes in the set are an example to illustrate the meaning of the field. There is no particular preference for its use nor any assertion that the provided values are sufficient to meet implementation needs. + + + + + + + Binding conformance for applications + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + If the constraint is violated, the resource is not conformant. + + + + + If the constraint is violated, the resource is conformant, but it is not necessarily following best practice. + + + + + + + SHALL applications comply with this constraint? + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + This profile is still under development. + + + + + This profile is ready for normal use. + + + + + This profile has been deprecated, withdrawn or superseded and should no longer be used. + + + + + + + The lifecycle status of a Resource Profile + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + In XML, this property is represented as an attribute not an element. + + + + + + + How a property is represented on the wire + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The reference is a local reference to a contained resource. + + + + + The reference to to a resource that has to be resolved externally to the resource that includes the reference. + + + + + The resource the reference points to will be found in the same bundle as the resource that includes the reference. + + + + + + + How resource references can be aggregated + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The context is all elements matching a particular resource element path. + + + + + The context is all nodes matching a particular data type element path (root or repeating element) or all elements referencing a particular primitive data type (expressed as the datatype name). + + + + + The context is all nodes whose mapping to a specified reference model corresponds to a particular mapping structure. The context identifies the mapping target. The mapping should clearly identify where such an extension could be used. + + + + + The context is a particular extension from a particular profile. Expressed as uri#name, where uri identifies the profile and #name identifies the extension code. + + + + + + + How an extension context is interpreted + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + No additional content is allowed other than that described by the slices in this profile. + + + + + Additional content is allowed anywhere in the list. + + + + + Additional content is allowed, but only at the end of the list. + + + + + + + How slices are interpreted when evaluating an instance + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Provenance information that describes the activity that led to the creation of a set of resources. This information can be used to help determine their reliability or trace where the information in them came from. The focus of the provenance resource is record keeping, audit and traceability, and not explicit statements of clinical significance. + + + + + Provenance information that describes the activity that led to the creation of a set of resources. This information can be used to help determine their reliability or trace where the information in them came from. The focus of the provenance resource is record keeping, audit and traceability, and not explicit statements of clinical significance. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The resource(s) that were generated by the activity described in this resource. A provenance can point to more than one target if multiple resources were created/updated by the same activity. + + + + + The period during which the activity occurred. + + + + + The instant of time at which the activity was recorded. + + + + + The reason that the activity was taking place. + + + + + Where the activity occurred, if relevant. + + + + + Policy or plan the activity was defined by. Typically, a single activity may have multiple applicable policy documents, such as patient consent, guarantor funding, etc. + + + + + An agent takes a role in an activity such that the agent can be assigned some degree of responsibility for the activity taking place. An agent can be a person, a piece of software, an inanimate object, an organization, or other entities that may be ascribed responsibility. + + + + + An entity used in this activity. + + + + + A digital signature on the target resource(s). The signature should match a Provenance.agent.reference in the provenance resource. The signature is only added to support checking cryptographic integrity of the resource, and not to represent workflow and clinical aspects of the signing process, or to support non-repudiation. + + + + + + + + + Provenance information that describes the activity that led to the creation of a set of resources. This information can be used to help determine their reliability or trace where the information in them came from. The focus of the provenance resource is record keeping, audit and traceability, and not explicit statements of clinical significance. + + + + + + + The role that the participant played. + + + + + The type of the participant. + + + + + Identity of participant. May be a logical or physical uri and maybe absolute or relative. + + + + + Human-readable description of the participant. + + + + + + + + + Provenance information that describes the activity that led to the creation of a set of resources. This information can be used to help determine their reliability or trace where the information in them came from. The focus of the provenance resource is record keeping, audit and traceability, and not explicit statements of clinical significance. + + + + + + + How the entity was used during the activity. + + + + + The type of the entity. If the entity is a resource, then this is a resource type. + + + + + Identity of participant. May be a logical or physical uri and maybe absolute or relative. + + + + + Human-readable description of the entity. + + + + + The entity is attributed to an agent to express the agent's responsibility for that entity, possibly along with other agents. This description can be understood as shorthand for saying that the agent was responsible for the activity which generated the entity. + + + + + + + + + + + A transformation of an entity into another, an update of an entity resulting in a new one, or the construction of a new entity based on a preexisting entity. + + + + + A derivation for which the resulting entity is a revised version of some original. + + + + + The repeat of (some or all of) an entity, such as text or image, by someone who may or may not be its original author. + + + + + A primary source for a topic refers to something produced by some agent with direct experience and knowledge about the topic, at the time of the topic's study, without benefit from hindsight. + + + + + + + How an entity was used in an activity + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A description of a query with a set of parameters. + + + + + A description of a query with a set of parameters. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Links query and its response(s). + + + + + Set of query parameters with values. + + + + + If this is a response to a query. + + + + + + + + + A description of a query with a set of parameters. + + + + + + + Links response to source query. + + + + + Outcome of processing the query. + + + + + Total number of matching records. + + + + + Parameters server used. + + + + + To get first page (if paged). + + + + + To get previous page (if paged). + + + + + To get next page (if paged). + + + + + To get last page (if paged). + + + + + Resources that are the results of the search. + + + + + + + + + + + The query was processed successfully. + + + + + The query was processed successfully, but some additional limitations were added. + + + + + The server refused to process the query. + + + + + The server tried to process the query, but some error occurred. + + + + + + + The outcome of processing a query request + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A structured set of questions and their answers. The Questionnaire may contain questions, answers or both. The questions are ordered and grouped into coherent subsets, corresponding to the structure of the grouping of the underlying questions. + + + + + A structured set of questions and their answers. The Questionnaire may contain questions, answers or both. The questions are ordered and grouped into coherent subsets, corresponding to the structure of the grouping of the underlying questions. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The lifecycle status of the questionnaire as a whole. + + + + + The date and/or time that this version of the questionnaire was authored. + + + + + The subject of the questionnaires: this is the patient that the answers apply to, but this person is not necessarily the source of information. + + + + + Person who received the answers to the questions in the Questionnaire and recorded them in the system. + + + + + The person who answered the questions about the subject. Only used when this is not the subject him/herself. + + + + + Structured name for a predefined list of questions this questionnaire is responding to. + + + + + This records identifiers associated with this question/answer set that are defined by business processed and/ or used to refer to it when a direct URL reference to the resource itself is not appropriate (e.g. in CDA documents, or in written / printed documentation). + + + + + Encounter during which this questionnaire answers were collected. When there were multiple encounters, this is the one considered most relevant to the context of the answers. + + + + + A group of questions to a possibly similarly grouped set of questions in the questionnaire. + + + + + + + + + A structured set of questions and their answers. The Questionnaire may contain questions, answers or both. The questions are ordered and grouped into coherent subsets, corresponding to the structure of the grouping of the underlying questions. + + + + + + + Structured name for a section of a predefined list of questions this questionnaire is responding to. + + + + + Text that is displayed above the contents of the group. + + + + + Additional text for the group, used for display purposes. + + + + + More specific subject this section's answers are about, details the subject given in Questionnaire. + + + + + A sub-group within a group. The ordering of groups within this group is relevant. + + + + + Set of questions within this group. The order of questions within the group is relevant. + + + + + + + + + A structured set of questions and their answers. The Questionnaire may contain questions, answers or both. The questions are ordered and grouped into coherent subsets, corresponding to the structure of the grouping of the underlying questions. + + + + + + + Structured name for the question that identifies this question within the Questionnaire or Group. + + + + + Text of the question as it is shown to the user. + + + + + Single-valued answer to the question. + + + + + + + + + + + + Selections made by the user from the list of options. + + + + + Reference to a valueset containing the possible options. + + + + + Structured answer in the form of a FHIR Resource or datatype. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The remark contains information about the answer given. This is additional information about the answer the author wishes to convey, but should not be used to contain information that is part of the answer itself. + + + + + Nested group, containing nested question for this question. The order of groups within the question is relevant. + + + + + + + + + + + This Questionnaire is used as a template but the template is not ready for use or publication. + + + + + This Questionnaire is used as a template, is published and ready for use. + + + + + This Questionnaire is used as a template but should no longer be used for new Questionnaires. + + + + + This Questionnaire has been filled out with answers, but changes or additions are still expected to be made to it. + + + + + This Questionnaire has been filled out with answers, and the current content is regarded as definitive. + + + + + This Questionnaire has been filled out with answers, then marked as complete, yet changes or additions have been made to it afterwards. + + + + + + + Lifecycle status of the questionnaire + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Information about a person that is involved in the care for a patient, but who is not the target of healthcare, nor has a formal responsibility in the care process. + + + + + Information about a person that is involved in the care for a patient, but who is not the target of healthcare, nor has a formal responsibility in the care process. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifier for a person within a particular scope. + + + + + The patient this person is related to. + + + + + The nature of the relationship between a patient and the related person. + + + + + A name associated with the person. + + + + + A contact detail for the person, e.g. a telephone number or an email address. + + + + + Administrative Gender - the gender that the person is considered to have for administration and record keeping purposes. + + + + + Address where the related person can be contacted or visited. + + + + + Image of the person. + + + + + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Identifies the name, action type, time, and disposition of the audited event. + + + + + A person, a hardware device or software process. + + + + + Application systems and processes. + + + + + Specific instances of data or objects that have been accessed. + + + + + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + + + Identifier for a family of the event. + + + + + Identifier for the category of event. + + + + + Indicator for type of action performed during the event that generated the audit. + + + + + The time when the event occurred on the source. + + + + + Indicates whether the event succeeded or failed. + + + + + A free text description of the outcome of the event. + + + + + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + + + Specification of the role(s) the user plays when performing the event. Usually the codes used in this element are local codes defined by the role-based access control security system used in the local context. + + + + + Direct reference to a resource that identifies the participant. + + + + + Unique identifier for the user actively participating in the event. + + + + + Alternative Participant Identifier. For a human, this should be a user identifier text string from authentication system. This identifier would be one known to a common authentication system (e.g., single sign-on), if available. + + + + + Human-meaningful name for the user. + + + + + Indicator that the user is or is not the requestor, or initiator, for the event being audited. + + + + + Type of media involved. Used when the event is about exporting/importing onto media. + + + + + Logical network location for application activity, if the activity has a network location. + + + + + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + + + An identifier for the network access point of the user device for the audit event. + + + + + An identifier for the type of network access point that originated the audit event. + + + + + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + + + Logical source location within the healthcare enterprise network. + + + + + Identifier of the source where the event originated. + + + + + Code specifying the type of source where event originated. + + + + + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + + + Identifies a specific instance of the participant object. The reference should always be version specific. + + + + + Identifies a specific instance of the participant object. The reference should always be version specific. + + + + + Object type being audited. + + + + + Code representing the functional application role of Participant Object being audited. + + + + + Identifier for the data life-cycle stage for the participant object. + + + + + Denotes policy-defined sensitivity for the Participant Object ID such as VIP, HIV status, mental health status or similar topics. + + + + + An instance-specific descriptor of the Participant Object ID audited, such as a person's name. + + + + + Text that describes the object in more detail. + + + + + The actual query for a query-type participant object. + + + + + Additional Information about the Object. + + + + + + + + + A record of an event made for purposes of maintaining a security log. Typical uses include detection of intrusion attempts and monitoring for inappropriate usage. + + + + + + + Name of the property. + + + + + Property value. + + + + + + + + + + + This object is the patient that is the subject of care related to this event. It is identifiable by patient ID or equivalent. The patient may be either human or animal. + + + + + This is a location identified as related to the event. This is usually the location where the event took place. Note that for shipping, the usual events are arrival at a location or departure from a location. + + + + + This object is any kind of persistent document created as a result of the event. This could be a paper report, film, electronic report, DICOM Study, etc. Issues related to medical records life cycle management are conveyed elsewhere. + + + + + A logical object related to the event. (Deprecated). + + + + + This is any configurable file used to control creation of documents. Examples include the objects maintained by the HL7 Master File transactions, Value Sets, etc. + + + + + A human participant not otherwise identified by some other category. + + + + + (deprecated). + + + + + Typically a licensed person who is providing or performing care related to the event, generally a physician. The key distinction between doctor and practitioner is with regards to their role, not the licensing. The doctor is the human who actually performed the work. The practitioner is the human or organization that is responsible for the work. + + + + + A person or system that is being notified as part of the event. This is relevant in situations where automated systems provide notifications to other parties when an event took place. + + + + + Insurance company, or any other organization who accepts responsibility for paying for the healthcare event. + + + + + A person or active system object involved in the event with a security role. + + + + + A person or system object involved in the event with the authority to modify security roles of other objects. + + + + + A passive object, such as a role table, that is relevant to the event. + + + + + (deprecated) Relevant to certain RBAC security methodologies. + + + + + Any person or organization responsible for providing care. This encompasses all forms of care, licensed or otherwise, and all sorts of teams and care groups. Note, the distinction between practitioners and the doctor that actually provided the care to the patient. + + + + + The source or destination for data transfer, when it does not match some other role. + + + + + A source or destination for data transfer, that acts as an archive, database, or similar role. + + + + + An object that holds schedule information. This could be an appointment book, availability information, etc. + + + + + An organization or person that is the recipient of services. This could be an organization that is buying services for a patient, or a person that is buying services for an animal. + + + + + An order, task, work item, procedure step, or other description of work to be performed. E.g., a particular instance of an MPPS. + + + + + A list of jobs or a system that provides lists of jobs. E.g., an MWL SCP. + + + + + (Deprecated). + + + + + An object that specifies or controls the routing or delivery of items. For example, a distribution list is the routing criteria for mail. The items delivered may be documents, jobs, or other objects. + + + + + The contents of a query. This is used to capture the contents of any kind of query. For security surveillance purposes knowing the queries being made is very important. + + + + + + + Code representing the functional application role of Participant Object being audited + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Person. + + + + + System Object. + + + + + Organization. + + + + + Other. + + + + + + + Code for the participant object type being audited + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Create a new database object, such as Placing an Order. + + + + + Display or print data, such as a Doctor Census. + + + + + Update data, such as Revise Patient Information. + + + + + Delete items, such as a doctor master file record. + + + + + Perform a system or application function such as log-on, program execution or use of an object's method, or perform a query/search operation. + + + + + + + Indicator for type of action performed during the event that generated the audit. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Origination / Creation. + + + + + Import / Copy from original. + + + + + Amendment. + + + + + Verification. + + + + + Translation. + + + + + Access / Use. + + + + + De-identification. + + + + + Aggregation, summarization, derivation. + + + + + Report. + + + + + Export / Copy to target. + + + + + Disclosure. + + + + + Receipt of disclosure. + + + + + Archiving. + + + + + Logical deletion. + + + + + Permanent erasure / Physical destruction. + + + + + + + Identifier for the data life-cycle stage for the participant object + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Machine Name, including DNS name. + + + + + IP Address. + + + + + Telephone Number. + + + + + Email address. + + + + + URI (User directory, HTTP-PUT, ftp, etc.). + + + + + + + The type of network access point that originated the audit event + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + The operation completed successfully (whether with warnings or not). + + + + + The action was not successful due to some kind of catered for error (often equivalent to an HTTP 400 response). + + + + + The action was not successful due to some kind of unexpected error (often equivalent to an HTTP 500 response). + + + + + An error of such magnitude occurred that the system is not longer available for use (i.e. the system died). + + + + + + + Indicates whether the event succeeded or failed + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + Sample for analysis. + + + + + Sample for analysis. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Id for specimen. + + + + + Kind of material that forms the specimen. + + + + + Parent specimen from which the focal specimen was a component. + + + + + Where the specimen came from. This may be the patient(s) or from the environment or a device. + + + + + The identifier assigned by the lab when accessioning specimen(s). This is not necessarily the same as the specimen identifier, depending on local lab procedures. + + + + + Time when specimen was received for processing or testing. + + + + + Details concerning the specimen collection. + + + + + Details concerning treatment and processing steps for the specimen. + + + + + The container holding the specimen. The recursive nature of containers; i.e. blood in tube in tray in rack is not addressed here. + + + + + + + + + Sample for analysis. + + + + + + + Whether this relationship is to a parent or to a child. + + + + + The specimen resource that is the target of this relationship. + + + + + + + + + Sample for analysis. + + + + + + + Person who collected the specimen. + + + + + To communicate any details or issues encountered during the specimen collection procedure. + + + + + Time when specimen was collected from subject - the physiologically relevant time. + + + + + + + The quantity of specimen collected; for instance the volume of a blood sample, or the physical measurement of an anatomic pathology sample. + + + + + A coded value specifying the technique that is used to perform the procedure. + + + + + Anatomical location from which the specimen should be collected (if subject is a patient). This element is not used for environmental specimens. + + + + + + + + + Sample for analysis. + + + + + + + Textual description of procedure. + + + + + A coded value specifying the procedure used to process the specimen. + + + + + Material used in the processing step. + + + + + + + + + Sample for analysis. + + + + + + + Id for container. There may be multiple; a manufacturer's bar code, lab assigned identifier, etc. The container ID may differ from the specimen id in some circumstances. + + + + + Textual description of the container. + + + + + The type of container associated with the specimen (e.g. slide, aliquot, etc). + + + + + The capacity (volume or other measure) the container may contain. + + + + + The quantity of specimen in the container; may be volume, dimensions, or other appropriate measurements, depending on the specimen type. + + + + + Additive associated with the container. + + + + + + + + + + + The target resource is the parent of the focal specimen resource. + + + + + The target resource is the child of the focal specimen resource. + + + + + + + Type indicating if this is a parent or child relationship + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A homogeneous material with a definite composition. + + + + + A homogeneous material with a definite composition. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + A code (or set of codes) that identify this substance. + + + + + A description of the substance - its appearance, handling requirements, and other usage notes. + + + + + Substance may be used to describe a kind of substance, or a specific package/container of the substance: an instance. + + + + + A substance can be composed of other substances. + + + + + + + + + A homogeneous material with a definite composition. + + + + + + + Identifier associated with the package/container (usually a label affixed directly). + + + + + When the substance is no longer valid to use. For some substances, a single arbitrary date is used for expiry. + + + + + The amount of the substance. + + + + + + + + + A homogeneous material with a definite composition. + + + + + + + The amount of the ingredient in the substance - a concentration ratio. + + + + + Another substance that is a component of this substance. + + + + + + + + + A supply - a request for something, and provision of what is supplied. + + + + + A supply - a request for something, and provision of what is supplied. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + Category of supply, e.g. central, non-stock, etc. This is used to support work flows associated with the supply process. + + + + + Unique identifier for this supply request. + + + + + Status of the supply request. + + + + + The item that is requested to be supplied. + + + + + A link to a resource representing the person whom the ordered item is for. + + + + + Indicates the details of the dispense event such as the days supply and quantity of a supply dispensed. + + + + + + + + + A supply - a request for something, and provision of what is supplied. + + + + + + + Identifier assigned by the dispensing facility when the dispense occurs. + + + + + A code specifying the state of the dispense event. + + + + + Indicates the type of dispensing event that is performed. Examples include: Trial Fill, Completion of Trial, Partial Fill, Emergency Fill, Samples, etc. + + + + + The amount of supply that has been dispensed. Includes unit of measure. + + + + + Identifies the medication or substance being dispensed. This is either a link to a resource representing the details of the medication or substance or a simple attribute carrying a code that identifies the medication from a known list of medications. + + + + + The individual responsible for dispensing the medication. + + + + + The time the dispense event occurred. + + + + + The time the dispensed item was sent or handed to the patient (or agent). + + + + + Identification of the facility/location where the Supply was shipped to, as part of the dispense event. + + + + + Identifies the person who picked up the Supply. + + + + + + + + + + + Supply has been requested, but not dispensed. + + + + + Supply is part of a pharmacy order and has been dispensed. + + + + + Dispensing was not completed. + + + + + + + Status of the dispense + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + + + Supply has been requested, but not dispensed. + + + + + Supply is part of a pharmacy order and has been dispensed. + + + + + Supply has been received by the requestor. + + + + + The supply will not be completed because the supplier was unable or unwilling to supply the item. + + + + + The orderer of the supply cancelled the request. + + + + + + + Status of the supply + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + A value set specifies a set of codes drawn from one or more code systems. + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + The identifier that is used to identify this value set when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI). + + + + + The identifier that is used to identify this version of the value set when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp. + + + + + A free text natural language name describing the value set. + + + + + The name of the individual or organization that published the value set. + + + + + Contacts of the publisher to assist a user in finding and communicating with the publisher. + + + + + A free text natural language description of the use of the value set - reason for definition, conditions of use, etc. + + + + + A copyright statement relating to the value set and/or its contents. + + + + + The status of the value set. + + + + + This valueset was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage. + + + + + Whether this is intended to be used with an extensible binding or not. + + + + + The date that the value set status was last changed. + + + + + When value set defines its own codes. + + + + + When value set includes codes from elsewhere. + + + + + When value set is an expansion. + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + + + URI to identify the code system. + + + + + The version of this code system that defines the codes. Note that the version is optional because a well maintained code system does not suffer from versioning, and therefore the version does not need to be maintained. However many code systems are not well maintained, and the version needs to be defined and tracked. + + + + + If code comparison is case sensitive when codes within this system are compared to each other. + + + + + Concepts in the code system. + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + + + Code that identifies concept. + + + + + If this code is not for use as a real concept. + + + + + Text to Display to the user. + + + + + The formal definition of the concept. Formal definitions are not required, because of the prevalence of legacy systems without them, but they are highly recommended, as without them there is no formal meaning associated with the concept. + + + + + Child Concepts (is-a / contains). + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + + + Includes the contents of the referenced value set as a part of the contents of this value set. + + + + + Include one or more codes from a code system. + + + + + Exclude one or more codes from the value set. + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + + + The code system from which the selected codes come from. + + + + + The version of the code system that the codes are selected from. + + + + + Specifies a code or concept to be included or excluded. The list of codes is considered ordered, though the order may not have any particular significance. + + + + + Select concepts by specify a matching criteria based on the properties (including relationships) defined by the system. If multiple filters are specified, they SHALL all be true. + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + + + A code that identifies a property defined in the code system. + + + + + The kind of operation to perform as a part of the filter criteria. + + + + + The match value may be either a code defined by the system, or a string value which is used a regex match on the literal string of the property value. + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + + + An identifier that uniquely identifies this expansion of the valueset. Systems may re-use the same identifier as long as the expansion and the definition remain the same, but are not required to do so. + + + + + Time valueset expansion happened. + + + + + Codes in the value set. + + + + + + + + + A value set specifies a set of codes drawn from one or more code systems. + + + + + + + System value for the code. + + + + + Code - if blank, this is not a choosable code. + + + + + User display for the concept. + + + + + Codes contained in this concept. + + + + + + + + + + + The property value has the concept specified by the value. + + + + + The property value has a concept that has an is-a relationship with the value. + + + + + The property value has a concept that does not have an is-a relationship with the value. + + + + + The property value representation matches the regex specified in the value. + + + + + The property value is in the set of codes or concepts identified by the value. + + + + + The property value is not in the set of codes or concepts identified by the value. + + + + + + + The kind of operation to perform as a part of a property based filter + If the element is present, it must have either a @value, an @id, or extensions + + + + + + + + diff --git a/hapi-fhir-structures-dstu/src/test/resources/furore-conformance.json b/hapi-fhir-structures-dstu/src/test/resources/furore-conformance.json new file mode 100644 index 00000000000..c31db15391b --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/furore-conformance.json @@ -0,0 +1 @@ +{"resourceType":"Conformance","text":{"status":"generated","div":"
\r\n

The server supports all operations on the AdverseReaction resource, including history

\r\n

The server supports all operations on the Alert resource, including history

\r\n

The server supports all operations on the AllergyIntolerance resource, including history

\r\n

The server supports all operations on the Appointment resource, including history

\r\n

The server supports all operations on the AppointmentResponse resource, including history

\r\n

The server supports all operations on the Availability resource, including history

\r\n

The server supports all operations on the CarePlan resource, including history

\r\n

The server supports all operations on the Composition resource, including history

\r\n

The server supports all operations on the ConceptMap resource, including history

\r\n

The server supports all operations on the Condition resource, including history

\r\n

The server supports all operations on the Conformance resource, including history

\r\n

The server supports all operations on the Device resource, including history

\r\n

The server supports all operations on the DeviceObservationReport resource, including history

\r\n

The server supports all operations on the DiagnosticOrder resource, including history

\r\n

The server supports all operations on the DiagnosticReport resource, including history

\r\n

The server supports all operations on the DocumentManifest resource, including history

\r\n

The server supports all operations on the DocumentReference resource, including history

\r\n

The server supports all operations on the Encounter resource, including history

\r\n

The server supports all operations on the FamilyHistory resource, including history

\r\n

The server supports all operations on the Group resource, including history

\r\n

The server supports all operations on the ImagingStudy resource, including history

\r\n

The server supports all operations on the Immunization resource, including history

\r\n

The server supports all operations on the ImmunizationRecommendation resource, including history

\r\n

The server supports all operations on the List resource, including history

\r\n

The server supports all operations on the Location resource, including history

\r\n

The server supports all operations on the Media resource, including history

\r\n

The server supports all operations on the Medication resource, including history

\r\n

The server supports all operations on the MedicationAdministration resource, including history

\r\n

The server supports all operations on the MedicationDispense resource, including history

\r\n

The server supports all operations on the MedicationPrescription resource, including history

\r\n

The server supports all operations on the MedicationStatement resource, including history

\r\n

The server supports all operations on the MessageHeader resource, including history

\r\n

The server supports all operations on the Observation resource, including history

\r\n

The server supports all operations on the OperationOutcome resource, including history

\r\n

The server supports all operations on the Order resource, including history

\r\n

The server supports all operations on the OrderResponse resource, including history

\r\n

The server supports all operations on the Organization resource, including history

\r\n

The server supports all operations on the Other resource, including history

\r\n

The server supports all operations on the Patient resource, including history

\r\n

The server supports all operations on the Practitioner resource, including history

\r\n

The server supports all operations on the Procedure resource, including history

\r\n

The server supports all operations on the Profile resource, including history

\r\n

The server supports all operations on the Provenance resource, including history

\r\n

The server supports all operations on the Query resource, including history

\r\n

The server supports all operations on the Questionnaire resource, including history

\r\n

The server supports all operations on the RelatedPerson resource, including history

\r\n

The server supports all operations on the SecurityEvent resource, including history

\r\n

The server supports all operations on the Slot resource, including history

\r\n

The server supports all operations on the Specimen resource, including history

\r\n

The server supports all operations on the Substance resource, including history

\r\n

The server supports all operations on the Supply resource, including history

\r\n

The server supports all operations on the ValueSet resource, including history

\r\n

The server supports all operations on the Binary resource, including history

\r\n
"},"name":"Spark FHIR demo server","publisher":"Furore","telecom":[{"system":"email","value":"e.kramer@furore.com","use":"work"}],"description":"Conformance statement for the Spark FHIR demo server running at AppHarbor","date":"2014-03-28","software":{"name":"Spark.Service","version":"1.0.0.0"},"implementation":{"description":"Furore Spark FHIR demo server running at AppHarbor","url":"http://spark.furore.com/"},"fhirVersion":"0.12","acceptUnknown":false,"format":["xml","json"],"rest":[{"mode":"server","documentation":"Publicly available, no security, use only for TESTING.","resource":[{"type":"AdverseReaction","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["substance","subject"],"searchParam":[{"name":"substance","source":"http://hl7.org/fhir/adversereaction/search#substance","type":"reference","documentation":"The name or code of the substance that produces the sensitivity","xpath":"AdverseReaction.exposure.substance"},{"name":"_id","source":"http://hl7.org/fhir/adversereaction/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/adversereaction/search#subject","type":"reference","documentation":"The subject that the sensitivity is about","xpath":"AdverseReaction.subject"},{"name":"date","source":"http://hl7.org/fhir/adversereaction/search#date","type":"date","documentation":"The date of the reaction","xpath":"AdverseReaction.date"},{"name":"symptom","source":"http://hl7.org/fhir/adversereaction/search#symptom","type":"token","documentation":"One of the symptoms of the reaction","xpath":"AdverseReaction.symptom.code"}]},{"type":"Alert","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/alert/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/alert/search#subject","type":"reference","documentation":"The identity of a subject to list alerts for","xpath":"Alert.subject"}]},{"type":"AllergyIntolerance","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["substance","recorder","subject"],"searchParam":[{"name":"substance","source":"http://hl7.org/fhir/allergyintolerance/search#substance","type":"reference","documentation":"The name or code of the substance that produces the sensitivity","xpath":"AllergyIntolerance.substance"},{"name":"_id","source":"http://hl7.org/fhir/allergyintolerance/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/allergyintolerance/search#status","type":"token","documentation":"The status of the sensitivity","xpath":"AllergyIntolerance.status"},{"name":"recorder","source":"http://hl7.org/fhir/allergyintolerance/search#recorder","type":"reference","documentation":"Who recorded the sensitivity","xpath":"AllergyIntolerance.recorder"},{"name":"subject","source":"http://hl7.org/fhir/allergyintolerance/search#subject","type":"reference","documentation":"The subject that the sensitivity is about","xpath":"AllergyIntolerance.subject"},{"name":"date","source":"http://hl7.org/fhir/allergyintolerance/search#date","type":"date","documentation":"Recorded date/time.","xpath":"AllergyIntolerance.recordedDate"},{"name":"type","source":"http://hl7.org/fhir/allergyintolerance/search#type","type":"token","documentation":"The type of sensitivity","xpath":"AllergyIntolerance.sensitivityType"}]},{"type":"Appointment","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject"],"searchParam":[{"name":"partstatus","source":"http://hl7.org/fhir/appointment/search#partstatus","type":"token","documentation":"The Participation status of the subject, or other participant on the appointment","xpath":"Appointment.participant.status"},{"name":"_id","source":"http://hl7.org/fhir/appointment/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/appointment/search#status","type":"string","documentation":"The overall status of the appointment","xpath":"Appointment.status"},{"name":"subject","source":"http://hl7.org/fhir/appointment/search#subject","type":"reference","documentation":"The subject that the sensitivity is about","xpath":"Appointment.participant.individual"},{"name":"date","source":"http://hl7.org/fhir/appointment/search#date","type":"date","documentation":"Appointment date/time.","xpath":"Appointment.start"}]},{"type":"AppointmentResponse","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject","appointment"],"searchParam":[{"name":"partstatus","source":"http://hl7.org/fhir/appointmentresponse/search#partstatus","type":"string","documentation":"The overall status of the appointment","xpath":"AppointmentResponse.participantStatus"},{"name":"_id","source":"http://hl7.org/fhir/appointmentresponse/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/appointmentresponse/search#subject","type":"reference","documentation":"The subject that the appointment response replies for","xpath":"AppointmentResponse.individual"},{"name":"appointment","source":"http://hl7.org/fhir/appointmentresponse/search#appointment","type":"reference","documentation":"The appointment that the response is attached to","xpath":"AppointmentResponse.appointment"}]},{"type":"Availability","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["individual"],"searchParam":[{"name":"individual","source":"http://hl7.org/fhir/availability/search#individual","type":"reference","documentation":"The individual to find an availability for","xpath":"Availability.individual"},{"name":"_id","source":"http://hl7.org/fhir/availability/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"slottype","source":"http://hl7.org/fhir/availability/search#slottype","type":"token","documentation":"The type of appointments that can be booked into associated slot(s)","xpath":"Availability.type"}]},{"type":"CarePlan","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["patient","condition","activitydetail","participant"],"searchParam":[{"name":"activitycode","source":"http://hl7.org/fhir/careplan/search#activitycode","type":"token","documentation":"Detail type of activity","xpath":"CarePlan.activity.simple.code"},{"name":"patient","source":"http://hl7.org/fhir/careplan/search#patient","type":"reference","documentation":"Who care plan is for","xpath":"CarePlan.patient"},{"name":"_id","source":"http://hl7.org/fhir/careplan/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"condition","source":"http://hl7.org/fhir/careplan/search#condition","type":"reference","documentation":"Health issues this plan addresses","xpath":"CarePlan.concern"},{"name":"activitydetail","source":"http://hl7.org/fhir/careplan/search#activitydetail","type":"reference","documentation":"Activity details defined in specific resource","xpath":"CarePlan.activity.detail"},{"name":"activitydate","source":"http://hl7.org/fhir/careplan/search#activitydate","type":"date","documentation":"Specified date occurs within period specified by CarePlan.activity.timingSchedule","xpath":"CarePlan.activity.simple.timing[x]"},{"name":"participant","source":"http://hl7.org/fhir/careplan/search#participant","type":"reference","documentation":"Who is involved","xpath":"CarePlan.participant.member"},{"name":"date","source":"http://hl7.org/fhir/careplan/search#date","type":"date","documentation":"Time period plan covers","xpath":"CarePlan.period"}]},{"type":"Composition","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["author","attester","subject","section-content"],"searchParam":[{"name":"author","source":"http://hl7.org/fhir/composition/search#author","type":"reference","documentation":"Who/what authored the composition","xpath":"Composition.author"},{"name":"_id","source":"http://hl7.org/fhir/composition/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"attester","source":"http://hl7.org/fhir/composition/search#attester","type":"reference","documentation":"Who attested the composition","xpath":"Composition.attester.party"},{"name":"subject","source":"http://hl7.org/fhir/composition/search#subject","type":"reference","documentation":"Who/what the composition is about","xpath":"Composition.subject"},{"name":"section-content","source":"http://hl7.org/fhir/composition/search#section-content","type":"reference","documentation":"The actual data for the section","xpath":"Composition.section.content"},{"name":"context","source":"http://hl7.org/fhir/composition/search#context","type":"token","documentation":"Code(s) that apply to the event being documented","xpath":"Composition.event.code"},{"name":"class","source":"http://hl7.org/fhir/composition/search#class","type":"token","documentation":"Categorisation of Composition","xpath":"Composition.class"},{"name":"section-type","source":"http://hl7.org/fhir/composition/search#section-type","type":"token","documentation":"Classification of section (recommended)","xpath":"Composition.section.code"},{"name":"type","source":"http://hl7.org/fhir/composition/search#type","type":"token","documentation":"Kind of composition (LOINC if possible)","xpath":"Composition.type"},{"name":"identifier","source":"http://hl7.org/fhir/composition/search#identifier","type":"token","documentation":"Logical identifier of composition (version-independent)","xpath":"Composition.identifier"},{"name":"instant","source":"http://hl7.org/fhir/composition/search#instant","type":"date","documentation":"Composition editing time","xpath":"Composition.instant"}]},{"type":"ConceptMap","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["source","target"],"searchParam":[{"name":"product","source":"http://hl7.org/fhir/conceptmap/search#product","type":"token","documentation":"Reference to element/field/valueset provides the context","xpath":"ConceptMap.concept.map.product.concept"},{"name":"dependson","source":"http://hl7.org/fhir/conceptmap/search#dependson","type":"token","documentation":"Reference to element/field/valueset provides the context","xpath":"ConceptMap.concept.dependsOn.concept"},{"name":"system","source":"http://hl7.org/fhir/conceptmap/search#system","type":"token","documentation":"The system for any destination concepts mapped by this map","xpath":"ConceptMap.concept.map.system"},{"name":"source","source":"http://hl7.org/fhir/conceptmap/search#source","type":"reference","documentation":"The system for any concepts mapped by this concept map","xpath":"ConceptMap.source"},{"name":"_id","source":"http://hl7.org/fhir/conceptmap/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/conceptmap/search#status","type":"token","documentation":"Status of the concept map","xpath":"ConceptMap.status"},{"name":"description","source":"http://hl7.org/fhir/conceptmap/search#description","type":"string","documentation":"Text search in the description of the concept map","xpath":"ConceptMap.description"},{"name":"name","source":"http://hl7.org/fhir/conceptmap/search#name","type":"string","documentation":"Name of the concept map","xpath":"ConceptMap.name"},{"name":"target","source":"http://hl7.org/fhir/conceptmap/search#target","type":"reference","documentation":"Provides context to the mappings","xpath":"ConceptMap.target"},{"name":"date","source":"http://hl7.org/fhir/conceptmap/search#date","type":"date","documentation":"The concept map publication date","xpath":"ConceptMap.date"},{"name":"identifier","source":"http://hl7.org/fhir/conceptmap/search#identifier","type":"token","documentation":"The identifier of the concept map","xpath":"ConceptMap.identifier"},{"name":"publisher","source":"http://hl7.org/fhir/conceptmap/search#publisher","type":"string","documentation":"Name of the publisher of the concept map","xpath":"ConceptMap.publisher"},{"name":"version","source":"http://hl7.org/fhir/conceptmap/search#version","type":"token","documentation":"The version identifier of the concept map","xpath":"ConceptMap.version"}]},{"type":"Condition","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["asserter","subject","encounter","related-item"],"searchParam":[{"name":"asserter","source":"http://hl7.org/fhir/condition/search#asserter","type":"reference","documentation":"Person who asserts this condition","xpath":"Condition.asserter"},{"name":"status","source":"http://hl7.org/fhir/condition/search#status","type":"token","documentation":"The status of the condition","xpath":"Condition.status"},{"name":"location","source":"http://hl7.org/fhir/condition/search#location","type":"token","documentation":"Location - may include laterality","xpath":"Condition.location.code"},{"name":"subject","source":"http://hl7.org/fhir/condition/search#subject","type":"reference","documentation":"Who has the condition?","xpath":"Condition.subject"},{"name":"onset","source":"http://hl7.org/fhir/condition/search#onset","type":"date","documentation":"When the Condition started (if started on a date)","xpath":"Condition.onset[x]"},{"name":"evidence","source":"http://hl7.org/fhir/condition/search#evidence","type":"token","documentation":"Manifestation/symptom","xpath":"Condition.evidence.code"},{"name":"severity","source":"http://hl7.org/fhir/condition/search#severity","type":"token","documentation":"The severity of the condition","xpath":"Condition.severity"},{"name":"code","source":"http://hl7.org/fhir/condition/search#code","type":"token","documentation":"Code for the condition","xpath":"Condition.code"},{"name":"encounter","source":"http://hl7.org/fhir/condition/search#encounter","type":"reference","documentation":"Encounter when condition first asserted","xpath":"Condition.encounter"},{"name":"date-asserted","source":"http://hl7.org/fhir/condition/search#date-asserted","type":"date","documentation":"When first detected/suspected/entered","xpath":"Condition.dateAsserted"},{"name":"stage","source":"http://hl7.org/fhir/condition/search#stage","type":"token","documentation":"Simple summary (disease specific)","xpath":"Condition.stage.summary"},{"name":"related-code","source":"http://hl7.org/fhir/condition/search#related-code","type":"token","documentation":"Relationship target by means of a predefined code","xpath":"Condition.relatedItem.code"},{"name":"category","source":"http://hl7.org/fhir/condition/search#category","type":"token","documentation":"The category of the condition","xpath":"Condition.category"},{"name":"_id","source":"http://hl7.org/fhir/condition/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"related-item","source":"http://hl7.org/fhir/condition/search#related-item","type":"reference","documentation":"Relationship target resource","xpath":"Condition.relatedItem.target"}]},{"type":"Conformance","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["supported-profile","profile"],"searchParam":[{"name":"status","source":"http://hl7.org/fhir/conformance/search#status","type":"token","documentation":"The current status of the conformance statement","xpath":"Conformance.status"},{"name":"resource","source":"http://hl7.org/fhir/conformance/search#resource","type":"token","documentation":"Name of a resource mentioned in a conformance statement","xpath":"Conformance.rest.resource.type"},{"name":"security","source":"http://hl7.org/fhir/conformance/search#security","type":"token","documentation":"Information about security of implementation","xpath":"Conformance.rest.security"},{"name":"format","source":"http://hl7.org/fhir/conformance/search#format","type":"token","documentation":"formats supported (xml | json | mime type)","xpath":"Conformance.format"},{"name":"date","source":"http://hl7.org/fhir/conformance/search#date","type":"date","documentation":"The conformance statement publication date","xpath":"Conformance.date"},{"name":"mode","source":"http://hl7.org/fhir/conformance/search#mode","type":"token","documentation":"Mode - restful (server/client) or messaging (sender/receiver)","xpath":"Conformance.rest.mode"},{"name":"version","source":"http://hl7.org/fhir/conformance/search#version","type":"token","documentation":"The version identifier of the conformance statement","xpath":"Conformance.version"},{"name":"publisher","source":"http://hl7.org/fhir/conformance/search#publisher","type":"string","documentation":"Name of the publisher of the conformance statement","xpath":"Conformance.publisher"},{"name":"software","source":"http://hl7.org/fhir/conformance/search#software","type":"string","documentation":"Part of a the name of a software application","xpath":"Conformance.software.name"},{"name":"_id","source":"http://hl7.org/fhir/conformance/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"description","source":"http://hl7.org/fhir/conformance/search#description","type":"string","documentation":"Text search in the description of the conformance statement","xpath":"Conformance.description"},{"name":"event","source":"http://hl7.org/fhir/conformance/search#event","type":"token","documentation":"Event code in a conformance statement","xpath":"Conformance.messaging.event.code"},{"name":"name","source":"http://hl7.org/fhir/conformance/search#name","type":"string","documentation":"Name of the conformance statement","xpath":"Conformance.name"},{"name":"supported-profile","source":"http://hl7.org/fhir/conformance/search#supported-profile","type":"reference","documentation":"Profiles supported by the system","xpath":"Conformance.profile"},{"name":"fhirversion","source":"http://hl7.org/fhir/conformance/search#fhirversion","type":"token","documentation":"The version of FHIR","xpath":"Conformance.version"},{"name":"identifier","source":"http://hl7.org/fhir/conformance/search#identifier","type":"token","documentation":"The identifier of the conformance statement","xpath":"Conformance.identifier"},{"name":"profile","source":"http://hl7.org/fhir/conformance/search#profile","type":"reference","documentation":"A profile id invoked in a conformance statement","xpath":"Conformance.rest.resource.profile"}]},{"type":"Device","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["organization","patient","location"],"searchParam":[{"name":"organization","source":"http://hl7.org/fhir/device/search#organization","type":"reference","documentation":"The organization responsible for the device","xpath":"Device.owner"},{"name":"model","source":"http://hl7.org/fhir/device/search#model","type":"string","documentation":"The model of the device","xpath":"Device.model"},{"name":"patient","source":"http://hl7.org/fhir/device/search#patient","type":"reference","documentation":"If the resource is affixed to a person","xpath":"Device.patient"},{"name":"_id","source":"http://hl7.org/fhir/device/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"location","source":"http://hl7.org/fhir/device/search#location","type":"reference","documentation":"Where the resource is found","xpath":"Device.location"},{"name":"manufacturer","source":"http://hl7.org/fhir/device/search#manufacturer","type":"string","documentation":"The manufacturer of the device","xpath":"Device.manufacturer"},{"name":"udi","source":"http://hl7.org/fhir/device/search#udi","type":"string","documentation":"FDA Mandated Unique Device Identifier","xpath":"Device.udi"},{"name":"type","source":"http://hl7.org/fhir/device/search#type","type":"token","documentation":"The type of the device","xpath":"Device.type"},{"name":"identifier","source":"http://hl7.org/fhir/device/search#identifier","type":"token","documentation":"Instance id from manufacturer, owner and others","xpath":"Device.identifier"}]},{"type":"DeviceObservationReport","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["observation","source","subject"],"searchParam":[{"name":"observation","source":"http://hl7.org/fhir/deviceobservationreport/search#observation","type":"reference","documentation":"The data for the metric","xpath":"DeviceObservationReport.virtualDevice.channel.metric.observation"},{"name":"source","source":"http://hl7.org/fhir/deviceobservationreport/search#source","type":"reference","documentation":"Identifies/describes where the data came from","xpath":"DeviceObservationReport.source"},{"name":"_id","source":"http://hl7.org/fhir/deviceobservationreport/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/deviceobservationreport/search#subject","type":"reference","documentation":"Subject of the measurement","xpath":"DeviceObservationReport.subject"},{"name":"code","source":"http://hl7.org/fhir/deviceobservationreport/search#code","type":"token","documentation":"The compatment code","xpath":"DeviceObservationReport.virtualDevice.code"},{"name":"channel","source":"http://hl7.org/fhir/deviceobservationreport/search#channel","type":"token","documentation":"The channel code","xpath":"DeviceObservationReport.virtualDevice.channel.code"}]},{"type":"DiagnosticOrder","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["orderer","subject","actor","encounter","specimen"],"searchParam":[{"name":"orderer","source":"http://hl7.org/fhir/diagnosticorder/search#orderer","type":"reference","documentation":"Who ordered the test","xpath":"DiagnosticOrder.orderer"},{"name":"status","source":"http://hl7.org/fhir/diagnosticorder/search#status","type":"token","documentation":"requested | received | accepted | in progress | review | completed | suspended | rejected | failed","xpath":"DiagnosticOrder.status"},{"name":"subject","source":"http://hl7.org/fhir/diagnosticorder/search#subject","type":"reference","documentation":"Who/what test is about","xpath":"DiagnosticOrder.subject"},{"name":"item-status","source":"http://hl7.org/fhir/diagnosticorder/search#item-status","type":"token","documentation":"requested | received | accepted | in progress | review | completed | suspended | rejected | failed","xpath":"DiagnosticOrder.item.status"},{"name":"event-status","source":"http://hl7.org/fhir/diagnosticorder/search#event-status","type":"token","documentation":"requested | received | accepted | in progress | review | completed | suspended | rejected | failed","xpath":"DiagnosticOrder.event.status"},{"name":"actor","source":"http://hl7.org/fhir/diagnosticorder/search#actor","type":"reference","documentation":"Who recorded or did this","xpath":"DiagnosticOrder.event.actor,DiagnosticOrder.item.event.actor"},{"name":"code","source":"http://hl7.org/fhir/diagnosticorder/search#code","type":"token","documentation":"Code to indicate the item (test or panel) being ordered","xpath":"DiagnosticOrder.item.code"},{"name":"encounter","source":"http://hl7.org/fhir/diagnosticorder/search#encounter","type":"reference","documentation":"The encounter that this diagnostic order is associated with","xpath":"DiagnosticOrder.encounter"},{"name":"item-past-status","source":"http://hl7.org/fhir/diagnosticorder/search#item-past-status","type":"token","documentation":"requested | received | accepted | in progress | review | completed | suspended | rejected | failed","xpath":"DiagnosticOrder.item.event.status"},{"name":"_id","source":"http://hl7.org/fhir/diagnosticorder/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"bodysite","source":"http://hl7.org/fhir/diagnosticorder/search#bodysite","type":"token","documentation":"Location of requested test (if applicable)","xpath":"DiagnosticOrder.item.bodySite"},{"name":"item-date","source":"http://hl7.org/fhir/diagnosticorder/search#item-date","type":"date","documentation":"The date at which the event happened","xpath":"DiagnosticOrder.item.event.dateTime"},{"name":"specimen","source":"http://hl7.org/fhir/diagnosticorder/search#specimen","type":"reference","documentation":"If the whole order relates to specific specimens","xpath":"DiagnosticOrder.specimen,DiagnosticOrder.item.specimen"},{"name":"event-status-date","source":"http://hl7.org/fhir/diagnosticorder/search#event-status-date","type":"composite","documentation":"A combination of past-status and date"},{"name":"event-date","source":"http://hl7.org/fhir/diagnosticorder/search#event-date","type":"date","documentation":"The date at which the event happened","xpath":"DiagnosticOrder.event.dateTime"},{"name":"identifier","source":"http://hl7.org/fhir/diagnosticorder/search#identifier","type":"token","documentation":"Identifiers assigned to this order","xpath":"DiagnosticOrder.identifier"},{"name":"item-status-date","source":"http://hl7.org/fhir/diagnosticorder/search#item-status-date","type":"composite","documentation":"A combination of item-past-status and item-date"}]},{"type":"DiagnosticReport","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["result","subject","image","request","specimen","performer"],"searchParam":[{"name":"result","source":"http://hl7.org/fhir/diagnosticreport/search#result","type":"reference","documentation":"Link to an atomic result (observation resource)","xpath":"DiagnosticReport.results.result,DiagnosticReport.results.group.result"},{"name":"status","source":"http://hl7.org/fhir/diagnosticreport/search#status","type":"token","documentation":"The status of the report","xpath":"DiagnosticReport.status"},{"name":"subject","source":"http://hl7.org/fhir/diagnosticreport/search#subject","type":"reference","documentation":"The subject of the report","xpath":"DiagnosticReport.subject"},{"name":"issued","source":"http://hl7.org/fhir/diagnosticreport/search#issued","type":"date","documentation":"When the report was issued","xpath":"DiagnosticReport.issued"},{"name":"diagnosis","source":"http://hl7.org/fhir/diagnosticreport/search#diagnosis","type":"token","documentation":"A coded diagnosis on the report","xpath":"DiagnosticReport.codedDiagnosis"},{"name":"image","source":"http://hl7.org/fhir/diagnosticreport/search#image","type":"reference","documentation":"Reference to the image source","xpath":"DiagnosticReport.image.link"},{"name":"date","source":"http://hl7.org/fhir/diagnosticreport/search#date","type":"date","documentation":"The clinically relevant time of the report","xpath":"DiagnosticReport.diagnostic[x]"},{"name":"_id","source":"http://hl7.org/fhir/diagnosticreport/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"request","source":"http://hl7.org/fhir/diagnosticreport/search#request","type":"reference","documentation":"What was requested","xpath":"DiagnosticReport.requestDetail"},{"name":"specimen","source":"http://hl7.org/fhir/diagnosticreport/search#specimen","type":"reference","documentation":"The specimen details","xpath":"DiagnosticReport.results.specimen,DiagnosticReport.results.group.specimen"},{"name":"name","source":"http://hl7.org/fhir/diagnosticreport/search#name","type":"token","documentation":"The name of the report (e.g. the code for the report as a whole, as opposed to codes for the atomic results, which are the names on the observation resource referred to from the result)","xpath":"DiagnosticReport.results.name"},{"name":"service","source":"http://hl7.org/fhir/diagnosticreport/search#service","type":"token","documentation":"Which diagnostic discipline/department created the report","xpath":"DiagnosticReport.serviceCategory"},{"name":"performer","source":"http://hl7.org/fhir/diagnosticreport/search#performer","type":"reference","documentation":"Who was the source of the report (organization)","xpath":"DiagnosticReport.performer"},{"name":"group","source":"http://hl7.org/fhir/diagnosticreport/search#group","type":"token","documentation":"Name /code of a group in the report"},{"name":"identifier","source":"http://hl7.org/fhir/diagnosticreport/search#identifier","type":"token","documentation":"An identifier for the report","xpath":"DiagnosticReport.identifier"}]},{"type":"DocumentManifest","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["content","author","supersedes","subject","recipient"],"searchParam":[{"name":"content","source":"http://hl7.org/fhir/documentmanifest/search#content","type":"reference","documentation":"Contents of this set of documents","xpath":"DocumentManifest.content"},{"name":"author","source":"http://hl7.org/fhir/documentmanifest/search#author","type":"reference","documentation":"Who/what authored the document","xpath":"DocumentManifest.author"},{"name":"supersedes","source":"http://hl7.org/fhir/documentmanifest/search#supersedes","type":"reference","documentation":"If this document manifest replaces another","xpath":"DocumentManifest.supercedes"},{"name":"_id","source":"http://hl7.org/fhir/documentmanifest/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/documentmanifest/search#status","type":"token","documentation":"current | superceded | entered in error","xpath":"DocumentManifest.status"},{"name":"created","source":"http://hl7.org/fhir/documentmanifest/search#created","type":"date","documentation":"When this document manifest created","xpath":"DocumentManifest.created"},{"name":"confidentiality","source":"http://hl7.org/fhir/documentmanifest/search#confidentiality","type":"token","documentation":"Sensitivity of set of documents","xpath":"DocumentManifest.confidentiality"},{"name":"description","source":"http://hl7.org/fhir/documentmanifest/search#description","type":"string","documentation":"Human-readable description (title)","xpath":"DocumentManifest.description"},{"name":"subject","source":"http://hl7.org/fhir/documentmanifest/search#subject","type":"reference","documentation":"The subject of the set of documents","xpath":"DocumentManifest.subject"},{"name":"type","source":"http://hl7.org/fhir/documentmanifest/search#type","type":"token","documentation":"What kind of document set this is","xpath":"DocumentManifest.type"},{"name":"identifier","source":"http://hl7.org/fhir/documentmanifest/search#identifier","type":"token","documentation":"Unique Identifier for the set of documents","xpath":"DocumentManifest.masterIdentifier,DocumentManifest.identifier"},{"name":"recipient","source":"http://hl7.org/fhir/documentmanifest/search#recipient","type":"reference","documentation":"Intended to get notified about this set of documents","xpath":"DocumentManifest.recipient"}]},{"type":"DocumentReference","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject","relatesto","authenticator","author","custodian"],"searchParam":[{"name":"location","source":"http://hl7.org/fhir/documentreference/search#location","type":"string","documentation":"Where to access the document","xpath":"DocumentReference.location"},{"name":"indexed","source":"http://hl7.org/fhir/documentreference/search#indexed","type":"date","documentation":"When this document reference created","xpath":"DocumentReference.indexed"},{"name":"status","source":"http://hl7.org/fhir/documentreference/search#status","type":"token","documentation":"current | superceded | entered in error","xpath":"DocumentReference.status"},{"name":"subject","source":"http://hl7.org/fhir/documentreference/search#subject","type":"reference","documentation":"Who|what is the subject of the document","xpath":"DocumentReference.subject"},{"name":"relatesto","source":"http://hl7.org/fhir/documentreference/search#relatesto","type":"reference","documentation":"Target of the relationship","xpath":"DocumentReference.relatesTo.target"},{"name":"relation","source":"http://hl7.org/fhir/documentreference/search#relation","type":"token","documentation":"replaces | transforms | signs | appends","xpath":"DocumentReference.relatesTo.code"},{"name":"class","source":"http://hl7.org/fhir/documentreference/search#class","type":"token","documentation":"Categorisation of Document","xpath":"DocumentReference.class"},{"name":"format","source":"http://hl7.org/fhir/documentreference/search#format","type":"token","documentation":"Format/content rules for the document","xpath":"DocumentReference.format"},{"name":"period","source":"http://hl7.org/fhir/documentreference/search#period","type":"date","documentation":"Time of service that is being documented","xpath":"DocumentReference.context.period"},{"name":"type","source":"http://hl7.org/fhir/documentreference/search#type","type":"token","documentation":"What kind of document this is (LOINC if possible)","xpath":"DocumentReference.type"},{"name":"authenticator","source":"http://hl7.org/fhir/documentreference/search#authenticator","type":"reference","documentation":"Who/What authenticated the document","xpath":"DocumentReference.authenticator"},{"name":"size","source":"http://hl7.org/fhir/documentreference/search#size","type":"number","documentation":"Size of the document in bytes","xpath":"DocumentReference.size"},{"name":"relationship","source":"http://hl7.org/fhir/documentreference/search#relationship","type":"composite","documentation":"Combination of relation and relatesTo"},{"name":"author","source":"http://hl7.org/fhir/documentreference/search#author","type":"reference","documentation":"Who/what authored the document","xpath":"DocumentReference.author"},{"name":"custodian","source":"http://hl7.org/fhir/documentreference/search#custodian","type":"reference","documentation":"Org which maintains the document","xpath":"DocumentReference.custodian"},{"name":"facility","source":"http://hl7.org/fhir/documentreference/search#facility","type":"token","documentation":"Kind of facility where patient was seen","xpath":"DocumentReference.context.facilityType"},{"name":"_id","source":"http://hl7.org/fhir/documentreference/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"created","source":"http://hl7.org/fhir/documentreference/search#created","type":"date","documentation":"Document creation time","xpath":"DocumentReference.created"},{"name":"event","source":"http://hl7.org/fhir/documentreference/search#event","type":"token","documentation":"Main Clinical Acts Documented","xpath":"DocumentReference.context.event"},{"name":"confidentiality","source":"http://hl7.org/fhir/documentreference/search#confidentiality","type":"token","documentation":"Sensitivity of source document","xpath":"DocumentReference.confidentiality"},{"name":"description","source":"http://hl7.org/fhir/documentreference/search#description","type":"string","documentation":"Human-readable description (title)","xpath":"DocumentReference.description"},{"name":"language","source":"http://hl7.org/fhir/documentreference/search#language","type":"token","documentation":"The marked primary language for the document","xpath":"DocumentReference.primaryLanguage"},{"name":"identifier","source":"http://hl7.org/fhir/documentreference/search#identifier","type":"token","documentation":"Master Version Specific Identifier","xpath":"DocumentReference.masterIdentifier,DocumentReference.identifier"}]},{"type":"Encounter","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["location","subject","indication"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/encounter/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"location","source":"http://hl7.org/fhir/encounter/search#location","type":"reference","documentation":"The location the encounter takes place","xpath":"Encounter.location.location"},{"name":"status","source":"http://hl7.org/fhir/encounter/search#status","type":"token","documentation":"planned | in progress | onleave | finished | cancelled","xpath":"Encounter.status"},{"name":"subject","source":"http://hl7.org/fhir/encounter/search#subject","type":"reference","documentation":"The patient present at the encounter","xpath":"Encounter.subject"},{"name":"indication","source":"http://hl7.org/fhir/encounter/search#indication","type":"reference","documentation":"Reason the encounter takes place (resource)","xpath":"Encounter.indication"},{"name":"length","source":"http://hl7.org/fhir/encounter/search#length","type":"number","documentation":"Length of encounter in days","xpath":"Encounter.length"},{"name":"date","source":"http://hl7.org/fhir/encounter/search#date","type":"date","documentation":"A date within the period the Encounter lasted","xpath":"Encounter.period"},{"name":"identifier","source":"http://hl7.org/fhir/encounter/search#identifier","type":"token","documentation":"Identifier(s) by which this encounter is known","xpath":"Encounter.identifier"},{"name":"location-period","source":"http://hl7.org/fhir/encounter/search#location-period","type":"date","documentation":"Time period during which the patient was present at the location","xpath":"Encounter.location.period"}]},{"type":"FamilyHistory","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/familyhistory/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/familyhistory/search#subject","type":"reference","documentation":"The identity of a subject to list family history items for","xpath":"FamilyHistory.subject"}]},{"type":"Group","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["member"],"searchParam":[{"name":"member","source":"http://hl7.org/fhir/group/search#member","type":"reference","documentation":"Who is in group","xpath":"Group.member"},{"name":"_id","source":"http://hl7.org/fhir/group/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"characteristic-value","source":"http://hl7.org/fhir/group/search#characteristic-value","type":"composite","documentation":"A composite of both characteristic and value"},{"name":"value","source":"http://hl7.org/fhir/group/search#value","type":"token","documentation":"Value held by characteristic","xpath":"Group.characteristic.value[x]"},{"name":"actual","source":"http://hl7.org/fhir/group/search#actual","type":"token","documentation":"Descriptive or actual","xpath":"Group.actual"},{"name":"exclude","source":"http://hl7.org/fhir/group/search#exclude","type":"token","documentation":"Group includes or excludes","xpath":"Group.characteristic.exclude"},{"name":"code","source":"http://hl7.org/fhir/group/search#code","type":"token","documentation":"The kind of resources contained","xpath":"Group.code"},{"name":"characteristic","source":"http://hl7.org/fhir/group/search#characteristic","type":"token","documentation":"Kind of characteristic","xpath":"Group.characteristic.code"},{"name":"type","source":"http://hl7.org/fhir/group/search#type","type":"token","documentation":"The type of resources the group contains","xpath":"Group.type"},{"name":"identifier","source":"http://hl7.org/fhir/group/search#identifier","type":"token","documentation":"Unique id","xpath":"Group.identifier"}]},{"type":"ImagingStudy","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject"],"searchParam":[{"name":"uid","source":"http://hl7.org/fhir/imagingstudy/search#uid","type":"token","documentation":"Formal identifier for this instance (0008,0018)","xpath":"ImagingStudy.series.instance.uid"},{"name":"series","source":"http://hl7.org/fhir/imagingstudy/search#series","type":"token","documentation":"The series id for the image","xpath":"ImagingStudy.series.uid"},{"name":"_id","source":"http://hl7.org/fhir/imagingstudy/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"bodysite","source":"http://hl7.org/fhir/imagingstudy/search#bodysite","type":"token","documentation":"Body part examined (Map from 0018,0015)","xpath":"ImagingStudy.series.bodySite"},{"name":"subject","source":"http://hl7.org/fhir/imagingstudy/search#subject","type":"reference","documentation":"Who the study is about","xpath":"ImagingStudy.subject"},{"name":"accession","source":"http://hl7.org/fhir/imagingstudy/search#accession","type":"token","documentation":"The accession id for the image","xpath":"ImagingStudy.accessionNo"},{"name":"study","source":"http://hl7.org/fhir/imagingstudy/search#study","type":"token","documentation":"The study id for the image","xpath":"ImagingStudy.uid"},{"name":"modality","source":"http://hl7.org/fhir/imagingstudy/search#modality","type":"token","documentation":"The modality of the image","xpath":"ImagingStudy.series.modality"},{"name":"date","source":"http://hl7.org/fhir/imagingstudy/search#date","type":"date","documentation":"The date the study was done was taken","xpath":"ImagingStudy.dateTime"},{"name":"dicom-class","source":"http://hl7.org/fhir/imagingstudy/search#dicom-class","type":"token","documentation":"DICOM class type (0008,0016)","xpath":"ImagingStudy.series.instance.sopclass"},{"name":"size","source":"http://hl7.org/fhir/imagingstudy/search#size","type":"number","documentation":"The size of the image in MB - may include > or < in the value"}]},{"type":"Immunization","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["reaction","requester","location","subject","manufacturer","performer"],"searchParam":[{"name":"reaction","source":"http://hl7.org/fhir/immunization/search#reaction","type":"reference","documentation":"Additional information on reaction","xpath":"Immunization.reaction.detail"},{"name":"requester","source":"http://hl7.org/fhir/immunization/search#requester","type":"reference","documentation":"The practitioner who ordered the vaccination","xpath":"Immunization.requester"},{"name":"dose-sequence","source":"http://hl7.org/fhir/immunization/search#dose-sequence","type":"number","documentation":"What dose number within series?","xpath":"Immunization.vaccinationProtocol.doseSequence"},{"name":"vaccine-type","source":"http://hl7.org/fhir/immunization/search#vaccine-type","type":"token","documentation":"Vaccine Product Type Administered","xpath":"Immunization.vaccineType"},{"name":"location","source":"http://hl7.org/fhir/immunization/search#location","type":"reference","documentation":"The service delivery location or facility in which the vaccine was / was to be administered","xpath":"Immunization.location"},{"name":"reason","source":"http://hl7.org/fhir/immunization/search#reason","type":"token","documentation":"Why immunization occurred","xpath":"Immunization.explanation.reason"},{"name":"subject","source":"http://hl7.org/fhir/immunization/search#subject","type":"reference","documentation":"The subject of the vaccination event / refusal","xpath":"Immunization.subject"},{"name":"reaction-date","source":"http://hl7.org/fhir/immunization/search#reaction-date","type":"date","documentation":"When did reaction start?","xpath":"Immunization.reaction.date"},{"name":"date","source":"http://hl7.org/fhir/immunization/search#date","type":"date","documentation":"Vaccination Administration / Refusal Date","xpath":"Immunization.date"},{"name":"lot-number","source":"http://hl7.org/fhir/immunization/search#lot-number","type":"string","documentation":"Vaccine Lot Number","xpath":"Immunization.lotNumber"},{"name":"_id","source":"http://hl7.org/fhir/immunization/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"manufacturer","source":"http://hl7.org/fhir/immunization/search#manufacturer","type":"reference","documentation":"Vaccine Manufacturer","xpath":"Immunization.manufacturer"},{"name":"performer","source":"http://hl7.org/fhir/immunization/search#performer","type":"reference","documentation":"The practitioner who administered the vaccination","xpath":"Immunization.performer"},{"name":"refused","source":"http://hl7.org/fhir/immunization/search#refused","type":"token","documentation":"Was immunization refused?","xpath":"Immunization.refusedIndicator"},{"name":"refusal-reason","source":"http://hl7.org/fhir/immunization/search#refusal-reason","type":"token","documentation":"Explanation of refusal / exemption","xpath":"Immunization.explanation.refusalReason"},{"name":"identifier","source":"http://hl7.org/fhir/immunization/search#identifier","type":"token","documentation":"Business identifier","xpath":"Immunization.identifier"}]},{"type":"ImmunizationRecommendation","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["information","support","subject"],"searchParam":[{"name":"information","source":"http://hl7.org/fhir/immunizationrecommendation/search#information","type":"reference","documentation":"Patient observations supporting recommendation","xpath":"ImmunizationRecommendation.recommendation.supportingPatientInformation"},{"name":"dose-sequence","source":"http://hl7.org/fhir/immunizationrecommendation/search#dose-sequence","type":"token","documentation":"Number of dose within sequence","xpath":"ImmunizationRecommendation.recommendation.protocol.doseSequence"},{"name":"support","source":"http://hl7.org/fhir/immunizationrecommendation/search#support","type":"reference","documentation":"Past immunizations supporting recommendation","xpath":"ImmunizationRecommendation.recommendation.supportingImmunization"},{"name":"vaccine-type","source":"http://hl7.org/fhir/immunizationrecommendation/search#vaccine-type","type":"token","documentation":"Vaccine recommendation applies to","xpath":"ImmunizationRecommendation.recommendation.vaccineType"},{"name":"_id","source":"http://hl7.org/fhir/immunizationrecommendation/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/immunizationrecommendation/search#status","type":"token","documentation":"Vaccine administration status","xpath":"ImmunizationRecommendation.recommendation.forecastStatus"},{"name":"dose-number","source":"http://hl7.org/fhir/immunizationrecommendation/search#dose-number","type":"number","documentation":"Recommended dose number","xpath":"ImmunizationRecommendation.recommendation.doseNumber"},{"name":"subject","source":"http://hl7.org/fhir/immunizationrecommendation/search#subject","type":"reference","documentation":"Who this profile is for","xpath":"ImmunizationRecommendation.subject"},{"name":"date","source":"http://hl7.org/fhir/immunizationrecommendation/search#date","type":"date","documentation":"Date recommendation created","xpath":"ImmunizationRecommendation.recommendation.date"},{"name":"identifier","source":"http://hl7.org/fhir/immunizationrecommendation/search#identifier","type":"token","documentation":"Business identifier","xpath":"ImmunizationRecommendation.identifier"}]},{"type":"List","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["source","subject","item"],"searchParam":[{"name":"source","source":"http://hl7.org/fhir/list/search#source","type":"reference","documentation":"Who/what defined the list contents","xpath":"List.source"},{"name":"_id","source":"http://hl7.org/fhir/list/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/list/search#subject","type":"reference","documentation":"If all resources have the same subject","xpath":"List.subject"},{"name":"item","source":"http://hl7.org/fhir/list/search#item","type":"reference","documentation":"Actual entry","xpath":"List.entry.item"},{"name":"code","source":"http://hl7.org/fhir/list/search#code","type":"token","documentation":"What the purpose of this list is","xpath":"List.code"},{"name":"date","source":"http://hl7.org/fhir/list/search#date","type":"date","documentation":"When the list was prepared","xpath":"List.date"},{"name":"empty-reason","source":"http://hl7.org/fhir/list/search#empty-reason","type":"token","documentation":"Why list is empty","xpath":"List.emptyReason"}]},{"type":"Location","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["partof"],"searchParam":[{"name":"near","source":"http://hl7.org/fhir/location/search#near","type":"token","documentation":"The coordinates expressed as [lat],[long] (using KML, see notes) to find locations near to (servers may search using a square rather than a circle for efficiency)"},{"name":"partof","source":"http://hl7.org/fhir/location/search#partof","type":"reference","documentation":"The location of which this location is a part","xpath":"Location.partOf"},{"name":"_id","source":"http://hl7.org/fhir/location/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/location/search#status","type":"token","documentation":"Searches for locations with a specific kind of status","xpath":"Location.status"},{"name":"address","source":"http://hl7.org/fhir/location/search#address","type":"string","documentation":"A (part of the) address of the location","xpath":"Location.address"},{"name":"name","source":"http://hl7.org/fhir/location/search#name","type":"string","documentation":"A (portion of the) name of the location","xpath":"Location.name"},{"name":"near-distance","source":"http://hl7.org/fhir/location/search#near-distance","type":"token","documentation":"A distance quantity to limit the near search to locations within a specific distance"},{"name":"type","source":"http://hl7.org/fhir/location/search#type","type":"token","documentation":"A code for the type of location","xpath":"Location.type"},{"name":"identifier","source":"http://hl7.org/fhir/location/search#identifier","type":"token","documentation":"Unique code or number identifying the location to its users","xpath":"Location.identifier"}]},{"type":"Media","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject","operator"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/media/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/media/search#subject","type":"reference","documentation":"Who/What this Media is a record of","xpath":"Media.subject"},{"name":"subtype","source":"http://hl7.org/fhir/media/search#subtype","type":"token","documentation":"The type of acquisition equipment/process","xpath":"Media.subtype"},{"name":"view","source":"http://hl7.org/fhir/media/search#view","type":"token","documentation":"Imaging view e.g Lateral or Antero-posterior","xpath":"Media.view"},{"name":"date","source":"http://hl7.org/fhir/media/search#date","type":"date","documentation":"When the media was taken/recorded (end)","xpath":"Media.dateTime"},{"name":"type","source":"http://hl7.org/fhir/media/search#type","type":"token","documentation":"photo | video | audio","xpath":"Media.type"},{"name":"identifier","source":"http://hl7.org/fhir/media/search#identifier","type":"token","documentation":"Identifier(s) for the image","xpath":"Media.identifier"},{"name":"operator","source":"http://hl7.org/fhir/media/search#operator","type":"reference","documentation":"The person who generated the image","xpath":"Media.operator"}]},{"type":"Medication","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["content","manufacturer","ingredient"],"searchParam":[{"name":"content","source":"http://hl7.org/fhir/medication/search#content","type":"reference","documentation":"A product in the package","xpath":"Medication.package.content.item"},{"name":"form","source":"http://hl7.org/fhir/medication/search#form","type":"token","documentation":"powder | tablets | carton +","xpath":"Medication.product.form"},{"name":"_id","source":"http://hl7.org/fhir/medication/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"container","source":"http://hl7.org/fhir/medication/search#container","type":"token","documentation":"E.g. box, vial, blister-pack","xpath":"Medication.package.container"},{"name":"manufacturer","source":"http://hl7.org/fhir/medication/search#manufacturer","type":"reference","documentation":"Manufacturer of the item","xpath":"Medication.manufacturer"},{"name":"name","source":"http://hl7.org/fhir/medication/search#name","type":"string","documentation":"Common / Commercial name","xpath":"Medication.name"},{"name":"ingredient","source":"http://hl7.org/fhir/medication/search#ingredient","type":"reference","documentation":"The product contained","xpath":"Medication.product.ingredient.item"},{"name":"code","source":"http://hl7.org/fhir/medication/search#code","type":"token","documentation":"Codes that identify this medication","xpath":"Medication.code"}]},{"type":"MedicationAdministration","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["medication","patient","prescription","device","encounter"],"searchParam":[{"name":"medication","source":"http://hl7.org/fhir/medicationadministration/search#medication","type":"reference","documentation":"Return administrations of this medication","xpath":"MedicationAdministration.medication"},{"name":"patient","source":"http://hl7.org/fhir/medicationadministration/search#patient","type":"reference","documentation":"The identity of a patient to list administrations for","xpath":"MedicationAdministration.patient"},{"name":"_id","source":"http://hl7.org/fhir/medicationadministration/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/medicationadministration/search#status","type":"token","documentation":"MedicationAdministration event status (for example one of active/paused/completed/nullified)","xpath":"MedicationAdministration.status"},{"name":"prescription","source":"http://hl7.org/fhir/medicationadministration/search#prescription","type":"reference","documentation":"The identity of a prescription to list administrations from","xpath":"MedicationAdministration.prescription"},{"name":"device","source":"http://hl7.org/fhir/medicationadministration/search#device","type":"reference","documentation":"Return administrations with this administration device identity","xpath":"MedicationAdministration.device"},{"name":"notgiven","source":"http://hl7.org/fhir/medicationadministration/search#notgiven","type":"token","documentation":"Administrations that were not made","xpath":"MedicationAdministration.wasNotGiven"},{"name":"whengiven","source":"http://hl7.org/fhir/medicationadministration/search#whengiven","type":"date","documentation":"Date of administration","xpath":"MedicationAdministration.whenGiven"},{"name":"encounter","source":"http://hl7.org/fhir/medicationadministration/search#encounter","type":"reference","documentation":"Return administrations that share this encounter","xpath":"MedicationAdministration.encounter"},{"name":"identifier","source":"http://hl7.org/fhir/medicationadministration/search#identifier","type":"token","documentation":"Return administrations with this external identity","xpath":"MedicationAdministration.identifier"}]},{"type":"MedicationDispense","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["medication","patient","prescription","responsibleparty","dispenser","destination"],"searchParam":[{"name":"medication","source":"http://hl7.org/fhir/medicationdispense/search#medication","type":"reference","documentation":"Returns dispenses of this medicine","xpath":"MedicationDispense.dispense.medication"},{"name":"patient","source":"http://hl7.org/fhir/medicationdispense/search#patient","type":"reference","documentation":"The identity of a patient to list dispenses for","xpath":"MedicationDispense.patient"},{"name":"_id","source":"http://hl7.org/fhir/medicationdispense/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/medicationdispense/search#status","type":"token","documentation":"Status of the dispense","xpath":"MedicationDispense.dispense.status"},{"name":"prescription","source":"http://hl7.org/fhir/medicationdispense/search#prescription","type":"reference","documentation":"The identity of a prescription to list dispenses from","xpath":"MedicationDispense.authorizingPrescription"},{"name":"responsibleparty","source":"http://hl7.org/fhir/medicationdispense/search#responsibleparty","type":"reference","documentation":"Return all dispenses with the specified responsibel party","xpath":"MedicationDispense.substitution.responsibleParty"},{"name":"dispenser","source":"http://hl7.org/fhir/medicationdispense/search#dispenser","type":"reference","documentation":"Return all dispenses performed by a specific indiividual","xpath":"MedicationDispense.dispenser"},{"name":"type","source":"http://hl7.org/fhir/medicationdispense/search#type","type":"token","documentation":"Return all dispenses of a specific type","xpath":"MedicationDispense.dispense.type"},{"name":"identifier","source":"http://hl7.org/fhir/medicationdispense/search#identifier","type":"token","documentation":"Return dispenses with this external identity","xpath":"MedicationDispense.identifier"},{"name":"whenprepared","source":"http://hl7.org/fhir/medicationdispense/search#whenprepared","type":"date","documentation":"Date when medication prepared","xpath":"MedicationDispense.dispense.whenPrepared"},{"name":"whenhandedover","source":"http://hl7.org/fhir/medicationdispense/search#whenhandedover","type":"date","documentation":"Date when medication handed over to patient (outpatient setting), or supplied to ward or clinic (inpatient setting)","xpath":"MedicationDispense.dispense.whenHandedOver"},{"name":"destination","source":"http://hl7.org/fhir/medicationdispense/search#destination","type":"reference","documentation":"Return dispenses that should be sent to a secific destination","xpath":"MedicationDispense.dispense.destination"}]},{"type":"MedicationPrescription","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["medication","patient","encounter"],"searchParam":[{"name":"medication","source":"http://hl7.org/fhir/medicationprescription/search#medication","type":"reference","documentation":"Code for medicine or text in medicine name","xpath":"MedicationPrescription.medication"},{"name":"datewritten","source":"http://hl7.org/fhir/medicationprescription/search#datewritten","type":"date","documentation":"Return prescriptions written on this date","xpath":"MedicationPrescription.dateWritten"},{"name":"patient","source":"http://hl7.org/fhir/medicationprescription/search#patient","type":"reference","documentation":"The identity of a patient to list dispenses for","xpath":"MedicationPrescription.patient"},{"name":"_id","source":"http://hl7.org/fhir/medicationprescription/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/medicationprescription/search#status","type":"token","documentation":"Status of the prescription","xpath":"MedicationPrescription.status"},{"name":"encounter","source":"http://hl7.org/fhir/medicationprescription/search#encounter","type":"reference","documentation":"Return prescriptions with this encounter identity","xpath":"MedicationPrescription.encounter"},{"name":"identifier","source":"http://hl7.org/fhir/medicationprescription/search#identifier","type":"token","documentation":"Return prescriptions with this external identity","xpath":"MedicationPrescription.identifier"}]},{"type":"MedicationStatement","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["medication","patient","device"],"searchParam":[{"name":"medication","source":"http://hl7.org/fhir/medicationstatement/search#medication","type":"reference","documentation":"Code for medicine or text in medicine name","xpath":"MedicationStatement.medication"},{"name":"patient","source":"http://hl7.org/fhir/medicationstatement/search#patient","type":"reference","documentation":"The identity of a patient to list administrations for","xpath":"MedicationStatement.patient"},{"name":"_id","source":"http://hl7.org/fhir/medicationstatement/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"device","source":"http://hl7.org/fhir/medicationstatement/search#device","type":"reference","documentation":"Return administrations with this administration device identity","xpath":"MedicationStatement.device"},{"name":"when-given","source":"http://hl7.org/fhir/medicationstatement/search#when-given","type":"date","documentation":"Date of administration","xpath":"MedicationStatement.whenGiven"},{"name":"identifier","source":"http://hl7.org/fhir/medicationstatement/search#identifier","type":"token","documentation":"Return administrations with this external identity","xpath":"MedicationStatement.identifier"}]},{"type":"MessageHeader","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/messageheader/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"}]},{"type":"Observation","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject","specimen","performer"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/observation/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/observation/search#status","type":"token","documentation":"The status of the observation","xpath":"Observation.status"},{"name":"subject","source":"http://hl7.org/fhir/observation/search#subject","type":"reference","documentation":"The subject that the observation is about","xpath":"Observation.subject"},{"name":"specimen","source":"http://hl7.org/fhir/observation/search#specimen","type":"reference","documentation":"Specimen used for this observation","xpath":"Observation.specimen"},{"name":"name","source":"http://hl7.org/fhir/observation/search#name","type":"token","documentation":"The name of the observation type","xpath":"Observation.name"},{"name":"reliability","source":"http://hl7.org/fhir/observation/search#reliability","type":"token","documentation":"The reliability of the observation","xpath":"Observation.reliability"},{"name":"value","source":"http://hl7.org/fhir/observation/search#value","type":"token","documentation":"The code or value of a result","xpath":"Observation.value[x]"},{"name":"performer","source":"http://hl7.org/fhir/observation/search#performer","type":"reference","documentation":"Who/what performed the observation","xpath":"Observation.performer"},{"name":"name-value","source":"http://hl7.org/fhir/observation/search#name-value","type":"composite","documentation":"Both name and value"},{"name":"date","source":"http://hl7.org/fhir/observation/search#date","type":"date","documentation":"Obtained date/time. If the obtained element is a period, a date that falls in the period","xpath":"Observation.applies[x]"}]},{"type":"OperationOutcome","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/operationoutcome/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"}]},{"type":"Order","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["authority","detail","source","subject","target"],"searchParam":[{"name":"authority","source":"http://hl7.org/fhir/order/search#authority","type":"reference","documentation":"If required by policy","xpath":"Order.authority"},{"name":"detail","source":"http://hl7.org/fhir/order/search#detail","type":"reference","documentation":"What action is being ordered","xpath":"Order.detail"},{"name":"source","source":"http://hl7.org/fhir/order/search#source","type":"reference","documentation":"Who initiated the order","xpath":"Order.source"},{"name":"_id","source":"http://hl7.org/fhir/order/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/order/search#subject","type":"reference","documentation":"Patient this order is about","xpath":"Order.subject"},{"name":"when","source":"http://hl7.org/fhir/order/search#when","type":"date","documentation":"A formal schedule","xpath":"Order.when.schedule"},{"name":"target","source":"http://hl7.org/fhir/order/search#target","type":"reference","documentation":"Who is intended to fulfill the order","xpath":"Order.target"},{"name":"when_code","source":"http://hl7.org/fhir/order/search#when_code","type":"token","documentation":"Code specifies when request should be done. The code may simply be a priority code","xpath":"Order.when.code"},{"name":"date","source":"http://hl7.org/fhir/order/search#date","type":"date","documentation":"When the order was made","xpath":"Order.date"}]},{"type":"OrderResponse","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["fulfillment","request","who"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/orderresponse/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"fulfillment","source":"http://hl7.org/fhir/orderresponse/search#fulfillment","type":"reference","documentation":"Details of the outcome of performing the order","xpath":"OrderResponse.fulfillment"},{"name":"request","source":"http://hl7.org/fhir/orderresponse/search#request","type":"reference","documentation":"The order that this is a response to","xpath":"OrderResponse.request"},{"name":"code","source":"http://hl7.org/fhir/orderresponse/search#code","type":"token","documentation":"pending | review | rejected | error | accepted | cancelled | replaced | aborted | complete","xpath":"OrderResponse.code"},{"name":"date","source":"http://hl7.org/fhir/orderresponse/search#date","type":"date","documentation":"When the response was made","xpath":"OrderResponse.date"},{"name":"who","source":"http://hl7.org/fhir/orderresponse/search#who","type":"reference","documentation":"Who made the response","xpath":"OrderResponse.who"}]},{"type":"Organization","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["partof"],"searchParam":[{"name":"phonetic","source":"http://hl7.org/fhir/organization/search#phonetic","type":"string","documentation":"A portion of the organization's name using some kind of phonetic matching algorithm"},{"name":"partof","source":"http://hl7.org/fhir/organization/search#partof","type":"reference","documentation":"Search all organizations that are part of the given organization","xpath":"Organization.partOf"},{"name":"_id","source":"http://hl7.org/fhir/organization/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"name","source":"http://hl7.org/fhir/organization/search#name","type":"string","documentation":"A portion of the organization's name","xpath":"Organization.name"},{"name":"active","source":"http://hl7.org/fhir/organization/search#active","type":"token","documentation":"Whether the organization's record is active","xpath":"Organization.active"},{"name":"type","source":"http://hl7.org/fhir/organization/search#type","type":"token","documentation":"A code for the type of organization","xpath":"Organization.type"},{"name":"identifier","source":"http://hl7.org/fhir/organization/search#identifier","type":"token","documentation":"Any identifier for the organization (not the accreditation issuer's identifier)","xpath":"Organization.identifier"}]},{"type":"Other","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/other/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"created","source":"http://hl7.org/fhir/other/search#created","type":"date","documentation":"When created","xpath":"Other.created"},{"name":"subject","source":"http://hl7.org/fhir/other/search#subject","type":"reference","documentation":"Identifies the","xpath":"Other.subject"},{"name":"code","source":"http://hl7.org/fhir/other/search#code","type":"token","documentation":"Kind of Resource","xpath":"Other.code"}]},{"type":"Patient","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["link","provider"],"searchParam":[{"name":"animal-breed","source":"http://hl7.org/fhir/patient/search#animal-breed","type":"token","documentation":"The breed for animal patients","xpath":"Patient.animal.breed"},{"name":"phonetic","source":"http://hl7.org/fhir/patient/search#phonetic","type":"string","documentation":"A portion of either family or given name using some kind of phonetic matching algorithm"},{"name":"link","source":"http://hl7.org/fhir/patient/search#link","type":"reference","documentation":"All patients linked to the given patient","xpath":"Patient.link.other"},{"name":"provider","source":"http://hl7.org/fhir/patient/search#provider","type":"reference","documentation":"The organization at which this person is a patient","xpath":"Patient.managingOrganization"},{"name":"animal-species","source":"http://hl7.org/fhir/patient/search#animal-species","type":"token","documentation":"The species for animal patients","xpath":"Patient.animal.species"},{"name":"_id","source":"http://hl7.org/fhir/patient/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"given","source":"http://hl7.org/fhir/patient/search#given","type":"string","documentation":"A portion of the given name of the patient","xpath":"Patient.name.given"},{"name":"address","source":"http://hl7.org/fhir/patient/search#address","type":"string","documentation":"An address in any kind of address/part of the patient","xpath":"Patient.address"},{"name":"family","source":"http://hl7.org/fhir/patient/search#family","type":"string","documentation":"A portion of the family name of the patient","xpath":"Patient.name.family"},{"name":"name","source":"http://hl7.org/fhir/patient/search#name","type":"string","documentation":"A portion of either family or given name of the patient","xpath":"Patient.name"},{"name":"telecom","source":"http://hl7.org/fhir/patient/search#telecom","type":"string","documentation":"The value in any kind of telecom details of the patient","xpath":"Patient.telecom"},{"name":"birthdate","source":"http://hl7.org/fhir/patient/search#birthdate","type":"date","documentation":"The patient's date of birth","xpath":"Patient.birthDate"},{"name":"active","source":"http://hl7.org/fhir/patient/search#active","type":"token","documentation":"Whether the patient record is active","xpath":"Patient.active"},{"name":"gender","source":"http://hl7.org/fhir/patient/search#gender","type":"token","documentation":"Gender of the patient","xpath":"Patient.gender"},{"name":"language","source":"http://hl7.org/fhir/patient/search#language","type":"token","documentation":"Language code (irrespective of use value)","xpath":"Patient.communication"},{"name":"identifier","source":"http://hl7.org/fhir/patient/search#identifier","type":"token","documentation":"A patient identifier","xpath":"Patient.identifier"}]},{"type":"Practitioner","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["organization"],"searchParam":[{"name":"organization","source":"http://hl7.org/fhir/practitioner/search#organization","type":"reference","documentation":"The identity of the organization the practitioner represents / acts on behalf of","xpath":"Practitioner.organization"},{"name":"phonetic","source":"http://hl7.org/fhir/practitioner/search#phonetic","type":"string","documentation":"A portion of either family or given name using some kind of phonetic matching algorithm","xpath":"Practitioner.name"},{"name":"given","source":"http://hl7.org/fhir/practitioner/search#given","type":"string","documentation":"A portion of the given name","xpath":"Practitioner.name"},{"name":"_id","source":"http://hl7.org/fhir/practitioner/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"address","source":"http://hl7.org/fhir/practitioner/search#address","type":"string","documentation":"An address in any kind of address/part","xpath":"Practitioner.address"},{"name":"family","source":"http://hl7.org/fhir/practitioner/search#family","type":"string","documentation":"A portion of the family name","xpath":"Practitioner.name"},{"name":"name","source":"http://hl7.org/fhir/practitioner/search#name","type":"string","documentation":"A portion of either family or given name","xpath":"Practitioner.name"},{"name":"telecom","source":"http://hl7.org/fhir/practitioner/search#telecom","type":"string","documentation":"The value in any kind of contact","xpath":"Practitioner.telecom"},{"name":"gender","source":"http://hl7.org/fhir/practitioner/search#gender","type":"token","documentation":"Gender of the practitioner","xpath":"Practitioner.gender"},{"name":"identifier","source":"http://hl7.org/fhir/practitioner/search#identifier","type":"token","documentation":"A practitioner's Identifier","xpath":"Practitioner.identifier"}]},{"type":"Procedure","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/procedure/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/procedure/search#subject","type":"reference","documentation":"The identity of a patient to list procedures for","xpath":"Procedure.subject"},{"name":"date","source":"http://hl7.org/fhir/procedure/search#date","type":"date","documentation":"The date the procedure was performed on","xpath":"Procedure.date"},{"name":"type","source":"http://hl7.org/fhir/procedure/search#type","type":"token","documentation":"Type of procedure","xpath":"Procedure.type"}]},{"type":"Profile","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["valueset"],"searchParam":[{"name":"extension","source":"http://hl7.org/fhir/profile/search#extension","type":"token","documentation":"An extension code (use or definition)","xpath":"Profile.extensionDefn.code"},{"name":"_id","source":"http://hl7.org/fhir/profile/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"valueset","source":"http://hl7.org/fhir/profile/search#valueset","type":"reference","documentation":"A vocabulary binding code","xpath":"Profile.structure.element.definition.binding.reference[x]"},{"name":"status","source":"http://hl7.org/fhir/profile/search#status","type":"token","documentation":"The current status of the profile","xpath":"Profile.status"},{"name":"description","source":"http://hl7.org/fhir/profile/search#description","type":"string","documentation":"Text search in the description of the profile","xpath":"Profile.description"},{"name":"name","source":"http://hl7.org/fhir/profile/search#name","type":"string","documentation":"Name of the profile","xpath":"Profile.name"},{"name":"code","source":"http://hl7.org/fhir/profile/search#code","type":"token","documentation":"A code for the profile in the format uri::code (server may choose to do subsumption)","xpath":"Profile.code"},{"name":"type","source":"http://hl7.org/fhir/profile/search#type","type":"token","documentation":"Type of resource that is constrained in the profile","xpath":"Profile.structure.type"},{"name":"date","source":"http://hl7.org/fhir/profile/search#date","type":"date","documentation":"The profile publication date","xpath":"Profile.date"},{"name":"identifier","source":"http://hl7.org/fhir/profile/search#identifier","type":"token","documentation":"The identifier of the profile","xpath":"Profile.identifier"},{"name":"publisher","source":"http://hl7.org/fhir/profile/search#publisher","type":"string","documentation":"Name of the publisher of the profile","xpath":"Profile.publisher"},{"name":"version","source":"http://hl7.org/fhir/profile/search#version","type":"token","documentation":"The version identifier of the profile","xpath":"Profile.version"}]},{"type":"Provenance","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["location","target"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/provenance/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"location","source":"http://hl7.org/fhir/provenance/search#location","type":"reference","documentation":"Where the activity occurred, if relevant","xpath":"Provenance.location"},{"name":"start","source":"http://hl7.org/fhir/provenance/search#start","type":"date","documentation":"Starting time with inclusive boundary","xpath":"Provenance.period.start"},{"name":"partytype","source":"http://hl7.org/fhir/provenance/search#partytype","type":"token","documentation":"e.g. Resource | Person | Application | Record | Document +","xpath":"Provenance.agent.type"},{"name":"target","source":"http://hl7.org/fhir/provenance/search#target","type":"reference","documentation":"Target resource(s) (usually version specific)","xpath":"Provenance.target"},{"name":"party","source":"http://hl7.org/fhir/provenance/search#party","type":"token","documentation":"Identity of agent (urn or url)","xpath":"Provenance.agent.reference"},{"name":"end","source":"http://hl7.org/fhir/provenance/search#end","type":"date","documentation":"End time with inclusive boundary, if not ongoing","xpath":"Provenance.period.end"}]},{"type":"Query","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchParam":[{"name":"response","source":"http://hl7.org/fhir/query/search#response","type":"token","documentation":"Links response to source query","xpath":"Query.response.identifier"},{"name":"_id","source":"http://hl7.org/fhir/query/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"identifier","source":"http://hl7.org/fhir/query/search#identifier","type":"token","documentation":"Links query and its response(s)","xpath":"Query.identifier"}]},{"type":"Questionnaire","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["author","subject","encounter"],"searchParam":[{"name":"author","source":"http://hl7.org/fhir/questionnaire/search#author","type":"reference","documentation":"The author of the questionnaire","xpath":"Questionnaire.author"},{"name":"authored","source":"http://hl7.org/fhir/questionnaire/search#authored","type":"date","documentation":"When the questionnaire was authored","xpath":"Questionnaire.authored"},{"name":"_id","source":"http://hl7.org/fhir/questionnaire/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/questionnaire/search#status","type":"token","documentation":"The status of the questionnaire","xpath":"Questionnaire.status"},{"name":"subject","source":"http://hl7.org/fhir/questionnaire/search#subject","type":"reference","documentation":"The subject of the questionnaire","xpath":"Questionnaire.subject"},{"name":"name","source":"http://hl7.org/fhir/questionnaire/search#name","type":"token","documentation":"Name of the questionnaire","xpath":"Questionnaire.name"},{"name":"encounter","source":"http://hl7.org/fhir/questionnaire/search#encounter","type":"reference","documentation":"Encounter during which questionnaire was authored","xpath":"Questionnaire.encounter"},{"name":"identifier","source":"http://hl7.org/fhir/questionnaire/search#identifier","type":"token","documentation":"An identifier for the questionnaire","xpath":"Questionnaire.identifier"}]},{"type":"RelatedPerson","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["patient"],"searchParam":[{"name":"patient","source":"http://hl7.org/fhir/relatedperson/search#patient","type":"reference","documentation":"The patient this person is related to","xpath":"RelatedPerson.patient"},{"name":"phonetic","source":"http://hl7.org/fhir/relatedperson/search#phonetic","type":"string","documentation":"A portion of name using some kind of phonetic matching algorithm"},{"name":"_id","source":"http://hl7.org/fhir/relatedperson/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"address","source":"http://hl7.org/fhir/relatedperson/search#address","type":"string","documentation":"An address in any kind of address/part","xpath":"RelatedPerson.address"},{"name":"name","source":"http://hl7.org/fhir/relatedperson/search#name","type":"string","documentation":"A portion of name in any name part","xpath":"RelatedPerson.name"},{"name":"telecom","source":"http://hl7.org/fhir/relatedperson/search#telecom","type":"string","documentation":"The value in any kind of contact","xpath":"RelatedPerson.telecom"},{"name":"gender","source":"http://hl7.org/fhir/relatedperson/search#gender","type":"token","documentation":"Gender of the person","xpath":"RelatedPerson.gender"},{"name":"identifier","source":"http://hl7.org/fhir/relatedperson/search#identifier","type":"token","documentation":"A patient Identifier","xpath":"RelatedPerson.identifier"}]},{"type":"SecurityEvent","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["reference"],"searchParam":[{"name":"site","source":"http://hl7.org/fhir/securityevent/search#site","type":"token","documentation":"Logical source location within the enterprise","xpath":"SecurityEvent.source.site"},{"name":"desc","source":"http://hl7.org/fhir/securityevent/search#desc","type":"string","documentation":"Instance-specific descriptor for Object","xpath":"SecurityEvent.object.name"},{"name":"type","source":"http://hl7.org/fhir/securityevent/search#type","type":"token","documentation":"Type/identifier of event","xpath":"SecurityEvent.event.type"},{"name":"date","source":"http://hl7.org/fhir/securityevent/search#date","type":"date","documentation":"Time when the event occurred on source","xpath":"SecurityEvent.event.dateTime"},{"name":"reference","source":"http://hl7.org/fhir/securityevent/search#reference","type":"reference","documentation":"Specific instance of resource (e.g. versioned)","xpath":"SecurityEvent.object.reference"},{"name":"identity","source":"http://hl7.org/fhir/securityevent/search#identity","type":"token","documentation":"Specific instance of object (e.g. versioned)","xpath":"SecurityEvent.object.identifier"},{"name":"altid","source":"http://hl7.org/fhir/securityevent/search#altid","type":"token","documentation":"Alternative User id e.g. authentication","xpath":"SecurityEvent.participant.altId"},{"name":"patientid","source":"http://hl7.org/fhir/securityevent/search#patientid","type":"token","documentation":"The id of the patient (one of multiple kinds of participations)"},{"name":"_id","source":"http://hl7.org/fhir/securityevent/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"source","source":"http://hl7.org/fhir/securityevent/search#source","type":"token","documentation":"The id of source where event originated","xpath":"SecurityEvent.source.identifier"},{"name":"address","source":"http://hl7.org/fhir/securityevent/search#address","type":"token","documentation":"Identifier for the network access point of the user device","xpath":"SecurityEvent.participant.network.identifier"},{"name":"subtype","source":"http://hl7.org/fhir/securityevent/search#subtype","type":"token","documentation":"More specific type/id for the event","xpath":"SecurityEvent.event.subtype"},{"name":"name","source":"http://hl7.org/fhir/securityevent/search#name","type":"string","documentation":"Human-meaningful name for the user","xpath":"SecurityEvent.participant.name"},{"name":"action","source":"http://hl7.org/fhir/securityevent/search#action","type":"token","documentation":"Type of action performed during the event","xpath":"SecurityEvent.event.action"},{"name":"object-type","source":"http://hl7.org/fhir/securityevent/search#object-type","type":"token","documentation":"Object type being audited","xpath":"SecurityEvent.object.type"},{"name":"user","source":"http://hl7.org/fhir/securityevent/search#user","type":"token","documentation":"Unique identifier for the user","xpath":"SecurityEvent.participant.userId"}]},{"type":"Slot","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["availability"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/slot/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"start","source":"http://hl7.org/fhir/slot/search#start","type":"date","documentation":"Appointment date/time.","xpath":"Slot.start"},{"name":"slottype","source":"http://hl7.org/fhir/slot/search#slottype","type":"token","documentation":"The type of appointments that can be booked into the slot","xpath":"Slot.type"},{"name":"fbtype","source":"http://hl7.org/fhir/slot/search#fbtype","type":"token","documentation":"The free/busy status of the appointment","xpath":"Slot.freeBusyType"},{"name":"availability","source":"http://hl7.org/fhir/slot/search#availability","type":"reference","documentation":"The Availability Resource that we are seeking a slot within","xpath":"Slot.availability"}]},{"type":"Specimen","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["subject"],"searchParam":[{"name":"_id","source":"http://hl7.org/fhir/specimen/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"subject","source":"http://hl7.org/fhir/specimen/search#subject","type":"reference","documentation":"The subject of the specimen","xpath":"Specimen.subject"}]},{"type":"Substance","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["substance"],"searchParam":[{"name":"substance","source":"http://hl7.org/fhir/substance/search#substance","type":"reference","documentation":"A component of the substance","xpath":"Substance.ingredient.substance"},{"name":"_id","source":"http://hl7.org/fhir/substance/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"quantity","source":"http://hl7.org/fhir/substance/search#quantity","type":"number","documentation":"Amount of substance in the package","xpath":"Substance.instance.quantity"},{"name":"type","source":"http://hl7.org/fhir/substance/search#type","type":"token","documentation":"The type of the substance","xpath":"Substance.type"},{"name":"identifier","source":"http://hl7.org/fhir/substance/search#identifier","type":"token","documentation":"Identifier of the package/container","xpath":"Substance.instance.identifier"},{"name":"expiry","source":"http://hl7.org/fhir/substance/search#expiry","type":"date","documentation":"When no longer valid to use","xpath":"Substance.instance.expiry"}]},{"type":"Supply","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchInclude":["patient","supplier"],"searchParam":[{"name":"patient","source":"http://hl7.org/fhir/supply/search#patient","type":"reference","documentation":"Patient for whom the item is supplied","xpath":"Supply.patient"},{"name":"_id","source":"http://hl7.org/fhir/supply/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/supply/search#status","type":"token","documentation":"requested | dispensed | received | failed | cancelled","xpath":"Supply.status"},{"name":"dispenseid","source":"http://hl7.org/fhir/supply/search#dispenseid","type":"token","documentation":"External identifier","xpath":"Supply.dispense.identifier"},{"name":"identifier","source":"http://hl7.org/fhir/supply/search#identifier","type":"token","documentation":"Unique identifier","xpath":"Supply.identifier"},{"name":"supplier","source":"http://hl7.org/fhir/supply/search#supplier","type":"reference","documentation":"Dispenser","xpath":"Supply.dispense.supplier"},{"name":"kind","source":"http://hl7.org/fhir/supply/search#kind","type":"token","documentation":"The kind of supply (central, non-stock, etc)","xpath":"Supply.kind"},{"name":"dispensestatus","source":"http://hl7.org/fhir/supply/search#dispensestatus","type":"token","documentation":"in progress | dispensed | abandoned","xpath":"Supply.dispense.status"}]},{"type":"ValueSet","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true,"searchParam":[{"name":"system","source":"http://hl7.org/fhir/valueset/search#system","type":"token","documentation":"The system for any codes defined by this value set","xpath":"ValueSet.define.system"},{"name":"_id","source":"http://hl7.org/fhir/valueset/search#_id","type":"token","documentation":"The logical resource id associated with the resource (must be supported by all servers)"},{"name":"status","source":"http://hl7.org/fhir/valueset/search#status","type":"token","documentation":"The status of the value set","xpath":"ValueSet.status"},{"name":"description","source":"http://hl7.org/fhir/valueset/search#description","type":"string","documentation":"Text search in the description of the value set","xpath":"ValueSet.description"},{"name":"name","source":"http://hl7.org/fhir/valueset/search#name","type":"string","documentation":"The name of the value set","xpath":"ValueSet.name"},{"name":"code","source":"http://hl7.org/fhir/valueset/search#code","type":"token","documentation":"A code defined in the value set","xpath":"ValueSet.define.concept.code"},{"name":"date","source":"http://hl7.org/fhir/valueset/search#date","type":"date","documentation":"The value set publication date","xpath":"ValueSet.date"},{"name":"identifier","source":"http://hl7.org/fhir/valueset/search#identifier","type":"token","documentation":"The identifier of the value set","xpath":"ValueSet.identifier"},{"name":"reference","source":"http://hl7.org/fhir/valueset/search#reference","type":"token","documentation":"A code system included or excluded in the value set or an imported value set","xpath":"ValueSet.compose.include.system"},{"name":"publisher","source":"http://hl7.org/fhir/valueset/search#publisher","type":"string","documentation":"Name of the publisher of the value set","xpath":"ValueSet.publisher"},{"name":"version","source":"http://hl7.org/fhir/valueset/search#version","type":"token","documentation":"The version identifier of the value set","xpath":"ValueSet.version"}]},{"type":"Binary","operation":[{"code":"create"},{"code":"delete"},{"code":"history-instance"},{"code":"history-type"},{"code":"read"},{"code":"search-type"},{"code":"update"},{"code":"validate"},{"code":"vread"}],"readHistory":true}]}]} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/furore-conformance.xml b/hapi-fhir-structures-dstu/src/test/resources/furore-conformance.xml new file mode 100644 index 00000000000..7dfcfeb73e3 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/furore-conformance.xml @@ -0,0 +1,4893 @@ + + + + +
+

The server supports all operations on the Binary resource, including history

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/hapi-fhir-structures-dstu/src/test/resources/logback-test.xml b/hapi-fhir-structures-dstu/src/test/resources/logback-test.xml new file mode 100644 index 00000000000..e0cd60554bf --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/logback-test.xml @@ -0,0 +1,27 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/mixed-return-bundle.xml b/hapi-fhir-structures-dstu/src/test/resources/mixed-return-bundle.xml new file mode 100644 index 00000000000..9bee3ae5f64 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/mixed-return-bundle.xml @@ -0,0 +1,335 @@ + + + <id>41fd781e-a207-4671-8589-8aee7892b4de</id> + <link rel="self" href="http://localhost:8888/fhir/context/Patient?_pretty=true&_include=Patient.managingOrganization&_pretty=true"/> + <link rel="fhir-base" href="http://localhost:8888/fhir/context"/> + <os:totalResults xmlns:os="http://a9.com/-/spec/opensearch/1.1/">2</os:totalResults> + <published>2014-06-22T21:37:05-04:00</published> + <author> + <name>HAPI FHIR Server</name> + </author> + <entry> + <title>Patient Patient/1/_history/1 + http://localhost:8888/fhir/context/Patient/1 + 2014-06-22T19:29:53.232-04:00 + 2014-06-22T19:29:52.797-04:00 + + + + + + + + + + + + + + + + + + Patient Patient/2/_history/1 + http://localhost:8888/fhir/context/Patient/2 + 2014-06-22T19:29:53.996-04:00 + 2014-06-22T19:29:53.809-04:00 + + + + + +
+
Donald null + DUCK +
+ + + + + + + + + + + + + + + +
Identifier7000135
Address + 10 Duxon Street +
+ VICTORIA + BC + Can +
Date of birth + 01 June 1980 +
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + +
+ + + +
+
+
+ + Organization Organization/4/_history/1 + http://localhost:8888/fhir/context/Organization/4 + 2014-06-22T19:29:54.205-04:00 + 2014-06-22T19:29:53.849-04:00 + + + + + + + + +
No narrative template available for resource profile: http://fhir.connectinggta.ca/Profile/organization
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + +
+
+
+
\ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/narrative/Practitioner.html b/hapi-fhir-structures-dstu/src/test/resources/narrative/Practitioner.html new file mode 100644 index 00000000000..4fadc9c851d --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/narrative/Practitioner.html @@ -0,0 +1,24 @@ +
+ +
+ + +

Name

+
+ +

Address

+
+ + +
\ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/narrative/customnarrative.properties b/hapi-fhir-structures-dstu/src/test/resources/narrative/customnarrative.properties new file mode 100644 index 00000000000..4f4404c5495 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/narrative/customnarrative.properties @@ -0,0 +1,16 @@ + +# Each resource to be defined has a pair or properties. +# +# The first (name.class) defines the class name of the +# resource to define a template for +# +# The second (name.narrative) defines the path/classpath to the +# template file. +# Format is file:/path/foo.html or classpath:/com/classpath/foo.html +# +practitioner.class=ca.uhn.fhir.model.dstu.resource.Practitioner +practitioner.narrative=file:src/test/resources/narrative/Practitioner.html + +# You may also override/define behaviour for datatypes +humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt +humanname.narrative=classpath:ca/uhn/fhir/narrative/datatype/HumanNameDt.html diff --git a/hapi-fhir-structures-dstu/src/test/resources/observation-example-eeg.xml b/hapi-fhir-structures-dstu/src/test/resources/observation-example-eeg.xml new file mode 100644 index 00000000000..cbfd8986153 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/observation-example-eeg.xml @@ -0,0 +1,55 @@ + + + + + + + + + + + + + + + + + + + + + + +
Sept 17, 2012: Systolic Blood pressure 107 mmHg (normal)
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/observation-example-f001-glucose.json b/hapi-fhir-structures-dstu/src/test/resources/observation-example-f001-glucose.json new file mode 100644 index 00000000000..6c92d5f4a55 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/observation-example-f001-glucose.json @@ -0,0 +1 @@ +{"resourceType":"Observation","text":{"status":"generated","div":"
\n

\n Generated Narrative\n

\n

\n name: \n Glucose [Mass/volume] in Blood\n

\n

\n value: 6.3 mmol/l\n

\n

\n interpretation: \n abnormal\n

\n

\n applies: 2-Apr 2013 9:30 --> 5-Apr 2013 9:30\n

\n

\n issued: 3-Apr 2013 15:30\n

\n

\n status: final_\n

\n

\n reliability: ok\n

\n

\n bodySite: \n Superficial forearm vein\n

\n

\n method: \n Injection to forearm\n

\n

\n identifier: 6323 (official)\n

\n

\n subject: P. van de Heuvel\n

\n

\n performer: A. Langeveld\n

\n

ReferenceRanges

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Low\n \n High\n \n Meaning\n \n Age\n
3.1 mmol/l6.2 mmol/l
\n
"},"name":{"coding":[{"system":"http://loinc.org","code":"2339-0","display":"Glucose [Mass/volume] in Blood"}]},"valueQuantity":{"value":6.3,"units":"mmol/l","system":"http://unitsofmeasure.org","code":"mmol/l"},"interpretation":{"coding":[{"system":"http://hl7.org/fhir/v2/0078","code":"A","display":"abnormal"}]},"appliesPeriod":{"start":"2013-04-02T09:30:10+01:00","end":"2013-04-05T09:30:10+01:00"},"issued":"2013-04-03T15:30:10+01:00","status":"final","reliability":"ok","bodySite":{"coding":[{"system":"http://snomed.info/sct","code":"308046002","display":"Superficial forearm vein"}]},"method":{"coding":[{"system":"http://snomed.info/sct","code":"120220003","display":"Injection to forearm"}]},"identifier":{"use":"official","system":"http://www.bmc.nl/zorgportal/identifiers/observations","value":"6323"},"subject":{"reference":"Patient/f001","display":"P. van de Heuvel"},"performer":[{"reference":"Practitioner/f005","display":"A. Langeveld"}],"referenceRange":[{"low":{"value":3.1,"units":"mmol/l","system":"http://unitsofmeasure.org","code":"mmol/l"},"high":{"value":6.2,"units":"mmol/l","system":"http://unitsofmeasure.org","code":"mmol/l"}}]} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/observation-example-f204-creatinine.json b/hapi-fhir-structures-dstu/src/test/resources/observation-example-f204-creatinine.json new file mode 100644 index 00000000000..09de22675c4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/observation-example-f204-creatinine.json @@ -0,0 +1 @@ +{"resourceType":"Observation","text":{"status":"generated","div":"
\n

\n Generated Narrative\n

\n

\n name: \n Creatinine level\n

\n

\n value: 122 umol/L\n

\n

\n interpretation: \n Serum creatinine raised\n

\n

\n issued: 4-Apr 2013 14:34\n

\n

\n status: final_\n

\n

\n reliability: ok\n

\n

\n method: \n Creatinine measurement, serum\n

\n

\n identifier: Creatinine value of Roel on April 2013 - 03720 = 1304-03720-Creatinine\n

\n

\n subject: Roel\n

\n

\n performer: Luigi Maas\n

\n

ReferenceRanges

\n \n \n \n \n \n \n \n \n \n \n \n \n \n
\n Low\n \n High\n \n Meaning\n \n Age\n
64 null104 null\n Normal Range\n
\n
"},"name":{"coding":[{"system":"http://snomed.info/sct","code":"365756002","display":"Creatinine level"}]},"valueQuantity":{"value":122,"units":"umol/L","system":"http://snomed.info/sct","code":"258814008"},"interpretation":{"coding":[{"system":"http://snomed.info/sct","code":"166717003","display":"Serum creatinine raised"},{"system":"http://hl7.org/fhir/v2/0078","code":"H"}]},"issued":"2013-04-04T14:34:00+01:00","status":"final","reliability":"ok","method":{"coding":[{"system":"http://snomed.info/sct","code":"113075003","display":"Creatinine measurement, serum"}]},"identifier":{"label":"Creatinine value of Roel on April 2013 - 03720","system":"https://intranet.aumc.nl/labvalues","value":"1304-03720-Creatinine"},"subject":{"reference":"Patient/f201","display":"Roel"},"performer":[{"reference":"Practitioner/f202","display":"Luigi Maas"}],"referenceRange":[{"low":{"value":64},"high":{"value":104},"meaning":{"coding":[{"system":"http://hl7.org/fhir/referencerange-meaning","code":"normal","display":"Normal Range"}]}}]} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/patient-example-dicom.xml b/hapi-fhir-structures-dstu/src/test/resources/patient-example-dicom.xml new file mode 100644 index 00000000000..ae5b1dff732 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/patient-example-dicom.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + +
Patient MINT_TEST, ID = MINT1234. Age = 56y, Size = + 1.83m, Weight = 72.58kg
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/hapi-fhir-structures-dstu/src/test/resources/patient-example-us-extensions.xml b/hapi-fhir-structures-dstu/src/test/resources/patient-example-us-extensions.xml new file mode 100644 index 00000000000..7c50f10a43d --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/patient-example-us-extensions.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + +
NamePeter James Chalmers ("Jim")
Address534 Erewhon, Pleasantville, Orange County, 3999
ContactsHome: unknown. Work: (03) 5555 6473
IdMRN: 12345 (Acme Healthcare)
+
+
+ + + + + + + + + +
+ + + + + + + + +
+ + + +
diff --git a/hapi-fhir-structures-dstu/src/test/resources/patient.profile.json b/hapi-fhir-structures-dstu/src/test/resources/patient.profile.json new file mode 100644 index 00000000000..2ad4938e7f4 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/patient.profile.json @@ -0,0 +1,1121 @@ +{ + "resourceType": "Profile", + "text": { + "status": "generated", + "div": "
\r\n<Patient xmlns="http://hl7.org/fhir"> \"doco\"\r\n <!-- from Resource: extension, modifierExtension, language, text, and contained -->\r\n <identifier><!-- 0..* Identifier An identifier for the person as this patient § --></identifier>\r\n <name><!-- 0..* HumanName A name associated with the patient § --></name>\r\n <telecom><!-- 0..* Contact A contact detail for the individual § --></telecom>\r\n <gender><!-- 0..1 CodeableConcept Gender for administrative purposes § --></gender>\r\n <birthDate value="[dateTime]"/><!-- 0..1 The date and time of birth for the individual § -->\r\n <deceased[x]><!-- 0..1 boolean|dateTime Indicates if the individual is deceased or not § --></deceased[x]>\r\n <address><!-- 0..* Address Addresses for the individual § --></address>\r\n <maritalStatus><!-- 0..1 CodeableConcept Marital (civil) status of a person § --></maritalStatus>\r\n <multipleBirth[x]><!-- 0..1 boolean|integer \r\n     Whether patient is part of a multiple birth § --></multipleBirth[x]>\r\n <photo><!-- 0..* Attachment Image of the person --></photo>\r\n <contact>  <!-- 0..* A contact party (e.g. guardian, partner, friend) for the patient -->\r\n  <relationship><!-- 0..* CodeableConcept The kind of relationship --></relationship>\r\n  <name><!-- 0..1 HumanName A name associated with the person --></name>\r\n  <telecom><!-- 0..* Contact A contact detail for the person --></telecom>\r\n  <address><!-- 0..1 Address Address for the contact person --></address>\r\n  <gender><!-- 0..1 CodeableConcept Gender for administrative purposes --></gender>\r\n  <organization><!-- \"??\" 0..1 Resource(Organization) \r\n      Organization that is associated with the contact --></organization>\r\n </contact>\r\n <animal>  <!-- 0..1 If this patient is an animal (non-human) § -->\r\n  <species><!-- 1..1 CodeableConcept E.g. Dog, Cow § --></species>\r\n  <breed><!-- 0..1 CodeableConcept E.g. Poodle, Angus § --></breed>\r\n  <genderStatus><!-- 0..1 CodeableConcept E.g. Neutered, Intact § --></genderStatus>\r\n </animal>\r\n <communication><!-- 0..* CodeableConcept Languages which may be used to communicate with the patient about his or her health --></communication>\r\n <careProvider><!-- 0..* Resource(Organization|Practitioner) \r\n     Patient's nominated care provider --></careProvider>\r\n <managingOrganization><!-- 0..1 Resource(Organization) \r\n     Organization that is the custodian of the patient record § --></managingOrganization>\r\n <link>  <!-- 0..* Link to another patient resource that concerns the same actual person § -->\r\n  <other><!-- 1..1 Resource(Patient) The other patient resource that the link refers to § --></other>\r\n  <type value="[code]"/><!-- 1..1 replace | refer | seealso - type of link § -->\r\n </link>\r\n <active value="[boolean]"/><!-- 0..1 Whether this patient's record is in active use § -->\r\n</Patient>\r\n
" + }, + "name": "patient", + "publisher": "FHIR Project", + "description": "Basic Profile. Demographics and other administrative information about a person or animal receiving care or other health-related services.", + "status": "draft", + "date": "2014-05-09", + "requirements": "Scope and Usage This Resource covers data about persons and animals involved in a wide range of health-related activities, including: \r\n\r\n* Curative activities\r\n* Psychiatric care\r\n* Social services\r\n* Pregnancy care\r\n* Nursing and assisted living\r\n* Dietary services\r\n* Tracking of personal health and exercise data\r\nThe data in the Resource covers the \"who\" information about the patient: its attributes are focused on the demographic information necessary to support the administrative, financial and logistic procedures. A Patient record is generally created and maintained by each organization providing care for a patient. A person or animal receiving care at multiple organizations may therefore have its information present in multiple Patient Resources.", + "mapping": [ + { + "identity": "rim", + "uri": "http://hl7.org/v3", + "name": "RIM" + }, + { + "identity": "v2", + "uri": "http://hl7.org/v2", + "name": "HL7 v2" + } + ], + "structure": [ + { + "type": "Patient", + "publish": true, + "element": [ + { + "path": "Patient", + "definition": { + "short": "Information about a person or animal receiving health care services", + "formal": "Demographics and other administrative information about a person or animal receiving care or other health-related services.", + "min": 1, + "max": "1", + "type": [ + { + "code": "Resource" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "Patient[classCode=PAT]" + } + ] + } + }, + { + "path": "Patient.extension", + "definition": { + "short": "Additional Content defined by implementations", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.modifierExtension", + "definition": { + "short": "Extensions that cannot be ignored", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.text", + "definition": { + "short": "Text summary of the resource, for human interpretation", + "formal": "A human-readable narrative that contains a summary of the resource, and may be used to represent the content of the resource to a human. The narrative need not encode all the structured data, but is required to contain sufficient detail to make it \"clinically safe\" for a human to just read the narrative. Resource definitions may define what content should be represented in the narrative to ensure clinical safety.", + "comments": "Contained resources do not have narrative. Resources that are not contained SHOULD have a narrative.", + "synonym": [ + "narrative", + "html", + "xhtml", + "display" + ], + "min": 0, + "max": "1", + "type": [ + { + "code": "Narrative" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.contained", + "definition": { + "short": "Contained, inline Resources", + "formal": "These resources do not have an independent existence apart from the resource that contains them - they cannot be identified independently, and nor can they have their own independent transaction scope.", + "comments": "This should never be done when the content can be identified properly, as once identification is lost, it is extremely difficult (and context dependent) to restore it again.", + "synonym": [ + "inline resources", + "anonymous resources", + "contained resources" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Resource" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.identifier", + "definition": { + "short": "An identifier for the person as this patient", + "formal": "An identifier that applies to this person as a patient.", + "min": 0, + "max": "*", + "type": [ + { + "code": "Identifier" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "id" + }, + { + "identity": "v2", + "map": "PID-3" + } + ] + } + }, + { + "path": "Patient.name", + "definition": { + "short": "A name associated with the patient", + "formal": "A name associated with the individual.", + "comments": "Person may have multiple names with different uses or applicable periods.For animals, the name is a \"HumanName\" in the sense that is assigned and used by humans and has the same patterns.", + "min": 0, + "max": "*", + "type": [ + { + "code": "HumanName" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "name" + }, + { + "identity": "v2", + "map": "PID-5, PID-9" + } + ] + } + }, + { + "path": "Patient.telecom", + "definition": { + "short": "A contact detail for the individual", + "formal": "A contact detail (e.g. a telephone number or an email address) by which the individual may be contacted.", + "comments": "Person may have multiple ways to be contacted with different uses or applicable periods. \rMay need to have options for contacting the person urgently and also to help with identification. The address may not go directly to the individual, but may reach another party that is able to proxy for the patient (i.e. home phone, or pet owner's phone).", + "min": 0, + "max": "*", + "type": [ + { + "code": "Contact" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "telecom" + }, + { + "identity": "v2", + "map": "PID-13, PID-14, PID-40" + } + ] + } + }, + { + "path": "Patient.gender", + "definition": { + "short": "Gender for administrative purposes", + "formal": "Administrative Gender - the gender that the patient is considered to have for administration and record keeping purposes.", + "comments": "The gender may not match the biological sex as determined by genetics, or the individual's preferred identification. Note that for both humans and particularly animals, there are other legitimate possibilities than M and F, though the vast majority of systems and contexts only support M and F.", + "min": 0, + "max": "1", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "AdministrativeGender", + "isExtensible": true, + "conformance": "preferred", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/administrative-gender" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/administrativeGender" + }, + { + "identity": "v2", + "map": "PID-8" + } + ] + } + }, + { + "path": "Patient.birthDate", + "definition": { + "short": "The date and time of birth for the individual", + "formal": "The date and time of birth for the individual.", + "comments": "At least an estimated year should be provided as a guess if the real dob is unknown.", + "min": 0, + "max": "1", + "type": [ + { + "code": "dateTime" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/birthTime" + }, + { + "identity": "v2", + "map": "PID-7" + } + ] + } + }, + { + "path": "Patient.deceased[x]", + "definition": { + "short": "Indicates if the individual is deceased or not", + "formal": "Indicates if the individual is deceased or not.", + "comments": "If there's no value in the instance it means there is no statement on whether or not the individual is deceased. Most systems will interpret the absence of a value as a sign of the person being alive.", + "min": 0, + "max": "1", + "type": [ + { + "code": "boolean" + }, + { + "code": "dateTime" + } + ], + "isModifier": true, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/deceasedInd,\rplayer[classCode=PSN|ANM and determinerCode=INSTANCE]/deceasedTime" + }, + { + "identity": "v2", + "map": "PID-30\r (bool) and PID-29 (datetime)" + } + ] + } + }, + { + "path": "Patient.address", + "definition": { + "short": "Addresses for the individual", + "formal": "Addresses for the individual.", + "comments": "Person may have multiple addresses with different uses or applicable periods.", + "min": 0, + "max": "*", + "type": [ + { + "code": "Address" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "addr" + }, + { + "identity": "v2", + "map": "PID-11" + } + ] + } + }, + { + "path": "Patient.maritalStatus", + "definition": { + "short": "Marital (civil) status of a person", + "formal": "This field contains a patient's most recent marital (civil) status.", + "min": 0, + "max": "1", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "MaritalStatus", + "isExtensible": true, + "conformance": "preferred", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/marital-status" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN]/maritalStatusCode" + }, + { + "identity": "v2", + "map": "PID-16" + } + ] + } + }, + { + "path": "Patient.multipleBirth[x]", + "definition": { + "short": "Whether patient is part of a multiple birth", + "formal": "Indicates whether the patient is part of a multiple or indicates the actual birth order.", + "min": 0, + "max": "1", + "type": [ + { + "code": "boolean" + }, + { + "code": "integer" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/multipleBirthInd, \rplayer[classCode=PSN|ANM and determinerCode=INSTANCE]/multipleBirthOrderNumber" + }, + { + "identity": "v2", + "map": "PID-24 (bool), PID-25 (integer)" + } + ] + } + }, + { + "path": "Patient.photo", + "definition": { + "short": "Image of the person", + "formal": "Image of the person.", + "min": 0, + "max": "*", + "type": [ + { + "code": "Attachment" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/desc" + }, + { + "identity": "v2", + "map": "OBX-5 - needs a profile" + } + ] + } + }, + { + "path": "Patient.contact", + "definition": { + "short": "A contact party (e.g. guardian, partner, friend) for the patient", + "formal": "A contact party (e.g. guardian, partner, friend) for the patient.", + "comments": "Contact covers all kinds of contact parties: family members, business contacts, guardians, caregivers. Not applicable to register pedigree and family ties beyond use of having contact.", + "min": 0, + "max": "*", + "constraint": [ + { + "key": "1", + "name": "ContactNeedsDetails", + "severity": "error", + "human": "SHALL at least contain a contact's details or a reference to an organization", + "xpath": "f:name or f:telecom or f:address or f:organization" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/scopedRole[classCode=CON]" + } + ] + } + }, + { + "path": "Patient.contact.extension", + "definition": { + "short": "Additional Content defined by implementations", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.contact.modifierExtension", + "definition": { + "short": "Extensions that cannot be ignored", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.contact.relationship", + "definition": { + "short": "The kind of relationship", + "formal": "The nature of the relationship between the patient and the contact person.", + "min": 0, + "max": "*", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "ContactRelationship", + "isExtensible": true, + "conformance": "preferred", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/patient-contact-relationship" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "code" + }, + { + "identity": "v2", + "map": "NK1-7, NK1-3" + } + ] + } + }, + { + "path": "Patient.contact.name", + "definition": { + "short": "A name associated with the person", + "formal": "A name associated with the person.", + "min": 0, + "max": "1", + "type": [ + { + "code": "HumanName" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "name" + }, + { + "identity": "v2", + "map": "NK1-2" + } + ] + } + }, + { + "path": "Patient.contact.telecom", + "definition": { + "short": "A contact detail for the person", + "formal": "A contact detail for the person, e.g. a telephone number or an email address.", + "comments": "Person may have multiple ways to be contacted with different uses or applicable periods. \rMay need to have options for contacting the person urgently, and also to help with identification.", + "min": 0, + "max": "*", + "type": [ + { + "code": "Contact" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "telecom" + }, + { + "identity": "v2", + "map": "NK1-5, NK1-6, NK1-40" + } + ] + } + }, + { + "path": "Patient.contact.address", + "definition": { + "short": "Address for the contact person", + "formal": "Address for the contact person.", + "min": 0, + "max": "1", + "type": [ + { + "code": "Address" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "addr" + }, + { + "identity": "v2", + "map": "NK1-4" + } + ] + } + }, + { + "path": "Patient.contact.gender", + "definition": { + "short": "Gender for administrative purposes", + "formal": "Administrative Gender - the gender that the person is considered to have for administration and record keeping purposes.", + "min": 0, + "max": "1", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "AdministrativeGender", + "isExtensible": true, + "conformance": "preferred", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/administrative-gender" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/administrativeGender" + }, + { + "identity": "v2", + "map": "NK1-15" + } + ] + } + }, + { + "path": "Patient.contact.organization", + "definition": { + "short": "Organization that is associated with the contact", + "formal": "Organization on behalf of which the contact is acting or for which the contact is working.", + "min": 0, + "max": "1", + "type": [ + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Organization" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "scoper" + }, + { + "identity": "v2", + "map": "NK1-13, NK1-30, NK1-31, NK1-32, NK1-41" + } + ] + } + }, + { + "path": "Patient.animal", + "definition": { + "short": "If this patient is an animal (non-human)", + "formal": "This element has a value if the patient is an animal.", + "comments": "The animal element is labeled \"Is Modifier\" since patients may be non-human. Systems SHALL either handle patient details appropriately (e.g. inform users patient is not human) or reject non-human patient records.", + "min": 0, + "max": "1", + "isModifier": true, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=ANM]" + } + ] + } + }, + { + "path": "Patient.animal.extension", + "definition": { + "short": "Additional Content defined by implementations", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.animal.modifierExtension", + "definition": { + "short": "Extensions that cannot be ignored", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.animal.species", + "definition": { + "short": "E.g. Dog, Cow", + "formal": "Identifies the high level categorization of the kind of animal.", + "comments": "If the patient is non-human, at least a species SHALL be specified.", + "min": 1, + "max": "1", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "AnimalSpecies", + "isExtensible": true, + "conformance": "example", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/animal-species" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "code" + }, + { + "identity": "v2", + "map": "PID-35" + } + ] + } + }, + { + "path": "Patient.animal.breed", + "definition": { + "short": "E.g. Poodle, Angus", + "formal": "Identifies the detailed categorization of the kind of animal.", + "min": 0, + "max": "1", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "AnimalBreed", + "isExtensible": true, + "conformance": "example", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/animal-breeds" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "playedRole[classCode=GEN]/scoper[classCode=ANM, determinerCode=KIND]/code" + }, + { + "identity": "v2", + "map": "PID-37" + } + ] + } + }, + { + "path": "Patient.animal.genderStatus", + "definition": { + "short": "E.g. Neutered, Intact", + "formal": "Indicates the current state of the animal's reproductive organs.", + "min": 0, + "max": "1", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "AnimalGenderStatus", + "isExtensible": true, + "conformance": "example", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/animal-genderstatus" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "genderStatusCode" + }, + { + "identity": "v2", + "map": "N/A" + } + ] + } + }, + { + "path": "Patient.communication", + "definition": { + "short": "Languages which may be used to communicate with the patient about his or her health", + "formal": "Languages which may be used to communicate with the patient about his or her health.", + "comments": "If no language is specified, this *implies* that the default local language is spoken.\rFor animals, language is not a relevant field, and should be absent from the instance.", + "min": 0, + "max": "*", + "type": [ + { + "code": "CodeableConcept" + } + ], + "isModifier": false, + "binding": { + "name": "Language", + "isExtensible": false, + "conformance": "required", + "referenceUri": "http://tools.ietf.org/html/bcp47" + }, + "mapping": [ + { + "identity": "rim", + "map": "player[classCode=PSN|ANM and determinerCode=INSTANCE]/languageCommunication/code" + }, + { + "identity": "v2", + "map": "LAN-2" + } + ] + } + }, + { + "path": "Patient.careProvider", + "definition": { + "short": "Patient's nominated care provider", + "formal": "Patient's nominated care provider.", + "min": 0, + "max": "*", + "type": [ + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Organization" + }, + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Practitioner" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "subjectOf.CareEvent.performer.AssignedEntity" + } + ] + } + }, + { + "path": "Patient.managingOrganization", + "definition": { + "short": "Organization that is the custodian of the patient record", + "formal": "Organization that is the custodian of the patient record.", + "min": 0, + "max": "1", + "type": [ + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Organization" + } + ], + "isModifier": false, + "mapping": [ + { + "identity": "rim", + "map": "scoper" + } + ] + } + }, + { + "path": "Patient.link", + "definition": { + "short": "Link to another patient resource that concerns the same actual person", + "formal": "Link to another patient resource that concerns the same actual person.", + "comments": "There is no assumption that linked patient records have mutual links.", + "min": 0, + "max": "*", + "isModifier": true, + "mapping": [ + { + "identity": "rim", + "map": "outboundLink" + } + ] + } + }, + { + "path": "Patient.link.extension", + "definition": { + "short": "Additional Content defined by implementations", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.link.modifierExtension", + "definition": { + "short": "Extensions that cannot be ignored", + "formal": "May be used to represent additional information that is not part of the basic definition of the resource, and that modifies the understanding of the element that contains it. Usually modifier elements provide negation or qualification. In order to make the use of extensions safe and manageable, there is a strict governance applied to the definition and use of extensions. Though any implementer is allowed to define an extension, there is a set of requirements that SHALL be met as part of the definition of the extension. Applications processing a resource are required to check for modifier extensions.", + "comments": "there can be no stigma associated with the use of extensions by any application, project, or standard - regardless of the institution or jurisdiction that uses or defines the extensions. The use of extensions is what allows the FHIR specification to retain a core simplicity for everyone.", + "synonym": [ + "extensions", + "user content" + ], + "min": 0, + "max": "*", + "type": [ + { + "code": "Extension" + } + ], + "isModifier": false + } + }, + { + "path": "Patient.link.other", + "definition": { + "short": "The other patient resource that the link refers to", + "formal": "The other patient resource that the link refers to.", + "min": 1, + "max": "1", + "type": [ + { + "code": "ResourceReference", + "profile": "http://hl7.org/fhir/profiles/Patient" + } + ], + "isModifier": true, + "mapping": [ + { + "identity": "rim", + "map": "id" + }, + { + "identity": "v2", + "map": "PID-3, MRG-1" + } + ] + } + }, + { + "path": "Patient.link.type", + "definition": { + "short": "replace | refer | seealso - type of link", + "formal": "The type of link between this patient resource and another patient resource.", + "min": 1, + "max": "1", + "type": [ + { + "code": "code" + } + ], + "isModifier": true, + "binding": { + "name": "LinkType", + "isExtensible": false, + "conformance": "required", + "referenceResource": { + "reference": "http://hl7.org/fhir/vs/link-type" + } + }, + "mapping": [ + { + "identity": "rim", + "map": "typeCode" + } + ] + } + }, + { + "path": "Patient.active", + "definition": { + "short": "Whether this patient's record is in active use", + "formal": "Whether this patient record is in active use.", + "comments": "Default is true. If a record is inactive, and linked to an active record, then future patient/person/record updates should occur on the other patient.", + "min": 0, + "max": "1", + "type": [ + { + "code": "boolean" + } + ], + "isModifier": true, + "mapping": [ + { + "identity": "rim", + "map": "statusCode" + } + ] + } + } + ], + "searchParam": [ + { + "name": "_id", + "type": "token", + "documentation": "The logical resource id associated with the resource (must be supported by all servers)" + }, + { + "name": "_language", + "type": "token", + "documentation": "The language of the resource" + }, + { + "name": "active", + "type": "token", + "documentation": "Whether the patient record is active", + "xpath": "f:Patient/f:active" + }, + { + "name": "address", + "type": "string", + "documentation": "An address in any kind of address/part of the patient", + "xpath": "f:Patient/f:address" + }, + { + "name": "animal-breed", + "type": "token", + "documentation": "The breed for animal patients", + "xpath": "f:Patient/f:animal/f:breed" + }, + { + "name": "animal-species", + "type": "token", + "documentation": "The species for animal patients", + "xpath": "f:Patient/f:animal/f:species" + }, + { + "name": "birthdate", + "type": "date", + "documentation": "The patient's date of birth", + "xpath": "f:Patient/f:birthDate" + }, + { + "name": "family", + "type": "string", + "documentation": "A portion of the family name of the patient", + "xpath": "f:Patient/f:name/f:family" + }, + { + "name": "gender", + "type": "token", + "documentation": "Gender of the patient", + "xpath": "f:Patient/f:gender" + }, + { + "name": "given", + "type": "string", + "documentation": "A portion of the given name of the patient", + "xpath": "f:Patient/f:name/f:given" + }, + { + "name": "identifier", + "type": "token", + "documentation": "A patient identifier", + "xpath": "f:Patient/f:identifier" + }, + { + "name": "language", + "type": "token", + "documentation": "Language code (irrespective of use value)", + "xpath": "f:Patient/f:communication" + }, + { + "name": "link", + "type": "reference", + "documentation": "All patients linked to the given patient", + "xpath": "f:Patient/f:link/f:other" + }, + { + "name": "name", + "type": "string", + "documentation": "A portion of either family or given name of the patient", + "xpath": "f:Patient/f:name" + }, + { + "name": "phonetic", + "type": "string", + "documentation": "A portion of either family or given name using some kind of phonetic matching algorithm" + }, + { + "name": "provider", + "type": "reference", + "documentation": "The organization at which this person is a patient", + "xpath": "f:Patient/f:managingOrganization" + }, + { + "name": "telecom", + "type": "string", + "documentation": "The value in any kind of telecom details of the patient", + "xpath": "f:Patient/f:telecom" + } + ] + } + ] +} \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/questionnaire-example.xml b/hapi-fhir-structures-dstu/src/test/resources/questionnaire-example.xml new file mode 100644 index 00000000000..409795045e2 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/questionnaire-example.xml @@ -0,0 +1,200 @@ + + + +
+
+            Comorbidity? YES
+              Cardial Comorbidity? YES
+                Angina? YES
+                MI? NO
+              Vascular Comorbidity?
+                (no answers)
+              ...
+            Histopathology
+              Abdominal
+                pT category: 1a
+              ...
+          
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/hapi-fhir-structures-dstu/src/test/resources/securitytest_war/WEB-INF/app-ctx.xml b/hapi-fhir-structures-dstu/src/test/resources/securitytest_war/WEB-INF/app-ctx.xml new file mode 100644 index 00000000000..448015e942a --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/securitytest_war/WEB-INF/app-ctx.xml @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + openid + email + address + profile + phone + + + + + + http://localhost:8080/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/securitytest_war/WEB-INF/web.xml b/hapi-fhir-structures-dstu/src/test/resources/securitytest_war/WEB-INF/web.xml new file mode 100644 index 00000000000..56e6a03c828 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/securitytest_war/WEB-INF/web.xml @@ -0,0 +1,35 @@ + + + + + springSecurityFilterChain + org.springframework.web.filter.DelegatingFilterProxy + + + + springSecurityFilterChain + /* + + + + org.springframework.web.context.ContextLoaderListener + + + + contextConfigLocation + + WEB-INF/app-ctx.xml + + + + + fhir + ca.uhn.fhir.rest.server.ServerSecurityTestRestfulServlet + + + + fhir + /fhir/* + + + \ No newline at end of file diff --git a/hapi-fhir-structures-dstu/src/test/resources/server-conformance-statement.xml b/hapi-fhir-structures-dstu/src/test/resources/server-conformance-statement.xml new file mode 100644 index 00000000000..740f516e876 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/server-conformance-statement.xml @@ -0,0 +1,101 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-structures-dstu/src/test/resources/xhtml1-strict.xsd b/hapi-fhir-structures-dstu/src/test/resources/xhtml1-strict.xsd new file mode 100644 index 00000000000..3e9de992a03 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/xhtml1-strict.xsd @@ -0,0 +1,2044 @@ + + + + + + XHTML 1.0 (Second Edition) Strict in XML Schema + + This is the same as HTML 4 Strict except for + changes due to the differences between XML and SGML. + + Namespace = http://www.w3.org/1999/xhtml + + For further information, see: http://www.w3.org/TR/xhtml1 + + Copyright (c) 1998-2002 W3C (MIT, INRIA, Keio), + All Rights Reserved. + + The DTD version is identified by the PUBLIC and SYSTEM identifiers: + + PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" + + _id: xhtml1-strict.xsd,v 1.2 2002/08/28 08:05:44 mimasa Exp $ + + + + + + ================ Character mnemonic entities ========================= + + XHTML entity sets are identified by the PUBLIC and SYSTEM identifiers: + + PUBLIC "-//W3C//ENTITIES Latin 1 for XHTML//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent" + + PUBLIC "-//W3C//ENTITIES Special for XHTML//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent" + + PUBLIC "-//W3C//ENTITIES Symbols for XHTML//EN" + SYSTEM "http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent" + + + + + ================== Imported Names ==================================== + + + + + + media type, as per [RFC2045] + + + + + + + + comma-separated list of media types, as per [RFC2045] + + + + + + + + a character encoding, as per [RFC2045] + + + + + + + + a space separated list of character encodings, as per [RFC2045] + + + + + + + + a language code, as per [RFC3066] + + + + + + + + a single character, as per section 2.2 of [XML] + + + + + + + + + + one or more digits + + + + + + + + + + tabindex attribute specifies the position of the current element + in the tabbing order for the current document. This value must be + a number between 0 and 32767. User agents should ignore leading zeros. + + + + + + + + + + + space-separated list of link types + + + + + + + + single or comma-separated list of media descriptors + + + + + + + + + + a Uniform Resource Identifier, see [RFC2396] + + + + + + + + a space separated list of Uniform Resource Identifiers + + + + + + + + date and time information. ISO date format + + + + + + + + script expression + + + + + + + + style sheet data + + + + + + + + used for titles etc. + + + + + + + + nn for pixels or nn% for percentage length + + + + + + + + + + pixel, percentage, or relative + + + + + + + + + + integer representing length in pixels + + + + + + + these are used for image maps + + + + + + + + + + + + + + comma separated list of lengths + + + + + + + + + =================== Generic Attributes =============================== + + + + + + core attributes common to most elements + id document-wide unique id + class space separated list of classes + style associated style info + title advisory title/amplification + + + + + + + + + + + internationalization attributes + lang language code (backwards compatible) + xml:lang language code (as per XML 1.0 spec) + dir direction for weak/neutral text + + + + + + + + + + + + + + + + + attributes for common UI events + onclick a pointer button was clicked + ondblclick a pointer button was double clicked + onmousedown a pointer button was pressed down + onmouseup a pointer button was released + onmousemove a pointer was moved onto the element + onmouseout a pointer was moved away from the element + onkeypress a key was pressed and released + onkeydown a key was pressed down + onkeyup a key was released + + + + + + + + + + + + + + + + + attributes for elements that can get the focus + accesskey accessibility key character + tabindex position in tabbing order + onfocus the element got the focus + onblur the element lost the focus + + + + + + + + + + + + + + + =================== Text Elements ==================================== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + these can only occur at block level + + + + + + + + + + + + + + + + + + + + "Inline" covers inline or "text-level" elements + + + + + + + + + + ================== Block level elements ============================== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + "Flow" mixes block and inline and is used for list items etc. + + + + + + + + + + + + ================== Content models for exclusions ===================== + + + + + + a elements use "Inline" excluding a + + + + + + + + + + + + + + pre uses "Inline" excluding big, small, sup or sup + + + + + + + + + + + + + + + form uses "Block" excluding form + + + + + + + + + + + button uses "Flow" but excludes a, form and form controls + + + + + + + + + + + + + + + + + + ================ Document Structure ================================== + + + + + + + + + + + + + + + ================ Document Head ======================================= + + + + + + + + + + + + + + + + + content model is "head.misc" combined with a single + title and an optional base element in any order + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The title element is not considered part of the flow of text. + It should be displayed, for example as the page header or + window title. Exactly one title is required per document. + + + + + + + + + + + document base URI + + + + + + + + + + + generic metainformation + + + + + + + + + + + + + + + Relationship values can be used in principle: + + a) for document specific toolbars/menus when used + with the link element in document head e.g. + start, contents, previous, next, index, end, help + b) to link to a separate style sheet (rel="stylesheet") + c) to make a link to a script (rel="script") + d) by stylesheets to control how collections of + html nodes are rendered into printed documents + e) to make a link to a printable version of this document + e.g. a PostScript or PDF version (rel="alternate" media="print") + + + + + + + + + + + + + + + + + style info, which may include CDATA sections + + + + + + + + + + + + + + + script statements, which may include CDATA sections + + + + + + + + + + + + + + + + + + + + + alternate content container for non script-based rendering + + + + + + + + + + + + + =================== Document Body ==================================== + + + + + + + + + + + + + + + + + generic language/style container + + + + + + + + + + + + + =================== Paragraphs ======================================= + + + + + + + + + + + + + + =================== Headings ========================================= + + There are six levels of headings from h1 (the most important) + to h6 (the least important). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + =================== Lists ============================================ + + + + + + Unordered list + + + + + + + + + + + + + Ordered (numbered) list + + + + + + + + + + + + + list item + + + + + + + + + + + + + definition lists - dt for term, dd for its definition + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + =================== Address ========================================== + + + + + + information on author + + + + + + + + + + + + + =================== Horizontal Rule ================================== + + + + + + + + + + =================== Preformatted Text ================================ + + + + + + content is "Inline" excluding "img|object|big|small|sub|sup" + + + + + + + + + + + + + + =================== Block-like Quotes ================================ + + + + + + + + + + + + + + + =================== Inserted/Deleted Text ============================ + + ins/del are allowed in block and inline content, but its + inappropriate to include block content within an ins element + occurring in inline content. + + + + + + + + + + + + + + + + + + + + + + + + + + + ================== The Anchor Element ================================ + + + + + + content is "Inline" except that anchors shouldn't be nested + + + + + + + + + + + + + + + + + + + + + + + ===================== Inline Elements ================================ + + + + + + generic language/style container + + + + + + + + + + + + + + I18N BiDi over-ride + + + + + + + + + + + + + + + + + + + + + + + + + forced line break + + + + + + + + + + emphasis + + + + + + + + + + + + + + strong emphasis + + + + + + + + + + + + + + definitional + + + + + + + + + + + + + + program code + + + + + + + + + + + + + + sample + + + + + + + + + + + + + + something user would type + + + + + + + + + + + + + + variable + + + + + + + + + + + + + + citation + + + + + + + + + + + + + + abbreviation + + + + + + + + + + + + + + acronym + + + + + + + + + + + + + + inlined quote + + + + + + + + + + + + + + + subscript + + + + + + + + + + + + + + superscript + + + + + + + + + + + + + + fixed pitch font + + + + + + + + + + + + + + italic font + + + + + + + + + + + + + + bold font + + + + + + + + + + + + + + bigger font + + + + + + + + + + + + + + smaller font + + + + + + + + + + + + + ==================== Object ====================================== + + object is used to embed objects as part of HTML pages. + param elements should precede other content. Parameters + can also be expressed as attribute/value pairs on the + object element itself when brevity is desired. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + param is used to supply a named property value. + In XML it would seem natural to follow RDF and support an + abbreviated syntax where the param elements are replaced + by attribute value pairs on the object start tag. + + + + + + + + + + + + + + + + + + + + + =================== Images =========================================== + + To avoid accessibility problems for people who aren't + able to see the image, you should provide a text + description using the alt and longdesc attributes. + In addition, avoid the use of server-side image maps. + Note that in this DTD there is no name attribute. That + is only available in the transitional and frameset DTD. + + + + + + + + + + + + + + usemap points to a map element which may be in this document + or an external document, although the latter is not widely supported + + + + + + + + + + + + + + + ================== Client-side image maps ============================ + + These can be placed in the same document or grouped in a + separate document although this isn't yet widely supported + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ================ Forms =============================================== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Each label must not contain more than ONE field + Label elements shouldn't be nested. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + form control + + + + + + + + + + the name attribute is required for all but submit & reset + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + option selector + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + option group + + + + + + + + + + + + + + + + + + + + + selectable choice + + + + + + + + + + + + + + + + + + + + + + + + + + multi-line text field + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The fieldset element is used to group form fields. + Only one legend element should occur in the content + and if present should only be preceded by whitespace. + + NOTE: this content model is different from the XHTML 1.0 DTD, + closer to the intended content model in HTML4 DTD + + + + + + + + + + + + + + + + + + + fieldset label + + + + + + + + + + + + + + + Content is "Flow" excluding a, form and form controls + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ======================= Tables ======================================= + + Derived from IETF HTML table standard, see [RFC1942] + + + + + + The border attribute sets the thickness of the frame around the + table. The default units are screen pixels. + + The frame attribute specifies which parts of the frame around + the table should be rendered. The values are not the same as + CALS to avoid a name clash with the valign attribute. + + + + + + + + + + + + + + + + + + The rules attribute defines which rules to draw between cells: + + If rules is absent then assume: + "none" if border is absent or border="0" otherwise "all" + + + + + + + + + + + + + + horizontal alignment attributes for cell contents + + char alignment char, e.g. char=':' + charoff offset for alignment char + + + + + + + + + + + + + + + + + + + + vertical alignment attributes for cell contents + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use thead to duplicate headers when breaking table + across page boundaries, or for static headers when + tbody sections are rendered in scrolling panel. + + Use tfoot to duplicate footers when breaking table + across page boundaries, or for static footers when + tbody sections are rendered in scrolling panel. + + Use multiple tbody sections when rules are needed + between groups of table rows. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + colgroup groups a set of col elements. It allows you to group + several semantically related columns together. + + + + + + + + + + + + + + + + + col elements define the alignment properties for cells in + one or more columns. + + The width attribute specifies the width of the columns, e.g. + + width=64 width in screen pixels + width=0.5* relative width of 0.5 + + The span attribute causes the attributes of one + col element to apply to more than one column. + + + + + + + + + + + + + + + + + + + + + + + + + Scope is simpler than headers attribute for common tables + + + + + + + + + + + + th is for headers, td for data and for cells acting as both + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-structures-dstu/src/test/resources/xml.xsd b/hapi-fhir-structures-dstu/src/test/resources/xml.xsd new file mode 100644 index 00000000000..efe005d46d8 --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/xml.xsd @@ -0,0 +1,272 @@ + + + + + + +
+

About the XML namespace

+
+

+ This schema document describes the XML namespace, in a form + suitable for import by other schema documents. +

+

+ See + http://www.w3.org/XML/1998/namespace.html and + + http://www.w3.org/TR/REC-xml for information + about this namespace. +

+

+ Note that local names in this namespace are intended to be + defined only by the World Wide Web Consortium or its subgroups. + The names currently defined in this namespace are listed below. + They should not be used with conflicting semantics by any Working + Group, specification, or document instance. +

+

+ See further below in this document for more information about how to refer to this schema document from your own + XSD schema documents and about the + namespace-versioning policy governing this schema document. +

+
+
+
+
+ + + +
+

lang (as an attribute name)

+

+ denotes an attribute whose value + is a language code for the natural language of the content of + any element; its value is inherited. This name is reserved + by virtue of its definition in the XML specification.

+
+
+

Notes

+

+ Attempting to install the relevant ISO 2- and 3-letter + codes as the enumerated possible values is probably never + going to be a realistic possibility. +

+

+ See BCP 47 at + http://www.rfc-editor.org/rfc/bcp/bcp47.txt + and the IANA language subtag registry at + + http://www.iana.org/assignments/language-subtag-registry + for further information. +

+

+ The union allows for the 'un-declaration' of xml:lang with + the empty string. +

+
+
+
+ + + + + + + + + +
+ + + +
+

space (as an attribute name)

+

+ denotes an attribute whose + value is a keyword indicating what whitespace processing + discipline is intended for the content of the element; its + value is inherited. This name is reserved by virtue of its + definition in the XML specification.

+
+
+
+ + + + + + +
+ + + +
+

base (as an attribute name)

+

+ denotes an attribute whose value + provides a URI to be used as the base for interpreting any + relative URIs in the scope of the element on which it + appears; its value is inherited. This name is reserved + by virtue of its definition in the XML Base specification.

+

+ See http://www.w3.org/TR/xmlbase/ + for information about this attribute. +

+
+
+
+
+ + + +
+

id (as an attribute name)

+

+ denotes an attribute whose value + should be interpreted as if declared to be of type ID. + This name is reserved by virtue of its definition in the + xml:id specification.

+

+ See http://www.w3.org/TR/xml-id/ + for information about this attribute. +

+
+
+
+
+ + + + + + + + +
+

Father (in any context at all)

+
+

+ denotes Jon Bosak, the chair of + the original XML Working Group. This name is reserved by + the following decision of the W3C XML Plenary and + XML Coordination groups: +

+
+

+ In appreciation for his vision, leadership and + dedication the W3C XML Plenary on this 10th day of + February, 2000, reserves for Jon Bosak in perpetuity + the XML name "xml:Father". +

+
+
+
+
+
+ + +
+

+ About this schema document +

+
+

+ This schema defines attributes and an attribute group suitable + for use by schemas wishing to allow xml:base, + xml:lang, xml:space or + xml:id attributes on elements they define. +

+

+ To enable this, such a schema must import this schema for + the XML namespace, e.g. as follows: +

+
+          <schema . . .>
+           . . .
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2001/xml.xsd"/>
+     
+

+ or +

+
+           <import namespace="http://www.w3.org/XML/1998/namespace"
+                      schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
+     
+

+ Subsequently, qualified reference to any of the attributes or the + group defined below will have the desired effect, e.g. +

+
+          <type . . .>
+           . . .
+           <attributeGroup ref="xml:specialAttrs"/>
+     
+

+ will define a type which will schema-validate an instance element + with any of those attributes. +

+
+
+
+
+ + +
+

+ Versioning policy for this schema document +

+
+

+ In keeping with the XML Schema WG's standard versioning + policy, this schema document will persist at + + http://www.w3.org/2009/01/xml.xsd. +

+

+ At the date of issue it can also be found at + + http://www.w3.org/2001/xml.xsd. +

+

+ The schema document at that URI may however change in the future, + in order to remain compatible with the latest version of XML + Schema itself, or with the XML namespace itself. In other words, + if the XML Schema or XML namespaces change, the version of this + document at + http://www.w3.org/2001/xml.xsd + + will change accordingly; the version at + + http://www.w3.org/2009/01/xml.xsd + + will not change. +

+

+ Previous dated (and unchanging) versions of this schema + document are at: +

+ +
+
+
+
+
diff --git a/hapi-fhir-structures-dstu/src/test/resources/xmlexample.xml b/hapi-fhir-structures-dstu/src/test/resources/xmlexample.xml new file mode 100644 index 00000000000..2260091a4da --- /dev/null +++ b/hapi-fhir-structures-dstu/src/test/resources/xmlexample.xml @@ -0,0 +1,114 @@ + + + +
+ + + + + + + + + + + + + + + + + + + +
NamePeter James Chalmers ("Jim")
Address534 Erewhon, Pleasantville, Vic, 3999
ContactsHome: unknown. Work: (03) 5555 6473
IdMRN: 12345 (Acme Healthcare)
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/hapi-fhir-testpage-overlay/.classpath b/hapi-fhir-testpage-overlay/.classpath index 97ac003ddee..5f121c3e99b 100644 --- a/hapi-fhir-testpage-overlay/.classpath +++ b/hapi-fhir-testpage-overlay/.classpath @@ -1,180 +1,201 @@ + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-testpage-overlay/.project b/hapi-fhir-testpage-overlay/.project index b44d8276004..bd4bfef659e 100644 --- a/hapi-fhir-testpage-overlay/.project +++ b/hapi-fhir-testpage-overlay/.project @@ -1,16 +1,44 @@ + - hapi-fhir-testpage-overlay - NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse. - - hapi-fhir-jpaserver-base - hapi-fhir-jpaserver-test - - - - org.eclipse.jdt.core.javabuilder - - - - org.eclipse.jdt.core.javanature - - \ No newline at end of file + hapi-fhir-testpage-overlay + NO_M2ECLIPSE_SUPPORT: Project files created with the maven-eclipse-plugin are not supported in M2Eclipse. + + hapi-fhir-jpaserver-base + hapi-fhir-jpaserver-test + + + + org.eclipse.wst.jsdt.core.javascriptValidator + + + + + org.eclipse.wst.common.project.facet.core.builder + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + org.eclipse.wst.validation.validationbuilder + + + + + + org.eclipse.jem.workbench.JavaEMFNature + org.eclipse.wst.common.modulecore.ModuleCoreNature + org.eclipse.m2e.core.maven2Nature + org.eclipse.jdt.core.javanature + org.eclipse.wst.common.project.facet.core.nature + org.eclipse.wst.jsdt.core.jsNature + + diff --git a/hapi-fhir-testpage-overlay/.settings/org.eclipse.jdt.core.prefs b/hapi-fhir-testpage-overlay/.settings/org.eclipse.jdt.core.prefs index 3f9a1773abb..69c31cd493c 100644 --- a/hapi-fhir-testpage-overlay/.settings/org.eclipse.jdt.core.prefs +++ b/hapi-fhir-testpage-overlay/.settings/org.eclipse.jdt.core.prefs @@ -1,5 +1,8 @@ -#Sun Aug 10 11:41:00 EDT 2014 -org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 eclipse.preferences.version=1 -org.eclipse.jdt.core.compiler.source=1.6 +org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled +org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 org.eclipse.jdt.core.compiler.compliance=1.6 +org.eclipse.jdt.core.compiler.problem.assertIdentifier=error +org.eclipse.jdt.core.compiler.problem.enumIdentifier=error +org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning +org.eclipse.jdt.core.compiler.source=1.6 diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index 1e2b0fadc5f..36604cc760b 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 0.7 + 0.8-SNAPSHOT ../pom.xml @@ -27,7 +27,12 @@ ca.uhn.hapi.fhir hapi-fhir-base - 0.7 + 0.8-SNAPSHOT + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT org.thymeleaf @@ -50,7 +55,7 @@ ca.uhn.hapi.fhir hapi-fhir-jpaserver-test - 0.7 + 0.8-SNAPSHOT test @@ -72,13 +77,15 @@ ${hamcrest_version} test + + commons-dbcp diff --git a/hapi-fhir-testpage-overlay/pom.xml.orig b/hapi-fhir-testpage-overlay/pom.xml.orig new file mode 100644 index 00000000000..997d6f28ff5 --- /dev/null +++ b/hapi-fhir-testpage-overlay/pom.xml.orig @@ -0,0 +1,245 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-fhir + 0.8-SNAPSHOT + ../pom.xml + + + hapi-fhir-testpage-overlay + war + + HAPI FHIR TestPage Overlay + + + + oss-snapshots + + true + + https://oss.sonatype.org/content/repositories/snapshots/ + + + + + + ca.uhn.hapi.fhir + hapi-fhir-base + 0.8-SNAPSHOT +<<<<<<< HEAD +======= + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + 0.8-SNAPSHOT +>>>>>>> versions + + + org.thymeleaf + thymeleaf + ${thymeleaf-version} + + + org.thymeleaf + thymeleaf-spring4 + ${thymeleaf-version} + + + + javax.servlet + javax.servlet-api + 3.1.0 + provided + + + + ca.uhn.hapi.fhir + hapi-fhir-jpaserver-test + 0.8-SNAPSHOT + test + + + + ch.qos.logback + logback-classic + ${logback_version} + test + + + junit + junit + ${junit_version} + test + + + org.hamcrest + hamcrest-all + ${hamcrest_version} + test + + + net.sourceforge.htmlunit + htmlunit + 2.16-SNAPSHOT + test + + + + + commons-dbcp + commons-dbcp + 1.4 + test + + + + + org.apache.derby + derby + ${derby_version} + test + + + + + + aopalliance + aopalliance + 1.0 + + + org.springframework + spring-core + ${spring_version} + + + org.springframework + spring-orm + ${spring_version} + + + org.springframework + spring-webmvc + ${spring_version} + + + org.springframework + spring-context + ${spring_version} + + + xml-apis + xml-apis + + + + + org.springframework + spring-beans + ${spring_version} + + + org.springframework + spring-tx + ${spring_version} + + + org.springframework + spring-context-support + ${spring_version} + + + org.springframework + spring-web + ${spring_version} + + + + + org.eclipse.jetty + jetty-servlets + ${jetty_version} + test + + + org.eclipse.jetty + jetty-webapp + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-server + ${jetty_version} + test + + + org.eclipse.jetty + jetty-servlet + ${jetty_version} + test + + + org.eclipse.jetty + jetty-util + ${jetty_version} + test + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 1.6 + 1.6 + + + + + + + maven-antrun-plugin + 1.7 + + + copyNarrativeCss + process-resources + + run + + + + + + + + + + + + + + + org.apache.maven.plugins + maven-deploy-plugin + + false + + + + + + diff --git a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java index 0db4d18adc2..1cb52eaf2c8 100644 --- a/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java +++ b/hapi-fhir-testpage-overlay/src/main/java/ca/uhn/fhir/to/Controller.java @@ -1009,7 +1009,7 @@ public class Controller { } if (StringUtils.isNotBlank(theReq.getParameter("param." + paramIdxString + ".0.name"))) { - handleSearchParam(paramIdxString + ".0", theReq, theQuery, theClientCodeJsonWriter); + handleSearchParam(paramIdxString + ".0", theReq, theQuery , theClientCodeJsonWriter); } return true; @@ -1020,7 +1020,7 @@ public class Controller { Conformance conformance; try { - conformance = client.conformance(); + conformance = (Conformance)client.conformance(); } catch (Exception e) { ourLog.warn("Failed to load conformance statement", e); theModel.put("errorMsg", "Failed to load conformance statement, error was: " + e.toString()); diff --git a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java index c064e31d2b2..32c549feccd 100644 --- a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java +++ b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/OverlayTestApp.java @@ -32,8 +32,8 @@ import ca.uhn.fhir.rest.annotation.RequiredParam; import ca.uhn.fhir.rest.annotation.Search; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.client.IGenericClient; -import ca.uhn.fhir.rest.param.CodingListParam; import ca.uhn.fhir.rest.param.DateRangeParam; +import ca.uhn.fhir.rest.param.TokenOrListParam; import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider; import ca.uhn.fhir.rest.server.IResourceProvider; import ca.uhn.fhir.rest.server.RestfulServer; @@ -173,7 +173,7 @@ public class OverlayTestApp { @Search public List findDiagnosticReportsByPatient ( @RequiredParam(name=DiagnosticReport.SP_SUBJECT + '.' + Patient.SP_IDENTIFIER) IdentifierDt thePatientId, - @OptionalParam(name=DiagnosticReport.SP_NAME) CodingListParam theNames, + @OptionalParam(name=DiagnosticReport.SP_NAME) TokenOrListParam theNames, @OptionalParam(name=DiagnosticReport.SP_DATE) DateRangeParam theDateRange, @IncludeParam(allow= {"DiagnosticReport.result"}) Set theIncludes ) throws Exception { @@ -184,7 +184,7 @@ public class OverlayTestApp { @Search public List findDiagnosticReportsByPatientIssued ( @RequiredParam(name=DiagnosticReport.SP_SUBJECT + '.' + Patient.SP_IDENTIFIER) IdentifierDt thePatientId, - @OptionalParam(name=DiagnosticReport.SP_NAME) CodingListParam theNames, + @OptionalParam(name=DiagnosticReport.SP_NAME) TokenOrListParam theNames, @OptionalParam(name=DiagnosticReport.SP_ISSUED) DateRangeParam theDateRange, @IncludeParam(allow= {"DiagnosticReport.result"}) Set theIncludes ) throws Exception { diff --git a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/WebUiTest_.java b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/WebUiTest_.java index e644894c81c..652862cf15a 100644 --- a/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/WebUiTest_.java +++ b/hapi-fhir-testpage-overlay/src/test/java/ca/uhn/fhir/jpa/test/WebUiTest_.java @@ -43,9 +43,9 @@ import ca.uhn.test.jpasrv.OrganizationResourceProvider; import ca.uhn.test.jpasrv.PatientResourceProvider; import ca.uhn.test.jpasrv.QuestionnaireResourceProvider; -import com.gargoylesoftware.htmlunit.BrowserVersion; -import com.gargoylesoftware.htmlunit.WebClient; -import com.gargoylesoftware.htmlunit.html.HtmlPage; +//import com.gargoylesoftware.htmlunit.BrowserVersion; +//import com.gargoylesoftware.htmlunit.WebClient; +//import com.gargoylesoftware.htmlunit.html.HtmlPage; public class WebUiTest_ { @@ -57,17 +57,17 @@ private static ClassPathXmlApplicationContext appCtx; // @Test public void homePage() throws Exception { - final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24); - final HtmlPage page = webClient.getPage("http://localhost:8888/"); - Assert.assertEquals("HtmlUnit - Welcome to HtmlUnit", page.getTitleText()); - - final String pageAsXml = page.asXml(); - Assert.assertTrue(pageAsXml.contains("")); - - final String pageAsText = page.asText(); - Assert.assertTrue(pageAsText.contains("Support for the HTTP and HTTPS protocols")); - - webClient.closeAllWindows(); +// final WebClient webClient = new WebClient(BrowserVersion.FIREFOX_24); +// final HtmlPage page = webClient.getPage("http://localhost:8888/"); +// Assert.assertEquals("HtmlUnit - Welcome to HtmlUnit", page.getTitleText()); +// +// final String pageAsXml = page.asXml(); +// Assert.assertTrue(pageAsXml.contains("")); +// +// final String pageAsText = page.asText(); +// Assert.assertTrue(pageAsText.contains("Support for the HTTP and HTTPS protocols")); +// +// webClient.closeAllWindows(); } @SuppressWarnings("unchecked") diff --git a/hapi-tinder-plugin/.classpath b/hapi-tinder-plugin/.classpath index 534b5e52fa5..832ed6c6d27 100644 --- a/hapi-tinder-plugin/.classpath +++ b/hapi-tinder-plugin/.classpath @@ -6,6 +6,7 @@ + @@ -22,6 +23,7 @@ + diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index 642ca0ff166..e9f510b3eb7 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 0.7 + 0.8-SNAPSHOT ../pom.xml @@ -19,9 +19,16 @@ ca.uhn.hapi.fhir hapi-fhir-base - 0.7 + 0.8-SNAPSHOT - + + org.apache.velocity velocity @@ -34,16 +41,16 @@ - com.google.guava - guava - 17.0 + com.google.guava + guava + ${guava_version} org.apache.commons commons-lang3 - 3.2.1 + ${commons_lang_version} commons-io @@ -139,7 +146,8 @@ - + org.eclipse.m2e lifecycle-mapping diff --git a/hapi-tinder-plugin/pom.xml.orig b/hapi-tinder-plugin/pom.xml.orig new file mode 100644 index 00000000000..fa1f3bf3cd2 --- /dev/null +++ b/hapi-tinder-plugin/pom.xml.orig @@ -0,0 +1,189 @@ + + 4.0.0 + + + ca.uhn.hapi.fhir + hapi-fhir + 0.8-SNAPSHOT + ../pom.xml + + + hapi-tinder-plugin + maven-plugin + + + HAPI Tinder Plugin + + + + ca.uhn.hapi.fhir + hapi-fhir-base + 0.8-SNAPSHOT +<<<<<<< HEAD +======= + + + + + org.apache.velocity + velocity + 1.7 + + + org.apache.velocity + velocity-tools + 2.0 + + + + com.google.guava + guava + 17.0 + + + + + org.apache.commons + commons-lang3 + 3.2.1 + + + commons-io + commons-io + 2.4 + + + + + org.slf4j + slf4j-api + 1.7.6 + + + ch.qos.logback + logback-classic + 1.1.1 + true + + + + + junit + junit + 4.11 + test + + + + + org.apache.maven + maven-project + 2.2.1 + + + org.apache.maven + maven-plugin-api + 3.2.1 + + + org.apache.maven.plugin-tools + maven-plugin-annotations + 3.2 + provided + + + + + 3.1.1 + + + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.2 + + + + report + + + + + + + + + + + org.apache.maven.plugins + maven-plugin-plugin + 3.2 + + + true + + + + + mojo-descriptor + + descriptor + + + + + + + + + + + org.eclipse.m2e + lifecycle-mapping + 1.0.0 + + + + + + + org.apache.maven.plugins + + + maven-plugin-plugin + + + [3.2,) + + + descriptor + + + + + + + + + + + + + + + + diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java new file mode 100644 index 00000000000..085b0f926d9 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/FhirDstu1.java @@ -0,0 +1,26 @@ +package ca.uhn.fhir.model.dstu; + +import ca.uhn.fhir.context.RuntimeResourceDefinition; +import ca.uhn.fhir.model.api.IFhirVersion; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.rest.server.IResourceProvider; +import ca.uhn.fhir.rest.server.RestfulServer; + +public class FhirDstu1 implements IFhirVersion { + + @Override + public Object createServerConformanceProvider(RestfulServer theServer) { + throw new UnsupportedOperationException(); + } + + @Override + public IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer) { + throw new UnsupportedOperationException(); + } + + @Override + public IResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition) { + throw new UnsupportedOperationException(); + } + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AddressDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AddressDt.java new file mode 100644 index 00000000000..1a6a6046cfe --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AddressDt.java @@ -0,0 +1,521 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.valueset.AddressUseEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR AddressDt Datatype + * (A postal address) + * + *

+ * Definition: + * There is a variety of postal address formats defined around the world. This format defines a superset that is the basis for all addresses around the world + *

+ * + *

+ * Requirements: + * Need to be able to record postal addresses, along with notes about their use + *

+ */ +@DatatypeDef(name="AddressDt") +public class AddressDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public AddressDt() { + // nothing + } + + + @Child(name="use", type=CodeDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="home | work | temp | old - purpose of this address", + formalDefinition="The purpose of this address" + ) + private BoundCodeDt myUse; + + @Child(name="text", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Text representation of the address", + formalDefinition="A full text representation of the address" + ) + private StringDt myText; + + @Child(name="line", type=StringDt.class, order=2, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Street name, number, direction & P.O. Box etc", + formalDefinition="This component contains the house number, apartment number, street name, street direction, P.O. Box number, delivery hints, and similar address information" + ) + private java.util.List myLine; + + @Child(name="city", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Name of city, town etc.", + formalDefinition="The name of the city, town, village or other community or delivery center." + ) + private StringDt myCity; + + @Child(name="state", type=StringDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="Sub-unit of country (abreviations ok)", + formalDefinition="Sub-unit of a country with limited sovereignty in a federally organized country. A code may be used if codes are in common use (i.e. US 2 letter state codes)." + ) + private StringDt myState; + + @Child(name="zip", type=StringDt.class, order=5, min=0, max=1) + @Description( + shortDefinition="Postal code for area", + formalDefinition="A postal code designating a region defined by the postal service." + ) + private StringDt myZip; + + @Child(name="country", type=StringDt.class, order=6, min=0, max=1) + @Description( + shortDefinition="Country (can be ISO 3166 3 letter code)", + formalDefinition="Country - a nation as commonly understood or generally accepted" + ) + private StringDt myCountry; + + @Child(name="period", type=PeriodDt.class, order=7, min=0, max=1) + @Description( + shortDefinition="Time period when address was/is in use", + formalDefinition="Time period when address was/is in use" + ) + private PeriodDt myPeriod; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myUse, myText, myLine, myCity, myState, myZip, myCountry, myPeriod); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myUse, myText, myLine, myCity, myState, myZip, myCountry, myPeriod); + } + + /** + * Gets the value(s) for use (home | work | temp | old - purpose of this address). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The purpose of this address + *

+ */ + public BoundCodeDt getUse() { + if (myUse == null) { + myUse = new BoundCodeDt(AddressUseEnum.VALUESET_BINDER); + } + return myUse; + } + + /** + * Sets the value(s) for use (home | work | temp | old - purpose of this address) + * + *

+ * Definition: + * The purpose of this address + *

+ */ + public AddressDt setUse(BoundCodeDt theValue) { + myUse = theValue; + return this; + } + + /** + * Sets the value(s) for use (home | work | temp | old - purpose of this address) + * + *

+ * Definition: + * The purpose of this address + *

+ */ + public AddressDt setUse(AddressUseEnum theValue) { + getUse().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for text (Text representation of the address). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A full text representation of the address + *

+ */ + public StringDt getText() { + if (myText == null) { + myText = new StringDt(); + } + return myText; + } + + /** + * Sets the value(s) for text (Text representation of the address) + * + *

+ * Definition: + * A full text representation of the address + *

+ */ + public AddressDt setText(StringDt theValue) { + myText = theValue; + return this; + } + + /** + * Sets the value for text (Text representation of the address) + * + *

+ * Definition: + * A full text representation of the address + *

+ */ + public AddressDt setText( String theString) { + myText = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for line (Street name, number, direction & P.O. Box etc). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * This component contains the house number, apartment number, street name, street direction, P.O. Box number, delivery hints, and similar address information + *

+ */ + public java.util.List getLine() { + if (myLine == null) { + myLine = new java.util.ArrayList(); + } + return myLine; + } + + /** + * Sets the value(s) for line (Street name, number, direction & P.O. Box etc) + * + *

+ * Definition: + * This component contains the house number, apartment number, street name, street direction, P.O. Box number, delivery hints, and similar address information + *

+ */ + public AddressDt setLine(java.util.List theValue) { + myLine = theValue; + return this; + } + + /** + * Adds and returns a new value for line (Street name, number, direction & P.O. Box etc) + * + *

+ * Definition: + * This component contains the house number, apartment number, street name, street direction, P.O. Box number, delivery hints, and similar address information + *

+ */ + public StringDt addLine() { + StringDt newType = new StringDt(); + getLine().add(newType); + return newType; + } + + /** + * Gets the first repetition for line (Street name, number, direction & P.O. Box etc), + * creating it if it does not already exist. + * + *

+ * Definition: + * This component contains the house number, apartment number, street name, street direction, P.O. Box number, delivery hints, and similar address information + *

+ */ + public StringDt getLineFirstRep() { + if (getLine().isEmpty()) { + return addLine(); + } + return getLine().get(0); + } + /** + * Adds a new value for line (Street name, number, direction & P.O. Box etc) + * + *

+ * Definition: + * This component contains the house number, apartment number, street name, street direction, P.O. Box number, delivery hints, and similar address information + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public AddressDt addLine( String theString) { + if (myLine == null) { + myLine = new java.util.ArrayList(); + } + myLine.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for city (Name of city, town etc.). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of the city, town, village or other community or delivery center. + *

+ */ + public StringDt getCity() { + if (myCity == null) { + myCity = new StringDt(); + } + return myCity; + } + + /** + * Sets the value(s) for city (Name of city, town etc.) + * + *

+ * Definition: + * The name of the city, town, village or other community or delivery center. + *

+ */ + public AddressDt setCity(StringDt theValue) { + myCity = theValue; + return this; + } + + /** + * Sets the value for city (Name of city, town etc.) + * + *

+ * Definition: + * The name of the city, town, village or other community or delivery center. + *

+ */ + public AddressDt setCity( String theString) { + myCity = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for state (Sub-unit of country (abreviations ok)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Sub-unit of a country with limited sovereignty in a federally organized country. A code may be used if codes are in common use (i.e. US 2 letter state codes). + *

+ */ + public StringDt getState() { + if (myState == null) { + myState = new StringDt(); + } + return myState; + } + + /** + * Sets the value(s) for state (Sub-unit of country (abreviations ok)) + * + *

+ * Definition: + * Sub-unit of a country with limited sovereignty in a federally organized country. A code may be used if codes are in common use (i.e. US 2 letter state codes). + *

+ */ + public AddressDt setState(StringDt theValue) { + myState = theValue; + return this; + } + + /** + * Sets the value for state (Sub-unit of country (abreviations ok)) + * + *

+ * Definition: + * Sub-unit of a country with limited sovereignty in a federally organized country. A code may be used if codes are in common use (i.e. US 2 letter state codes). + *

+ */ + public AddressDt setState( String theString) { + myState = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for zip (Postal code for area). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A postal code designating a region defined by the postal service. + *

+ */ + public StringDt getZip() { + if (myZip == null) { + myZip = new StringDt(); + } + return myZip; + } + + /** + * Sets the value(s) for zip (Postal code for area) + * + *

+ * Definition: + * A postal code designating a region defined by the postal service. + *

+ */ + public AddressDt setZip(StringDt theValue) { + myZip = theValue; + return this; + } + + /** + * Sets the value for zip (Postal code for area) + * + *

+ * Definition: + * A postal code designating a region defined by the postal service. + *

+ */ + public AddressDt setZip( String theString) { + myZip = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for country (Country (can be ISO 3166 3 letter code)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Country - a nation as commonly understood or generally accepted + *

+ */ + public StringDt getCountry() { + if (myCountry == null) { + myCountry = new StringDt(); + } + return myCountry; + } + + /** + * Sets the value(s) for country (Country (can be ISO 3166 3 letter code)) + * + *

+ * Definition: + * Country - a nation as commonly understood or generally accepted + *

+ */ + public AddressDt setCountry(StringDt theValue) { + myCountry = theValue; + return this; + } + + /** + * Sets the value for country (Country (can be ISO 3166 3 letter code)) + * + *

+ * Definition: + * Country - a nation as commonly understood or generally accepted + *

+ */ + public AddressDt setCountry( String theString) { + myCountry = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for period (Time period when address was/is in use). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Time period when address was/is in use + *

+ */ + public PeriodDt getPeriod() { + if (myPeriod == null) { + myPeriod = new PeriodDt(); + } + return myPeriod; + } + + /** + * Sets the value(s) for period (Time period when address was/is in use) + * + *

+ * Definition: + * Time period when address was/is in use + *

+ */ + public AddressDt setPeriod(PeriodDt theValue) { + myPeriod = theValue; + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AgeDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AgeDt.java new file mode 100644 index 00000000000..c1942fa57bf --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AgeDt.java @@ -0,0 +1,30 @@ +package ca.uhn.fhir.model.dstu.composite; + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +@DatatypeDef(name="AgeDt") +public class AgeDt extends QuantityDt { + + // TODO: implement restricions + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AttachmentDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AttachmentDt.java new file mode 100644 index 00000000000..0b5361057f7 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/AttachmentDt.java @@ -0,0 +1,450 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.primitive.Base64BinaryDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; + +/** + * HAPI/FHIR AttachmentDt Datatype + * (Content in a format defined elsewhere) + * + *

+ * Definition: + * For referring to data content defined in other formats. + *

+ * + *

+ * Requirements: + * Many models need to include data defined in other specifications that is complex and opaque to the healthcare model. This includes documents, media recordings, structured data, etc. + *

+ */ +@DatatypeDef(name="AttachmentDt") +public class AttachmentDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public AttachmentDt() { + // nothing + } + + + @Child(name="contentType", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Mime type of the content, with charset etc.", + formalDefinition="Identifies the type of the data in the attachment and allows a method to be chosen to interpret or render the data. Includes mime type parameters such as charset where appropriate" + ) + private CodeDt myContentType; + + @Child(name="language", type=CodeDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Human language of the content (BCP-47)", + formalDefinition="The human language of the content. The value can be any valid value according to BCP 47" + ) + private CodeDt myLanguage; + + @Child(name="data", type=Base64BinaryDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Data inline, base64ed", + formalDefinition="The actual data of the attachment - a sequence of bytes. In XML, represented using base64" + ) + private Base64BinaryDt myData; + + @Child(name="url", type=UriDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Uri where the data can be found", + formalDefinition="An alternative location where the data can be accessed" + ) + private UriDt myUrl; + + @Child(name="size", type=IntegerDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="Number of bytes of content (if url provided)", + formalDefinition="The number of bytes of data that make up this attachment." + ) + private IntegerDt mySize; + + @Child(name="hash", type=Base64BinaryDt.class, order=5, min=0, max=1) + @Description( + shortDefinition="Hash of the data (sha-1, base64ed )", + formalDefinition="The calculated hash of the data using SHA-1. Represented using base64" + ) + private Base64BinaryDt myHash; + + @Child(name="title", type=StringDt.class, order=6, min=0, max=1) + @Description( + shortDefinition="Label to display in place of the data", + formalDefinition="A label or set of text to display in place of the data" + ) + private StringDt myTitle; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myContentType, myLanguage, myData, myUrl, mySize, myHash, myTitle); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myContentType, myLanguage, myData, myUrl, mySize, myHash, myTitle); + } + + /** + * Gets the value(s) for contentType (Mime type of the content, with charset etc.). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the type of the data in the attachment and allows a method to be chosen to interpret or render the data. Includes mime type parameters such as charset where appropriate + *

+ */ + public CodeDt getContentType() { + if (myContentType == null) { + myContentType = new CodeDt(); + } + return myContentType; + } + + /** + * Sets the value(s) for contentType (Mime type of the content, with charset etc.) + * + *

+ * Definition: + * Identifies the type of the data in the attachment and allows a method to be chosen to interpret or render the data. Includes mime type parameters such as charset where appropriate + *

+ */ + public AttachmentDt setContentType(CodeDt theValue) { + myContentType = theValue; + return this; + } + + /** + * Sets the value for contentType (Mime type of the content, with charset etc.) + * + *

+ * Definition: + * Identifies the type of the data in the attachment and allows a method to be chosen to interpret or render the data. Includes mime type parameters such as charset where appropriate + *

+ */ + public AttachmentDt setContentType( String theCode) { + myContentType = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for language (Human language of the content (BCP-47)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The human language of the content. The value can be any valid value according to BCP 47 + *

+ */ + public CodeDt getLanguage() { + if (myLanguage == null) { + myLanguage = new CodeDt(); + } + return myLanguage; + } + + /** + * Sets the value(s) for language (Human language of the content (BCP-47)) + * + *

+ * Definition: + * The human language of the content. The value can be any valid value according to BCP 47 + *

+ */ + public AttachmentDt setLanguage(CodeDt theValue) { + myLanguage = theValue; + return this; + } + + /** + * Sets the value for language (Human language of the content (BCP-47)) + * + *

+ * Definition: + * The human language of the content. The value can be any valid value according to BCP 47 + *

+ */ + public AttachmentDt setLanguage( String theCode) { + myLanguage = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for data (Data inline, base64ed). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The actual data of the attachment - a sequence of bytes. In XML, represented using base64 + *

+ */ + public Base64BinaryDt getData() { + if (myData == null) { + myData = new Base64BinaryDt(); + } + return myData; + } + + /** + * Sets the value(s) for data (Data inline, base64ed) + * + *

+ * Definition: + * The actual data of the attachment - a sequence of bytes. In XML, represented using base64 + *

+ */ + public AttachmentDt setData(Base64BinaryDt theValue) { + myData = theValue; + return this; + } + + /** + * Sets the value for data (Data inline, base64ed) + * + *

+ * Definition: + * The actual data of the attachment - a sequence of bytes. In XML, represented using base64 + *

+ */ + public AttachmentDt setData( byte[] theBytes) { + myData = new Base64BinaryDt(theBytes); + return this; + } + + + /** + * Gets the value(s) for url (Uri where the data can be found). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An alternative location where the data can be accessed + *

+ */ + public UriDt getUrl() { + if (myUrl == null) { + myUrl = new UriDt(); + } + return myUrl; + } + + /** + * Sets the value(s) for url (Uri where the data can be found) + * + *

+ * Definition: + * An alternative location where the data can be accessed + *

+ */ + public AttachmentDt setUrl(UriDt theValue) { + myUrl = theValue; + return this; + } + + /** + * Sets the value for url (Uri where the data can be found) + * + *

+ * Definition: + * An alternative location where the data can be accessed + *

+ */ + public AttachmentDt setUrl( String theUri) { + myUrl = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for size (Number of bytes of content (if url provided)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The number of bytes of data that make up this attachment. + *

+ */ + public IntegerDt getSize() { + if (mySize == null) { + mySize = new IntegerDt(); + } + return mySize; + } + + /** + * Sets the value(s) for size (Number of bytes of content (if url provided)) + * + *

+ * Definition: + * The number of bytes of data that make up this attachment. + *

+ */ + public AttachmentDt setSize(IntegerDt theValue) { + mySize = theValue; + return this; + } + + /** + * Sets the value for size (Number of bytes of content (if url provided)) + * + *

+ * Definition: + * The number of bytes of data that make up this attachment. + *

+ */ + public AttachmentDt setSize( int theInteger) { + mySize = new IntegerDt(theInteger); + return this; + } + + + /** + * Gets the value(s) for hash (Hash of the data (sha-1, base64ed )). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The calculated hash of the data using SHA-1. Represented using base64 + *

+ */ + public Base64BinaryDt getHash() { + if (myHash == null) { + myHash = new Base64BinaryDt(); + } + return myHash; + } + + /** + * Sets the value(s) for hash (Hash of the data (sha-1, base64ed )) + * + *

+ * Definition: + * The calculated hash of the data using SHA-1. Represented using base64 + *

+ */ + public AttachmentDt setHash(Base64BinaryDt theValue) { + myHash = theValue; + return this; + } + + /** + * Sets the value for hash (Hash of the data (sha-1, base64ed )) + * + *

+ * Definition: + * The calculated hash of the data using SHA-1. Represented using base64 + *

+ */ + public AttachmentDt setHash( byte[] theBytes) { + myHash = new Base64BinaryDt(theBytes); + return this; + } + + + /** + * Gets the value(s) for title (Label to display in place of the data). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A label or set of text to display in place of the data + *

+ */ + public StringDt getTitle() { + if (myTitle == null) { + myTitle = new StringDt(); + } + return myTitle; + } + + /** + * Sets the value(s) for title (Label to display in place of the data) + * + *

+ * Definition: + * A label or set of text to display in place of the data + *

+ */ + public AttachmentDt setTitle(StringDt theValue) { + myTitle = theValue; + return this; + } + + /** + * Sets the value for title (Label to display in place of the data) + * + *

+ * Definition: + * A label or set of text to display in place of the data + *

+ */ + public AttachmentDt setTitle( String theString) { + myTitle = new StringDt(theString); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/BoundCodeableConceptDt_.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/BoundCodeableConceptDt_.java new file mode 100644 index 00000000000..04aa63e37f8 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/BoundCodeableConceptDt_.java @@ -0,0 +1,122 @@ +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import static org.apache.commons.lang3.StringUtils.*; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import ca.uhn.fhir.model.api.IValueSetEnumBinder; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +@DatatypeDef(name = "CodeableConcept", isSpecialization = true) +public class BoundCodeableConceptDt_> extends CodeableConceptDt { + + private IValueSetEnumBinder myBinder; + + /** + * Constructor + */ + public BoundCodeableConceptDt_(IValueSetEnumBinder theBinder) { + myBinder = theBinder; + } + + /** + * Constructor + */ + public BoundCodeableConceptDt_(IValueSetEnumBinder theBinder, T theValue) { + myBinder = theBinder; + setValueAsEnum(theValue); + } + + /** + * Constructor + */ + public BoundCodeableConceptDt_(IValueSetEnumBinder theBinder, Collection theValues) { + myBinder = theBinder; + setValueAsEnum(theValues); + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated types, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValue + * The value to add, or null + */ + public void setValueAsEnum(Collection theValues) { + getCoding().clear(); + if (theValues != null) { + for (T next : theValues) { + getCoding().add(new CodingDt(myBinder.toSystemString(next), myBinder.toCodeString(next))); + } + } + } + + /** + * Sets the {@link #getCoding()} to contain a coding with the code and + * system defined by the given enumerated type, AND clearing any existing + * codings first. If theValue is null, existing codings are cleared and no + * codings are added. + * + * @param theValue + * The value to add, or null + */ + public void setValueAsEnum(T theValue) { + getCoding().clear(); + if (theValue == null) { + return; + } + getCoding().add(new CodingDt(myBinder.toSystemString(theValue), myBinder.toCodeString(theValue))); + } + + /** + * Loops through the {@link #getCoding() codings} in this codeable concept + * and returns the first bound enumerated type that matches. Use + * caution using this method, see the return description for more + * information. + * + * @return Returns the bound enumerated type, or null if none + * are found. Note that a null return value doesn't neccesarily + * imply that this Codeable Concept has no codes, only that it has + * no codes that match the enum. + */ + public Set getValueAsEnum() { + Set retVal = new HashSet(); + for (CodingDt next : getCoding()) { + if (next == null) { + continue; + } + T nextT = myBinder.fromCodeString(defaultString(next.getCodeElement().getValue()), defaultString(next.getSystemElement().getValueAsString())); + if (nextT != null) { + retVal.add(nextT); + } else { + // TODO: throw special exception type? + } + } + return retVal; + } + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/CodeableConceptDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/CodeableConceptDt.java new file mode 100644 index 00000000000..9f358b4baca --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/CodeableConceptDt.java @@ -0,0 +1,214 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR CodeableConceptDt Datatype + * (Concept - reference to a terminology or just text) + * + *

+ * Definition: + * A concept that may be defined by a formal reference to a terminology or ontology or may be provided by text + *

+ * + *

+ * Requirements: + * This is a common pattern in healthcare - a concept that may be defined by one or more codes from formal definitions including LOINC and SNOMED CT, and/or defined by the provision of text that captures a human sense of the concept + *

+ */ +@DatatypeDef(name="CodeableConceptDt") +public class CodeableConceptDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public CodeableConceptDt() { + // nothing + } + + /** + * Constructor which creates a CodeableConceptDt with one coding repetition, containing + * the given system and code + */ + public CodeableConceptDt(String theSystem, String theCode) { + addCoding().setSystem(theSystem).setCode(theCode); + } + + @Child(name="coding", type=CodingDt.class, order=0, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Code defined by a terminology system", + formalDefinition="A reference to a code defined by a terminology system" + ) + private java.util.List myCoding; + + @Child(name="text", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Plain text representation of the concept", + formalDefinition="A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user" + ) + private StringDt myText; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCoding, myText); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCoding, myText); + } + + /** + * Gets the value(s) for coding (Code defined by a terminology system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public java.util.List getCoding() { + if (myCoding == null) { + myCoding = new java.util.ArrayList(); + } + return myCoding; + } + + /** + * Sets the value(s) for coding (Code defined by a terminology system) + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public CodeableConceptDt setCoding(java.util.List theValue) { + myCoding = theValue; + return this; + } + + /** + * Adds and returns a new value for coding (Code defined by a terminology system) + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public CodingDt addCoding() { + CodingDt newType = new CodingDt(); + getCoding().add(newType); + return newType; + } + + /** + * Gets the first repetition for coding (Code defined by a terminology system), + * creating it if it does not already exist. + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ */ + public CodingDt getCodingFirstRep() { + if (getCoding().isEmpty()) { + return addCoding(); + } + return getCoding().get(0); + } + + /** + * Gets the value(s) for text (Plain text representation of the concept). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user + *

+ */ + public StringDt getText() { + if (myText == null) { + myText = new StringDt(); + } + return myText; + } + + /** + * Sets the value(s) for text (Plain text representation of the concept) + * + *

+ * Definition: + * A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user + *

+ */ + public CodeableConceptDt setText(StringDt theValue) { + myText = theValue; + return this; + } + + /** + * Sets the value for text (Plain text representation of the concept) + * + *

+ * Definition: + * A human language representation of the concept as seen/selected/uttered by the user who entered the data and/or which represents the intended meaning of the user + *

+ */ + public CodeableConceptDt setText( String theString) { + myText = new StringDt(theString); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/CodingDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/CodingDt.java new file mode 100644 index 00000000000..5e58142cb38 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/CodingDt.java @@ -0,0 +1,393 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.base.composite.BaseCodingDt; +import ca.uhn.fhir.model.primitive.BooleanDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; + +/** + * HAPI/FHIR CodingDt Datatype + * (A reference to a code defined by a terminology system) + * + *

+ * Definition: + * A reference to a code defined by a terminology system + *

+ * + *

+ * Requirements: + * References to codes are very common in healthcare models + *

+ */ +@DatatypeDef(name="CodingDt") +public class CodingDt + extends BaseCodingDt implements ICompositeDatatype +{ + + /** + * Constructor + */ + public CodingDt() { + // nothing + } + + /** + * Creates a new Coding with the given system and code + */ + public CodingDt(String theSystem, String theCode) { + setSystem(theSystem); + setCode(theCode); + } + + @Child(name="system", type=UriDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Identity of the terminology system", + formalDefinition="The identification of the code system that defines the meaning of the symbol in the code." + ) + private UriDt mySystem; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Version of the system - if relevant", + formalDefinition="The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged" + ) + private StringDt myVersion; + + @Child(name="code", type=CodeDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Symbol in syntax defined by the system", + formalDefinition="A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination)" + ) + private CodeDt myCode; + + @Child(name="display", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Representation defined by the system", + formalDefinition="A representation of the meaning of the code in the system, following the rules of the system." + ) + private StringDt myDisplay; + + @Child(name="primary", type=BooleanDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="If this code was chosen directly by the user", + formalDefinition="Indicates that this code was chosen by a user directly - i.e. off a pick list of available items (codes or displays)" + ) + private BooleanDt myPrimary; + + @Child(name="valueSet", order=5, min=0, max=1, type={ + ca.uhn.fhir.model.dstu.resource.ValueSet.class }) + @Description( + shortDefinition="Set this coding was chosen from", + formalDefinition="The set of possible coded values this coding was chosen from or constrained by" + ) + private ResourceReferenceDt myValueSet; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( mySystem, myVersion, myCode, myDisplay, myPrimary, myValueSet); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, mySystem, myVersion, myCode, myDisplay, myPrimary, myValueSet); + } + + /** + * Gets the value(s) for system (Identity of the terminology system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identification of the code system that defines the meaning of the symbol in the code. + *

+ */ + public UriDt getSystemElement() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + /** + * Sets the value(s) for system (Identity of the terminology system) + * + *

+ * Definition: + * The identification of the code system that defines the meaning of the symbol in the code. + *

+ */ + public CodingDt setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + /** + * Sets the value for system (Identity of the terminology system) + * + *

+ * Definition: + * The identification of the code system that defines the meaning of the symbol in the code. + *

+ */ + public CodingDt setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for version (Version of the system - if relevant). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged + *

+ */ + public StringDt getVersion() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + /** + * Sets the value(s) for version (Version of the system - if relevant) + * + *

+ * Definition: + * The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged + *

+ */ + public CodingDt setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + /** + * Sets the value for version (Version of the system - if relevant) + * + *

+ * Definition: + * The version of the code system which was used when choosing this code. Note that a well-maintained code system does not need the version reported, because the meaning of codes is consistent across versions. However this cannot consistently be assured. and When the meaning is not guaranteed to be consistent, the version SHOULD be exchanged + *

+ */ + public CodingDt setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for code (Symbol in syntax defined by the system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination) + *

+ */ + public CodeDt getCodeElement() { + if (myCode == null) { + myCode = new CodeDt(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Symbol in syntax defined by the system) + * + *

+ * Definition: + * A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination) + *

+ */ + public CodingDt setCode(CodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value for code (Symbol in syntax defined by the system) + * + *

+ * Definition: + * A symbol in syntax defined by the system. The symbol may be a predefined code or an expression in a syntax defined by the coding system (e.g. post-coordination) + *

+ */ + public CodingDt setCode( String theCode) { + myCode = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for display (Representation defined by the system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A representation of the meaning of the code in the system, following the rules of the system. + *

+ */ + public StringDt getDisplay() { + if (myDisplay == null) { + myDisplay = new StringDt(); + } + return myDisplay; + } + + /** + * Sets the value(s) for display (Representation defined by the system) + * + *

+ * Definition: + * A representation of the meaning of the code in the system, following the rules of the system. + *

+ */ + public CodingDt setDisplay(StringDt theValue) { + myDisplay = theValue; + return this; + } + + /** + * Sets the value for display (Representation defined by the system) + * + *

+ * Definition: + * A representation of the meaning of the code in the system, following the rules of the system. + *

+ */ + public CodingDt setDisplay( String theString) { + myDisplay = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for primary (If this code was chosen directly by the user). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates that this code was chosen by a user directly - i.e. off a pick list of available items (codes or displays) + *

+ */ + public BooleanDt getPrimary() { + if (myPrimary == null) { + myPrimary = new BooleanDt(); + } + return myPrimary; + } + + /** + * Sets the value(s) for primary (If this code was chosen directly by the user) + * + *

+ * Definition: + * Indicates that this code was chosen by a user directly - i.e. off a pick list of available items (codes or displays) + *

+ */ + public CodingDt setPrimary(BooleanDt theValue) { + myPrimary = theValue; + return this; + } + + /** + * Sets the value for primary (If this code was chosen directly by the user) + * + *

+ * Definition: + * Indicates that this code was chosen by a user directly - i.e. off a pick list of available items (codes or displays) + *

+ */ + public CodingDt setPrimary( boolean theBoolean) { + myPrimary = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for valueSet (Set this coding was chosen from). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The set of possible coded values this coding was chosen from or constrained by + *

+ */ + public ResourceReferenceDt getValueSet() { + if (myValueSet == null) { + myValueSet = new ResourceReferenceDt(); + } + return myValueSet; + } + + /** + * Sets the value(s) for valueSet (Set this coding was chosen from) + * + *

+ * Definition: + * The set of possible coded values this coding was chosen from or constrained by + *

+ */ + public CodingDt setValueSet(ResourceReferenceDt theValue) { + myValueSet = theValue; + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ContactDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ContactDt.java new file mode 100644 index 00000000000..6863159f5bc --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ContactDt.java @@ -0,0 +1,301 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.SimpleSetter; +import ca.uhn.fhir.model.dstu.valueset.ContactSystemEnum; +import ca.uhn.fhir.model.dstu.valueset.ContactUseEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR ContactDt Datatype + * (Technology mediated contact details (phone, fax, email, etc)) + * + *

+ * Definition: + * All kinds of technology mediated contact details for a person or organization, including telephone, email, etc. + *

+ * + *

+ * Requirements: + * Need to track phone, fax, mobile, sms numbers, email addresses, twitter tags, etc. + *

+ */ +@DatatypeDef(name="ContactDt") +public class ContactDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public ContactDt() { + // nothing + } + + /** + * Constructor + */ + @SimpleSetter + public ContactDt(@SimpleSetter.Parameter(name="theValue") String theValue) { + setValue(theValue); + } + + /** + * Constructor + */ + @SimpleSetter + public ContactDt(@SimpleSetter.Parameter(name="theContactUse") ContactUseEnum theContactUse, @SimpleSetter.Parameter(name="theValue") String theValue) { + setUse(theContactUse); + setValue(theValue); + } + + @Child(name="system", type=CodeDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="phone | fax | email | url", + formalDefinition="Telecommunications form for contact - what communications system is required to make use of the contact" + ) + private BoundCodeDt mySystem; + + @Child(name="value", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="The actual contact details", + formalDefinition="The actual contact details, in a form that is meaningful to the designated communication system (i.e. phone number or email address)." + ) + private StringDt myValue; + + @Child(name="use", type=CodeDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="home | work | temp | old | mobile - purpose of this address", + formalDefinition="Identifies the purpose for the address" + ) + private BoundCodeDt myUse; + + @Child(name="period", type=PeriodDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Time period when the contact was/is in use", + formalDefinition="Time period when the contact was/is in use" + ) + private PeriodDt myPeriod; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( mySystem, myValue, myUse, myPeriod); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, mySystem, myValue, myUse, myPeriod); + } + + /** + * Gets the value(s) for system (phone | fax | email | url). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Telecommunications form for contact - what communications system is required to make use of the contact + *

+ */ + public BoundCodeDt getSystem() { + if (mySystem == null) { + mySystem = new BoundCodeDt(ContactSystemEnum.VALUESET_BINDER); + } + return mySystem; + } + + /** + * Sets the value(s) for system (phone | fax | email | url) + * + *

+ * Definition: + * Telecommunications form for contact - what communications system is required to make use of the contact + *

+ */ + public ContactDt setSystem(BoundCodeDt theValue) { + mySystem = theValue; + return this; + } + + /** + * Sets the value(s) for system (phone | fax | email | url) + * + *

+ * Definition: + * Telecommunications form for contact - what communications system is required to make use of the contact + *

+ */ + public ContactDt setSystem(ContactSystemEnum theValue) { + getSystem().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for value (The actual contact details). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The actual contact details, in a form that is meaningful to the designated communication system (i.e. phone number or email address). + *

+ */ + public StringDt getValue() { + if (myValue == null) { + myValue = new StringDt(); + } + return myValue; + } + + /** + * Sets the value(s) for value (The actual contact details) + * + *

+ * Definition: + * The actual contact details, in a form that is meaningful to the designated communication system (i.e. phone number or email address). + *

+ */ + public ContactDt setValue(StringDt theValue) { + myValue = theValue; + return this; + } + + /** + * Sets the value for value (The actual contact details) + * + *

+ * Definition: + * The actual contact details, in a form that is meaningful to the designated communication system (i.e. phone number or email address). + *

+ */ + public ContactDt setValue( String theString) { + myValue = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for use (home | work | temp | old | mobile - purpose of this address). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the purpose for the address + *

+ */ + public BoundCodeDt getUse() { + if (myUse == null) { + myUse = new BoundCodeDt(ContactUseEnum.VALUESET_BINDER); + } + return myUse; + } + + /** + * Sets the value(s) for use (home | work | temp | old | mobile - purpose of this address) + * + *

+ * Definition: + * Identifies the purpose for the address + *

+ */ + public ContactDt setUse(BoundCodeDt theValue) { + myUse = theValue; + return this; + } + + /** + * Sets the value(s) for use (home | work | temp | old | mobile - purpose of this address) + * + *

+ * Definition: + * Identifies the purpose for the address + *

+ */ + public ContactDt setUse(ContactUseEnum theValue) { + getUse().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for period (Time period when the contact was/is in use). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Time period when the contact was/is in use + *

+ */ + public PeriodDt getPeriod() { + if (myPeriod == null) { + myPeriod = new PeriodDt(); + } + return myPeriod; + } + + /** + * Sets the value(s) for period (Time period when the contact was/is in use) + * + *

+ * Definition: + * Time period when the contact was/is in use + *

+ */ + public ContactDt setPeriod(PeriodDt theValue) { + myPeriod = theValue; + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ContainedDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ContainedDt.java new file mode 100644 index 00000000000..bc20f2b1a12 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ContainedDt.java @@ -0,0 +1,53 @@ +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.ArrayList; +import java.util.List; + +import ca.uhn.fhir.model.api.IDatatype; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +@DatatypeDef(name = "duration") +public class ContainedDt implements IDatatype { + + @Child(name = "resource", type = IResource.class, order = 0, min = 0, max = Child.MAX_UNLIMITED) + private List myContainedResources; + + public List getContainedResources() { + if (myContainedResources == null) { + myContainedResources = new ArrayList(); + } + return myContainedResources; + } + + public void setContainedResources(List theContainedResources) { + myContainedResources = theContainedResources; + } + + @Override + public boolean isEmpty() { + return myContainedResources == null || myContainedResources.size() == 0; + } + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/DurationDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/DurationDt.java new file mode 100644 index 00000000000..5fa244c674d --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/DurationDt.java @@ -0,0 +1,33 @@ +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +@DatatypeDef(name = "Duration") +public class DurationDt extends QuantityDt { + + // TODO: implement restricions + + // There SHALL be a code if there is a value and it SHALL be an expression of length. If system is present, it SHALL be UCUM. + // (f:code or not(f:value)) and (not(exists(f:system)) or f:system/@value='http://unitsofmeasure.org') + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/HumanNameDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/HumanNameDt.java new file mode 100644 index 00000000000..c1785cbd862 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/HumanNameDt.java @@ -0,0 +1,572 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.base.composite.BaseHumanNameDt; +import ca.uhn.fhir.model.dstu.valueset.NameUseEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR HumanNameDt Datatype + * (Name of a human - parts and usage) + * + *

+ * Definition: + * A human's name with the ability to identify parts and usage + *

+ * + *

+ * Requirements: + * Need to be able to record names, along with notes about their use + *

+ */ +@DatatypeDef(name="HumanNameDt") +public class HumanNameDt + extends BaseHumanNameDt implements ICompositeDatatype +{ + + /** + * Constructor + */ + public HumanNameDt() { + // nothing + } + + + @Child(name="use", type=CodeDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="usual | official | temp | nickname | anonymous | old | maiden", + formalDefinition="Identifies the purpose for this name" + ) + private BoundCodeDt myUse; + + @Child(name="text", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Text representation of the full name", + formalDefinition="A full text representation of the name" + ) + private StringDt myText; + + @Child(name="family", type=StringDt.class, order=2, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Family name (often called 'Surname')", + formalDefinition="The part of a name that links to the genealogy. In some cultures (e.g. Eritrea) the family name of a son is the first name of his father." + ) + private java.util.List myFamily; + + @Child(name="given", type=StringDt.class, order=3, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Given names (not always 'first'). Includes middle names", + formalDefinition="Given name" + ) + private java.util.List myGiven; + + @Child(name="prefix", type=StringDt.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Parts that come before the name", + formalDefinition="Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the start of the name" + ) + private java.util.List myPrefix; + + @Child(name="suffix", type=StringDt.class, order=5, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Parts that come after the name", + formalDefinition="Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the end of the name" + ) + private java.util.List mySuffix; + + @Child(name="period", type=PeriodDt.class, order=6, min=0, max=1) + @Description( + shortDefinition="Time period when name was/is in use", + formalDefinition="Indicates the period of time when this name was valid for the named person." + ) + private PeriodDt myPeriod; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myUse, myText, myFamily, myGiven, myPrefix, mySuffix, myPeriod); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myUse, myText, myFamily, myGiven, myPrefix, mySuffix, myPeriod); + } + + /** + * Gets the value(s) for use (usual | official | temp | nickname | anonymous | old | maiden). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the purpose for this name + *

+ */ + public BoundCodeDt getUse() { + if (myUse == null) { + myUse = new BoundCodeDt(NameUseEnum.VALUESET_BINDER); + } + return myUse; + } + + /** + * Sets the value(s) for use (usual | official | temp | nickname | anonymous | old | maiden) + * + *

+ * Definition: + * Identifies the purpose for this name + *

+ */ + public HumanNameDt setUse(BoundCodeDt theValue) { + myUse = theValue; + return this; + } + + /** + * Sets the value(s) for use (usual | official | temp | nickname | anonymous | old | maiden) + * + *

+ * Definition: + * Identifies the purpose for this name + *

+ */ + public HumanNameDt setUse(NameUseEnum theValue) { + getUse().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for text (Text representation of the full name). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A full text representation of the name + *

+ */ + public StringDt getText() { + if (myText == null) { + myText = new StringDt(); + } + return myText; + } + + /** + * Sets the value(s) for text (Text representation of the full name) + * + *

+ * Definition: + * A full text representation of the name + *

+ */ + public HumanNameDt setText(StringDt theValue) { + myText = theValue; + return this; + } + + /** + * Sets the value for text (Text representation of the full name) + * + *

+ * Definition: + * A full text representation of the name + *

+ */ + public HumanNameDt setText( String theString) { + myText = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for family (Family name (often called 'Surname')). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The part of a name that links to the genealogy. In some cultures (e.g. Eritrea) the family name of a son is the first name of his father. + *

+ */ + public java.util.List getFamily() { + if (myFamily == null) { + myFamily = new java.util.ArrayList(); + } + return myFamily; + } + + /** + * Sets the value(s) for family (Family name (often called 'Surname')) + * + *

+ * Definition: + * The part of a name that links to the genealogy. In some cultures (e.g. Eritrea) the family name of a son is the first name of his father. + *

+ */ + public HumanNameDt setFamily(java.util.List theValue) { + myFamily = theValue; + return this; + } + + /** + * Adds and returns a new value for family (Family name (often called 'Surname')) + * + *

+ * Definition: + * The part of a name that links to the genealogy. In some cultures (e.g. Eritrea) the family name of a son is the first name of his father. + *

+ */ + public StringDt addFamily() { + StringDt newType = new StringDt(); + getFamily().add(newType); + return newType; + } + + /** + * Gets the first repetition for family (Family name (often called 'Surname')), + * creating it if it does not already exist. + * + *

+ * Definition: + * The part of a name that links to the genealogy. In some cultures (e.g. Eritrea) the family name of a son is the first name of his father. + *

+ */ + public StringDt getFamilyFirstRep() { + if (getFamily().isEmpty()) { + return addFamily(); + } + return getFamily().get(0); + } + /** + * Adds a new value for family (Family name (often called 'Surname')) + * + *

+ * Definition: + * The part of a name that links to the genealogy. In some cultures (e.g. Eritrea) the family name of a son is the first name of his father. + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public HumanNameDt addFamily( String theString) { + if (myFamily == null) { + myFamily = new java.util.ArrayList(); + } + myFamily.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for given (Given names (not always 'first'). Includes middle names). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Given name + *

+ */ + public java.util.List getGiven() { + if (myGiven == null) { + myGiven = new java.util.ArrayList(); + } + return myGiven; + } + + /** + * Sets the value(s) for given (Given names (not always 'first'). Includes middle names) + * + *

+ * Definition: + * Given name + *

+ */ + public HumanNameDt setGiven(java.util.List theValue) { + myGiven = theValue; + return this; + } + + /** + * Adds and returns a new value for given (Given names (not always 'first'). Includes middle names) + * + *

+ * Definition: + * Given name + *

+ */ + public StringDt addGiven() { + StringDt newType = new StringDt(); + getGiven().add(newType); + return newType; + } + + /** + * Gets the first repetition for given (Given names (not always 'first'). Includes middle names), + * creating it if it does not already exist. + * + *

+ * Definition: + * Given name + *

+ */ + public StringDt getGivenFirstRep() { + if (getGiven().isEmpty()) { + return addGiven(); + } + return getGiven().get(0); + } + /** + * Adds a new value for given (Given names (not always 'first'). Includes middle names) + * + *

+ * Definition: + * Given name + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public HumanNameDt addGiven( String theString) { + if (myGiven == null) { + myGiven = new java.util.ArrayList(); + } + myGiven.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for prefix (Parts that come before the name). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the start of the name + *

+ */ + public java.util.List getPrefix() { + if (myPrefix == null) { + myPrefix = new java.util.ArrayList(); + } + return myPrefix; + } + + /** + * Sets the value(s) for prefix (Parts that come before the name) + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the start of the name + *

+ */ + public HumanNameDt setPrefix(java.util.List theValue) { + myPrefix = theValue; + return this; + } + + /** + * Adds and returns a new value for prefix (Parts that come before the name) + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the start of the name + *

+ */ + public StringDt addPrefix() { + StringDt newType = new StringDt(); + getPrefix().add(newType); + return newType; + } + + /** + * Gets the first repetition for prefix (Parts that come before the name), + * creating it if it does not already exist. + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the start of the name + *

+ */ + public StringDt getPrefixFirstRep() { + if (getPrefix().isEmpty()) { + return addPrefix(); + } + return getPrefix().get(0); + } + /** + * Adds a new value for prefix (Parts that come before the name) + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the start of the name + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public HumanNameDt addPrefix( String theString) { + if (myPrefix == null) { + myPrefix = new java.util.ArrayList(); + } + myPrefix.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for suffix (Parts that come after the name). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the end of the name + *

+ */ + public java.util.List getSuffix() { + if (mySuffix == null) { + mySuffix = new java.util.ArrayList(); + } + return mySuffix; + } + + /** + * Sets the value(s) for suffix (Parts that come after the name) + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the end of the name + *

+ */ + public HumanNameDt setSuffix(java.util.List theValue) { + mySuffix = theValue; + return this; + } + + /** + * Adds and returns a new value for suffix (Parts that come after the name) + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the end of the name + *

+ */ + public StringDt addSuffix() { + StringDt newType = new StringDt(); + getSuffix().add(newType); + return newType; + } + + /** + * Gets the first repetition for suffix (Parts that come after the name), + * creating it if it does not already exist. + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the end of the name + *

+ */ + public StringDt getSuffixFirstRep() { + if (getSuffix().isEmpty()) { + return addSuffix(); + } + return getSuffix().get(0); + } + /** + * Adds a new value for suffix (Parts that come after the name) + * + *

+ * Definition: + * Part of the name that is acquired as a title due to academic, legal, employment or nobility status, etc. and that appears at the end of the name + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public HumanNameDt addSuffix( String theString) { + if (mySuffix == null) { + mySuffix = new java.util.ArrayList(); + } + mySuffix.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for period (Time period when name was/is in use). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates the period of time when this name was valid for the named person. + *

+ */ + public PeriodDt getPeriod() { + if (myPeriod == null) { + myPeriod = new PeriodDt(); + } + return myPeriod; + } + + /** + * Sets the value(s) for period (Time period when name was/is in use) + * + *

+ * Definition: + * Indicates the period of time when this name was valid for the named person. + *

+ */ + public HumanNameDt setPeriod(PeriodDt theValue) { + myPeriod = theValue; + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/IdentifierDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/IdentifierDt.java new file mode 100644 index 00000000000..120a4758293 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/IdentifierDt.java @@ -0,0 +1,399 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.SimpleSetter; +import ca.uhn.fhir.model.base.composite.BaseIdentifierDt; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; + +/** + * HAPI/FHIR IdentifierDt Datatype + * (An identifier intended for computation) + * + *

+ * Definition: + * A technical identifier - identifies some entity uniquely and unambiguously + *

+ * + *

+ * Requirements: + * Need to be able to identify things with confidence and be sure that the identification is not subject to misinterpretation + *

+ */ +@DatatypeDef(name="IdentifierDt") +public class IdentifierDt + extends BaseIdentifierDt implements ICompositeDatatype +{ + + /** + * Constructor + */ + public IdentifierDt() { + // nothing + } + + /** + * Creates a new identifier with the given system and value + */ + @SimpleSetter + public IdentifierDt(@SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theValue") String theValue) { + setSystem(theSystem); + setValue(theValue); + } + + /** + * Creates a new identifier with the given system and value + */ + @SimpleSetter + public IdentifierDt(@SimpleSetter.Parameter(name="theUse") IdentifierUseEnum theUse, @SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theValue") String theValue, @SimpleSetter.Parameter(name="theLabel") String theLabel) { + setUse(theUse); + setSystem(theSystem); + setValue(theValue); + setLabel(theLabel); + } + + @Override + public String toString() { + return "IdentifierDt[" + getValueAsQueryToken() + "]"; + } + + @Child(name="use", type=CodeDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="usual | official | temp | secondary (If known)", + formalDefinition="The purpose of this identifier" + ) + private BoundCodeDt myUse; + + @Child(name="label", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Description of identifier", + formalDefinition="A text string for the identifier that can be displayed to a human so they can recognize the identifier" + ) + private StringDt myLabel; + + @Child(name="system", type=UriDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="The namespace for the identifier", + formalDefinition="Establishes the namespace in which set of possible id values is unique." + ) + private UriDt mySystem; + + @Child(name="value", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="The value that is unique", + formalDefinition="The portion of the identifier typically displayed to the user and which is unique within the context of the system." + ) + private StringDt myValue; + + @Child(name="period", type=PeriodDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="Time period when id is/was valid for use", + formalDefinition="Time period during which identifier is/was valid for use" + ) + private PeriodDt myPeriod; + + @Child(name="assigner", order=5, min=0, max=1, type={ + ca.uhn.fhir.model.dstu.resource.Conformance.class }) + @Description( + shortDefinition="Organization that issued id (may be just text)", + formalDefinition="Organization that issued/manages the identifier" + ) + private ResourceReferenceDt myAssigner; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myUse, myLabel, mySystem, myValue, myPeriod, myAssigner); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myUse, myLabel, mySystem, myValue, myPeriod, myAssigner); + } + + /** + * Gets the value(s) for use (usual | official | temp | secondary (If known)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The purpose of this identifier + *

+ */ + public BoundCodeDt getUse() { + if (myUse == null) { + myUse = new BoundCodeDt(IdentifierUseEnum.VALUESET_BINDER); + } + return myUse; + } + + /** + * Sets the value(s) for use (usual | official | temp | secondary (If known)) + * + *

+ * Definition: + * The purpose of this identifier + *

+ */ + public IdentifierDt setUse(BoundCodeDt theValue) { + myUse = theValue; + return this; + } + + /** + * Sets the value(s) for use (usual | official | temp | secondary (If known)) + * + *

+ * Definition: + * The purpose of this identifier + *

+ */ + public IdentifierDt setUse(IdentifierUseEnum theValue) { + getUse().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for label (Description of identifier). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A text string for the identifier that can be displayed to a human so they can recognize the identifier + *

+ */ + public StringDt getLabel() { + if (myLabel == null) { + myLabel = new StringDt(); + } + return myLabel; + } + + /** + * Sets the value(s) for label (Description of identifier) + * + *

+ * Definition: + * A text string for the identifier that can be displayed to a human so they can recognize the identifier + *

+ */ + public IdentifierDt setLabel(StringDt theValue) { + myLabel = theValue; + return this; + } + + /** + * Sets the value for label (Description of identifier) + * + *

+ * Definition: + * A text string for the identifier that can be displayed to a human so they can recognize the identifier + *

+ */ + public IdentifierDt setLabel( String theString) { + myLabel = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for system (The namespace for the identifier). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Establishes the namespace in which set of possible id values is unique. + *

+ */ + public UriDt getSystemElement() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + /** + * Sets the value(s) for system (The namespace for the identifier) + * + *

+ * Definition: + * Establishes the namespace in which set of possible id values is unique. + *

+ */ + public IdentifierDt setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + /** + * Sets the value for system (The namespace for the identifier) + * + *

+ * Definition: + * Establishes the namespace in which set of possible id values is unique. + *

+ */ + public IdentifierDt setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for value (The value that is unique). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The portion of the identifier typically displayed to the user and which is unique within the context of the system. + *

+ */ + public StringDt getValueElement() { + if (myValue == null) { + myValue = new StringDt(); + } + return myValue; + } + + /** + * Sets the value(s) for value (The value that is unique) + * + *

+ * Definition: + * The portion of the identifier typically displayed to the user and which is unique within the context of the system. + *

+ */ + public IdentifierDt setValue(StringDt theValue) { + myValue = theValue; + return this; + } + + /** + * Sets the value for value (The value that is unique) + * + *

+ * Definition: + * The portion of the identifier typically displayed to the user and which is unique within the context of the system. + *

+ */ + public IdentifierDt setValue( String theString) { + myValue = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for period (Time period when id is/was valid for use). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Time period during which identifier is/was valid for use + *

+ */ + public PeriodDt getPeriod() { + if (myPeriod == null) { + myPeriod = new PeriodDt(); + } + return myPeriod; + } + + /** + * Sets the value(s) for period (Time period when id is/was valid for use) + * + *

+ * Definition: + * Time period during which identifier is/was valid for use + *

+ */ + public IdentifierDt setPeriod(PeriodDt theValue) { + myPeriod = theValue; + return this; + } + + + /** + * Gets the value(s) for assigner (Organization that issued id (may be just text)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Organization that issued/manages the identifier + *

+ */ + public ResourceReferenceDt getAssigner() { + if (myAssigner == null) { + myAssigner = new ResourceReferenceDt(); + } + return myAssigner; + } + + /** + * Sets the value(s) for assigner (Organization that issued id (may be just text)) + * + *

+ * Definition: + * Organization that issued/manages the identifier + *

+ */ + public IdentifierDt setAssigner(ResourceReferenceDt theValue) { + myAssigner = theValue; + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/NarrativeDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/NarrativeDt.java new file mode 100644 index 00000000000..d442915f951 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/NarrativeDt.java @@ -0,0 +1,176 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.XhtmlDt; + +/** + * HAPI/FHIR Narrative Datatype + * (A human-readable formatted text, including images) + * + *

+ * Definition: + * A human-readable formatted text, including images + *

+ * + *

+ * Requirements: + * + *

+ */ +@DatatypeDef(name="Narrative") +public class NarrativeDt extends BaseIdentifiableElement implements ICompositeDatatype { + + @Child(name="status", type=CodeDt.class, order=0, min=1, max=1) + private BoundCodeDt myStatus; + + @Child(name="div", type=XhtmlDt.class, order=1, min=1, max=1) + private XhtmlDt myDiv; + + public NarrativeDt() { + // nothing + } + + public NarrativeDt(XhtmlDt theDiv, NarrativeStatusEnum theStatus) { + setDiv(theDiv); + setStatus(theStatus); + } + + @Override + public boolean isEmpty() { + return ca.uhn.fhir.util.ElementUtil.isEmpty( myStatus, myDiv ); + } + + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements( theType, myStatus, myDiv ); + } + + /** + * Gets the value(s) for status (generated | extensions | additional). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data + *

+ */ + public BoundCodeDt getStatus() { + if (myStatus == null) { + myStatus = new BoundCodeDt(NarrativeStatusEnum.VALUESET_BINDER); + } + return myStatus; + } + + /** + * Sets the value(s) for status (generated | extensions | additional) + * + *

+ * Definition: + * The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data + *

+ */ + public void setStatus(BoundCodeDt theValue) { + myStatus = theValue; + } + + /** + * Sets the value(s) for status (generated | extensions | additional) + * + *

+ * Definition: + * The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data + *

+ */ + public void setStatus(NarrativeStatusEnum theValue) { + getStatus().setValueAsEnum(theValue); + } + + + /** + * Gets the value(s) for div (Limited xhtml content). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The actual narrative content, a stripped down version of XHTML + *

+ */ + public XhtmlDt getDiv() { + if (myDiv == null) { + myDiv = new XhtmlDt(); + } + return myDiv; + } + + /** + * Sets the value(s) for div (Limited xhtml content) + * + *

+ * Definition: + * The actual narrative content, a stripped down version of XHTML + *

+ */ + public void setDiv(XhtmlDt theValue) { + myDiv = theValue; + } + + /** + * Sets the value using a textual DIV (or simple text block which will be + * converted to XHTML) + */ + public void setDiv(String theTextDiv) { + myDiv = new XhtmlDt(theTextDiv); + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/PeriodDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/PeriodDt.java new file mode 100644 index 00000000000..e6bcd4ff20a --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/PeriodDt.java @@ -0,0 +1,219 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.Date; +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.primitive.DateTimeDt; + +/** + * HAPI/FHIR PeriodDt Datatype + * (Time range defined by start and end date/time) + * + *

+ * Definition: + * A time period defined by a start and end date and optionally time. + *

+ * + *

+ * Requirements: + * + *

+ */ +@DatatypeDef(name="PeriodDt") +public class PeriodDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public PeriodDt() { + // nothing + } + + + @Child(name="start", type=DateTimeDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Starting time with inclusive boundary", + formalDefinition="The start of the period. The boundary is inclusive." + ) + private DateTimeDt myStart; + + @Child(name="end", type=DateTimeDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="End time with inclusive boundary, if not ongoing", + formalDefinition="The end of the period. If the end of the period is missing, it means that the period is ongoing" + ) + private DateTimeDt myEnd; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myStart, myEnd); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myStart, myEnd); + } + + /** + * Gets the value(s) for start (Starting time with inclusive boundary). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The start of the period. The boundary is inclusive. + *

+ */ + public DateTimeDt getStart() { + if (myStart == null) { + myStart = new DateTimeDt(); + } + return myStart; + } + + /** + * Sets the value(s) for start (Starting time with inclusive boundary) + * + *

+ * Definition: + * The start of the period. The boundary is inclusive. + *

+ */ + public PeriodDt setStart(DateTimeDt theValue) { + myStart = theValue; + return this; + } + + /** + * Sets the value for start (Starting time with inclusive boundary) + * + *

+ * Definition: + * The start of the period. The boundary is inclusive. + *

+ */ + public PeriodDt setStartWithSecondsPrecision( Date theDate) { + myStart = new DateTimeDt(theDate); + return this; + } + + /** + * Sets the value for start (Starting time with inclusive boundary) + * + *

+ * Definition: + * The start of the period. The boundary is inclusive. + *

+ */ + public PeriodDt setStart( Date theDate, TemporalPrecisionEnum thePrecision) { + myStart = new DateTimeDt(theDate, thePrecision); + return this; + } + + + /** + * Gets the value(s) for end (End time with inclusive boundary, if not ongoing). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The end of the period. If the end of the period is missing, it means that the period is ongoing + *

+ */ + public DateTimeDt getEnd() { + if (myEnd == null) { + myEnd = new DateTimeDt(); + } + return myEnd; + } + + /** + * Sets the value(s) for end (End time with inclusive boundary, if not ongoing) + * + *

+ * Definition: + * The end of the period. If the end of the period is missing, it means that the period is ongoing + *

+ */ + public PeriodDt setEnd(DateTimeDt theValue) { + myEnd = theValue; + return this; + } + + /** + * Sets the value for end (End time with inclusive boundary, if not ongoing) + * + *

+ * Definition: + * The end of the period. If the end of the period is missing, it means that the period is ongoing + *

+ */ + public PeriodDt setEndWithSecondsPrecision( Date theDate) { + myEnd = new DateTimeDt(theDate); + return this; + } + + /** + * Sets the value for end (End time with inclusive boundary, if not ongoing) + * + *

+ * Definition: + * The end of the period. If the end of the period is missing, it means that the period is ongoing + *

+ */ + public PeriodDt setEnd( Date theDate, TemporalPrecisionEnum thePrecision) { + myEnd = new DateTimeDt(theDate, thePrecision); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/QuantityDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/QuantityDt.java new file mode 100644 index 00000000000..2c033d88cae --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/QuantityDt.java @@ -0,0 +1,436 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.api.annotation.SimpleSetter; +import ca.uhn.fhir.model.base.composite.BaseQuantityDt; +import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DecimalDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; + +/** + * HAPI/FHIR QuantityDt Datatype + * (A measured or measurable amount) + * + *

+ * Definition: + * A measured amount (or an amount that can potentially be measured). Note that measured amounts include amounts that are not precisely quantified, including amounts involving arbitrary units and floating currencies + *

+ * + *

+ * Requirements: + * Need to able to capture all sorts of measured values, even if the measured value are not precisely quantified. Values include exact measures such as 3.51g, customary units such as 3 tablets, and currencies such as $100.32USD + *

+ */ +@DatatypeDef(name="QuantityDt") +public class QuantityDt + extends BaseQuantityDt implements ICompositeDatatype +{ + + /** + * Constructor + */ + public QuantityDt() { + // nothing + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theValue") double theValue) { + setValue(theValue); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theValue") long theValue) { + setValue(theValue); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") double theValue, + @SimpleSetter.Parameter(name = "theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setUnits(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name = "theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name = "theValue") long theValue, + @SimpleSetter.Parameter(name = "theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setUnits(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name="theValue") double theValue, @SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setSystem(theSystem); + setUnits(theUnits); + } + + /** + * Constructor + */ + @SimpleSetter + public QuantityDt(@SimpleSetter.Parameter(name="theComparator") QuantityCompararatorEnum theComparator, @SimpleSetter.Parameter(name="theValue") long theValue, @SimpleSetter.Parameter(name="theSystem") String theSystem, @SimpleSetter.Parameter(name="theUnits") String theUnits) { + setValue(theValue); + setComparator(theComparator); + setSystem(theSystem); + setUnits(theUnits); + } + + + @Child(name="value", type=DecimalDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Numerical value (with implicit precision)", + formalDefinition="The value of the measured amount. The value includes an implicit precision in the presentation of the value" + ) + private DecimalDt myValue; + + @Child(name="comparator", type=CodeDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="< | <= | >= | > - how to understand the value", + formalDefinition="How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is \"<\" , then the real value is < stated value" + ) + private BoundCodeDt myComparator; + + @Child(name="units", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Unit representation", + formalDefinition="A human-readable form of the units" + ) + private StringDt myUnits; + + @Child(name="system", type=UriDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="System that defines coded unit form", + formalDefinition="The identification of the system that provides the coded form of the unit" + ) + private UriDt mySystem; + + @Child(name="code", type=CodeDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="Coded form of the unit", + formalDefinition="A computer processable form of the units in some unit representation system" + ) + private CodeDt myCode; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myValue, myComparator, myUnits, mySystem, myCode); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myValue, myComparator, myUnits, mySystem, myCode); + } + + /** + * Gets the value(s) for value (Numerical value (with implicit precision)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public DecimalDt getValueElement() { + if (myValue == null) { + myValue = new DecimalDt(); + } + return myValue; + } + + /** + * Sets the value(s) for value (Numerical value (with implicit precision)) + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue(DecimalDt theValue) { + myValue = theValue; + return this; + } + + /** + * Sets the value for value (Numerical value (with implicit precision)) + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue( long theValue) { + myValue = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for value (Numerical value (with implicit precision)) + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue( double theValue) { + myValue = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for value (Numerical value (with implicit precision)) + * + *

+ * Definition: + * The value of the measured amount. The value includes an implicit precision in the presentation of the value + *

+ */ + public QuantityDt setValue( java.math.BigDecimal theValue) { + myValue = new DecimalDt(theValue); + return this; + } + + + /** + * Gets the value(s) for comparator (< | <= | >= | > - how to understand the value). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is \"<\" , then the real value is < stated value + *

+ */ + public BoundCodeDt getComparatorElement() { + if (myComparator == null) { + myComparator = new BoundCodeDt(QuantityCompararatorEnum.VALUESET_BINDER); + } + return myComparator; + } + + /** + * Sets the value(s) for comparator (< | <= | >= | > - how to understand the value) + * + *

+ * Definition: + * How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is \"<\" , then the real value is < stated value + *

+ */ + public QuantityDt setComparator(BoundCodeDt theValue) { + myComparator = theValue; + return this; + } + + /** + * Sets the value(s) for comparator (< | <= | >= | > - how to understand the value) + * + *

+ * Definition: + * How the value should be understood and represented - whether the actual value is greater or less than the stated value due to measurement issues. E.g. if the comparator is \"<\" , then the real value is < stated value + *

+ */ + public QuantityDt setComparator(QuantityCompararatorEnum theValue) { + getComparatorElement().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for units (Unit representation). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A human-readable form of the units + *

+ */ + public StringDt getUnitsElement() { + if (myUnits == null) { + myUnits = new StringDt(); + } + return myUnits; + } + + /** + * Sets the value(s) for units (Unit representation) + * + *

+ * Definition: + * A human-readable form of the units + *

+ */ + public QuantityDt setUnits(StringDt theValue) { + myUnits = theValue; + return this; + } + + /** + * Sets the value for units (Unit representation) + * + *

+ * Definition: + * A human-readable form of the units + *

+ */ + public QuantityDt setUnits( String theString) { + myUnits = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for system (System that defines coded unit form). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identification of the system that provides the coded form of the unit + *

+ */ + public UriDt getSystemElement() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + /** + * Sets the value(s) for system (System that defines coded unit form) + * + *

+ * Definition: + * The identification of the system that provides the coded form of the unit + *

+ */ + public QuantityDt setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + /** + * Sets the value for system (System that defines coded unit form) + * + *

+ * Definition: + * The identification of the system that provides the coded form of the unit + *

+ */ + public QuantityDt setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for code (Coded form of the unit). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A computer processable form of the units in some unit representation system + *

+ */ + public CodeDt getCodeElement() { + if (myCode == null) { + myCode = new CodeDt(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Coded form of the unit) + * + *

+ * Definition: + * A computer processable form of the units in some unit representation system + *

+ */ + public QuantityDt setCode(CodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value for code (Coded form of the unit) + * + *

+ * Definition: + * A computer processable form of the units in some unit representation system + *

+ */ + public QuantityDt setCode( String theCode) { + myCode = new CodeDt(theCode); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/RangeDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/RangeDt.java new file mode 100644 index 00000000000..8a23cb4785a --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/RangeDt.java @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; + +/** + * HAPI/FHIR RangeDt Datatype + * (Set of values bounded by low and high) + * + *

+ * Definition: + * A set of ordered Quantities defined by a low and high limit. + *

+ * + *

+ * Requirements: + * Need to be able to specify ranges of values + *

+ */ +@DatatypeDef(name="RangeDt") +public class RangeDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public RangeDt() { + // nothing + } + + + @Child(name="low", type=QuantityDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Low limit", + formalDefinition="The low limit. The boundary is inclusive." + ) + private QuantityDt myLow; + + @Child(name="high", type=QuantityDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="High limit", + formalDefinition="The high limit. The boundary is inclusive." + ) + private QuantityDt myHigh; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myLow, myHigh); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myLow, myHigh); + } + + /** + * Gets the value(s) for low (Low limit). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public QuantityDt getLow() { + if (myLow == null) { + myLow = new QuantityDt(); + } + return myLow; + } + + /** + * Sets the value(s) for low (Low limit) + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public RangeDt setLow(QuantityDt theValue) { + myLow = theValue; + return this; + } + + /** + * Sets the value for low (Low limit) + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public RangeDt setLow( QuantityCompararatorEnum theComparator, double theValue, String theUnits) { + myLow = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for low (Low limit) + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public RangeDt setLow( QuantityCompararatorEnum theComparator, long theValue, String theUnits) { + myLow = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for low (Low limit) + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public RangeDt setLow( QuantityCompararatorEnum theComparator, double theValue, String theSystem, String theUnits) { + myLow = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for low (Low limit) + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public RangeDt setLow( QuantityCompararatorEnum theComparator, long theValue, String theSystem, String theUnits) { + myLow = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for low (Low limit) + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public RangeDt setLow( double theValue) { + myLow = new QuantityDt(theValue); + return this; + } + + /** + * Sets the value for low (Low limit) + * + *

+ * Definition: + * The low limit. The boundary is inclusive. + *

+ */ + public RangeDt setLow( long theValue) { + myLow = new QuantityDt(theValue); + return this; + } + + + /** + * Gets the value(s) for high (High limit). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public QuantityDt getHigh() { + if (myHigh == null) { + myHigh = new QuantityDt(); + } + return myHigh; + } + + /** + * Sets the value(s) for high (High limit) + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public RangeDt setHigh(QuantityDt theValue) { + myHigh = theValue; + return this; + } + + /** + * Sets the value for high (High limit) + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public RangeDt setHigh( QuantityCompararatorEnum theComparator, double theValue, String theUnits) { + myHigh = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for high (High limit) + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public RangeDt setHigh( QuantityCompararatorEnum theComparator, long theValue, String theUnits) { + myHigh = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for high (High limit) + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public RangeDt setHigh( QuantityCompararatorEnum theComparator, double theValue, String theSystem, String theUnits) { + myHigh = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for high (High limit) + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public RangeDt setHigh( QuantityCompararatorEnum theComparator, long theValue, String theSystem, String theUnits) { + myHigh = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for high (High limit) + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public RangeDt setHigh( double theValue) { + myHigh = new QuantityDt(theValue); + return this; + } + + /** + * Sets the value for high (High limit) + * + *

+ * Definition: + * The high limit. The boundary is inclusive. + *

+ */ + public RangeDt setHigh( long theValue) { + myHigh = new QuantityDt(theValue); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/RatioDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/RatioDt.java new file mode 100644 index 00000000000..39850e81c07 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/RatioDt.java @@ -0,0 +1,321 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; + +/** + * HAPI/FHIR RatioDt Datatype + * (A ratio of two Quantity values - a numerator and a denominator) + * + *

+ * Definition: + * A relationship of two Quantity values - expressed as a numerator and a denominator. + *

+ * + *

+ * Requirements: + * Need to able to capture ratios for some measurements (titers) and some rates (costs) + *

+ */ +@DatatypeDef(name="RatioDt") +public class RatioDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public RatioDt() { + // nothing + } + + + @Child(name="numerator", type=QuantityDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Numerator value", + formalDefinition="The value of the numerator" + ) + private QuantityDt myNumerator; + + @Child(name="denominator", type=QuantityDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Denominator value", + formalDefinition="The value of the denominator" + ) + private QuantityDt myDenominator; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myNumerator, myDenominator); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myNumerator, myDenominator); + } + + /** + * Gets the value(s) for numerator (Numerator value). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public QuantityDt getNumerator() { + if (myNumerator == null) { + myNumerator = new QuantityDt(); + } + return myNumerator; + } + + /** + * Sets the value(s) for numerator (Numerator value) + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public RatioDt setNumerator(QuantityDt theValue) { + myNumerator = theValue; + return this; + } + + /** + * Sets the value for numerator (Numerator value) + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public RatioDt setNumerator( QuantityCompararatorEnum theComparator, double theValue, String theUnits) { + myNumerator = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for numerator (Numerator value) + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public RatioDt setNumerator( QuantityCompararatorEnum theComparator, long theValue, String theUnits) { + myNumerator = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for numerator (Numerator value) + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public RatioDt setNumerator( QuantityCompararatorEnum theComparator, double theValue, String theSystem, String theUnits) { + myNumerator = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for numerator (Numerator value) + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public RatioDt setNumerator( QuantityCompararatorEnum theComparator, long theValue, String theSystem, String theUnits) { + myNumerator = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for numerator (Numerator value) + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public RatioDt setNumerator( double theValue) { + myNumerator = new QuantityDt(theValue); + return this; + } + + /** + * Sets the value for numerator (Numerator value) + * + *

+ * Definition: + * The value of the numerator + *

+ */ + public RatioDt setNumerator( long theValue) { + myNumerator = new QuantityDt(theValue); + return this; + } + + + /** + * Gets the value(s) for denominator (Denominator value). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public QuantityDt getDenominator() { + if (myDenominator == null) { + myDenominator = new QuantityDt(); + } + return myDenominator; + } + + /** + * Sets the value(s) for denominator (Denominator value) + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public RatioDt setDenominator(QuantityDt theValue) { + myDenominator = theValue; + return this; + } + + /** + * Sets the value for denominator (Denominator value) + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public RatioDt setDenominator( QuantityCompararatorEnum theComparator, double theValue, String theUnits) { + myDenominator = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for denominator (Denominator value) + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public RatioDt setDenominator( QuantityCompararatorEnum theComparator, long theValue, String theUnits) { + myDenominator = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for denominator (Denominator value) + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public RatioDt setDenominator( QuantityCompararatorEnum theComparator, double theValue, String theSystem, String theUnits) { + myDenominator = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for denominator (Denominator value) + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public RatioDt setDenominator( QuantityCompararatorEnum theComparator, long theValue, String theSystem, String theUnits) { + myDenominator = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for denominator (Denominator value) + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public RatioDt setDenominator( double theValue) { + myDenominator = new QuantityDt(theValue); + return this; + } + + /** + * Sets the value for denominator (Denominator value) + * + *

+ * Definition: + * The value of the denominator + *

+ */ + public RatioDt setDenominator( long theValue) { + myDenominator = new QuantityDt(theValue); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ResourceReferenceDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ResourceReferenceDt.java new file mode 100644 index 00000000000..4f0a2b479d4 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ResourceReferenceDt.java @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR ResourceReferenceDt Datatype + * (A reference from one resource to another) + * + *

+ * Definition: + * A reference from one resource to another + *

+ * + *

+ * Requirements: + * + *

+ */ +@DatatypeDef(name="ResourceReferenceDt") +public class ResourceReferenceDt + extends BaseResourceReferenceDt implements ICompositeDatatype +{ + + /** + * Constructor + */ + public ResourceReferenceDt() { + // nothing + } + + /** + * Constructor which creates a resource reference containing the actual resource in question. + *

+ * When using this in a server: Generally if this is serialized, it will be serialized as a contained + * resource, so this should not be used if the intent is not to actually supply the referenced resource. This is not + * a hard-and-fast rule however, as the server can be configured to not serialized this resource, or to load an ID + * and contain even if this constructor is not used. + *

+ * + * @param theResource + * The resource instance + */ + public ResourceReferenceDt(IResource theResource) { + super(theResource); + } + + /** + * Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute + * URL) + * + * @param theId + * The reference itself + */ + public ResourceReferenceDt(String theId) { + setReference(new IdDt(theId)); + } + + /** + * Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute + * URL) + * + * @param theId + * The reference itself + */ + public ResourceReferenceDt(IdDt theResourceId) { + setReference(theResourceId); + } + + @Child(name="reference", type=IdDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Relative, internal or absolute URL reference", + formalDefinition="A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources" + ) + private IdDt myReference; + + @Child(name="display", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Text alternative for the resource", + formalDefinition="Plain text narrative that identifies the resource in addition to the resource reference" + ) + private StringDt myDisplay; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myReference, myDisplay); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myReference, myDisplay); + } + + /** + * Gets the value(s) for reference (Relative, internal or absolute URL reference). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources + *

+ */ + public IdDt getReference() { + if (myReference == null) { + myReference = new IdDt(); + } + return myReference; + } + + /** + * Sets the value(s) for reference (Relative, internal or absolute URL reference) + * + *

+ * Definition: + * A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources + *

+ */ + public ResourceReferenceDt setReference(IdDt theValue) { + myReference = theValue; + return this; + } + + /** + * Sets the value for reference (Relative, internal or absolute URL reference) + * + *

+ * Definition: + * A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources + *

+ */ + public ResourceReferenceDt setReference( String theId) { + myReference = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for display (Text alternative for the resource). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Plain text narrative that identifies the resource in addition to the resource reference + *

+ */ + public StringDt getDisplay() { + if (myDisplay == null) { + myDisplay = new StringDt(); + } + return myDisplay; + } + + /** + * Sets the value(s) for display (Text alternative for the resource) + * + *

+ * Definition: + * Plain text narrative that identifies the resource in addition to the resource reference + *

+ */ + public ResourceReferenceDt setDisplay(StringDt theValue) { + myDisplay = theValue; + return this; + } + + /** + * Sets the value for display (Text alternative for the resource) + * + *

+ * Definition: + * Plain text narrative that identifies the resource in addition to the resource reference + *

+ */ + public ResourceReferenceDt setDisplay( String theString) { + myDisplay = new StringDt(theString); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/SampledDataDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/SampledDataDt.java new file mode 100644 index 00000000000..d9b2483396a --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/SampledDataDt.java @@ -0,0 +1,618 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum; +import ca.uhn.fhir.model.primitive.DecimalDt; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.model.primitive.StringDt; + +/** + * HAPI/FHIR SampledDataDt Datatype + * (A series of measurements taken by a device) + * + *

+ * Definition: + * A series of measurements taken by a device, with upper and lower limits. There may be more than one dimension in the data + *

+ * + *

+ * Requirements: + * There is a need for a concise way to handle the data produced by devices that sample a physical state at a high frequency + *

+ */ +@DatatypeDef(name="SampledDataDt") +public class SampledDataDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public SampledDataDt() { + // nothing + } + + + @Child(name="origin", type=QuantityDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Zero value and units", + formalDefinition="The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series" + ) + private QuantityDt myOrigin; + + @Child(name="period", type=DecimalDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="Number of milliseconds between samples", + formalDefinition="The length of time between sampling times, measured in milliseconds" + ) + private DecimalDt myPeriod; + + @Child(name="factor", type=DecimalDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Multiply data by this before adding to origin", + formalDefinition="A correction factor that is applied to the sampled data points before they are added to the origin" + ) + private DecimalDt myFactor; + + @Child(name="lowerLimit", type=DecimalDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Lower limit of detection", + formalDefinition="The lower limit of detection of the measured points. This is needed if any of the data points have the value \"L\" (lower than detection limit)" + ) + private DecimalDt myLowerLimit; + + @Child(name="upperLimit", type=DecimalDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="Upper limit of detection", + formalDefinition="The upper limit of detection of the measured points. This is needed if any of the data points have the value \"U\" (higher than detection limit)" + ) + private DecimalDt myUpperLimit; + + @Child(name="dimensions", type=IntegerDt.class, order=5, min=1, max=1) + @Description( + shortDefinition="Number of sample points at each time point", + formalDefinition="The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once" + ) + private IntegerDt myDimensions; + + @Child(name="data", type=StringDt.class, order=6, min=1, max=1) + @Description( + shortDefinition="Decimal values with spaces, or \"E\" | \"U\" | \"L\"", + formalDefinition="A series of data points which are decimal values separated by a single space (character u20). The special values \"E\" (error), \"L\" (below detection limit) and \"U\" (above detection limit) can also be used in place of a decimal value" + ) + private StringDt myData; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myOrigin, myPeriod, myFactor, myLowerLimit, myUpperLimit, myDimensions, myData); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myOrigin, myPeriod, myFactor, myLowerLimit, myUpperLimit, myDimensions, myData); + } + + /** + * Gets the value(s) for origin (Zero value and units). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public QuantityDt getOrigin() { + if (myOrigin == null) { + myOrigin = new QuantityDt(); + } + return myOrigin; + } + + /** + * Sets the value(s) for origin (Zero value and units) + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public SampledDataDt setOrigin(QuantityDt theValue) { + myOrigin = theValue; + return this; + } + + /** + * Sets the value for origin (Zero value and units) + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public SampledDataDt setOrigin( QuantityCompararatorEnum theComparator, double theValue, String theUnits) { + myOrigin = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for origin (Zero value and units) + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public SampledDataDt setOrigin( QuantityCompararatorEnum theComparator, long theValue, String theUnits) { + myOrigin = new QuantityDt(theComparator, theValue, theUnits); + return this; + } + + /** + * Sets the value for origin (Zero value and units) + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public SampledDataDt setOrigin( QuantityCompararatorEnum theComparator, double theValue, String theSystem, String theUnits) { + myOrigin = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for origin (Zero value and units) + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public SampledDataDt setOrigin( QuantityCompararatorEnum theComparator, long theValue, String theSystem, String theUnits) { + myOrigin = new QuantityDt(theComparator, theValue, theSystem, theUnits); + return this; + } + + /** + * Sets the value for origin (Zero value and units) + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public SampledDataDt setOrigin( double theValue) { + myOrigin = new QuantityDt(theValue); + return this; + } + + /** + * Sets the value for origin (Zero value and units) + * + *

+ * Definition: + * The base quantity that a measured value of zero represents. In addition, this provides the units of the entire measurement series + *

+ */ + public SampledDataDt setOrigin( long theValue) { + myOrigin = new QuantityDt(theValue); + return this; + } + + + /** + * Gets the value(s) for period (Number of milliseconds between samples). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The length of time between sampling times, measured in milliseconds + *

+ */ + public DecimalDt getPeriod() { + if (myPeriod == null) { + myPeriod = new DecimalDt(); + } + return myPeriod; + } + + /** + * Sets the value(s) for period (Number of milliseconds between samples) + * + *

+ * Definition: + * The length of time between sampling times, measured in milliseconds + *

+ */ + public SampledDataDt setPeriod(DecimalDt theValue) { + myPeriod = theValue; + return this; + } + + /** + * Sets the value for period (Number of milliseconds between samples) + * + *

+ * Definition: + * The length of time between sampling times, measured in milliseconds + *

+ */ + public SampledDataDt setPeriod( long theValue) { + myPeriod = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for period (Number of milliseconds between samples) + * + *

+ * Definition: + * The length of time between sampling times, measured in milliseconds + *

+ */ + public SampledDataDt setPeriod( double theValue) { + myPeriod = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for period (Number of milliseconds between samples) + * + *

+ * Definition: + * The length of time between sampling times, measured in milliseconds + *

+ */ + public SampledDataDt setPeriod( java.math.BigDecimal theValue) { + myPeriod = new DecimalDt(theValue); + return this; + } + + + /** + * Gets the value(s) for factor (Multiply data by this before adding to origin). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A correction factor that is applied to the sampled data points before they are added to the origin + *

+ */ + public DecimalDt getFactor() { + if (myFactor == null) { + myFactor = new DecimalDt(); + } + return myFactor; + } + + /** + * Sets the value(s) for factor (Multiply data by this before adding to origin) + * + *

+ * Definition: + * A correction factor that is applied to the sampled data points before they are added to the origin + *

+ */ + public SampledDataDt setFactor(DecimalDt theValue) { + myFactor = theValue; + return this; + } + + /** + * Sets the value for factor (Multiply data by this before adding to origin) + * + *

+ * Definition: + * A correction factor that is applied to the sampled data points before they are added to the origin + *

+ */ + public SampledDataDt setFactor( long theValue) { + myFactor = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for factor (Multiply data by this before adding to origin) + * + *

+ * Definition: + * A correction factor that is applied to the sampled data points before they are added to the origin + *

+ */ + public SampledDataDt setFactor( double theValue) { + myFactor = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for factor (Multiply data by this before adding to origin) + * + *

+ * Definition: + * A correction factor that is applied to the sampled data points before they are added to the origin + *

+ */ + public SampledDataDt setFactor( java.math.BigDecimal theValue) { + myFactor = new DecimalDt(theValue); + return this; + } + + + /** + * Gets the value(s) for lowerLimit (Lower limit of detection). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The lower limit of detection of the measured points. This is needed if any of the data points have the value \"L\" (lower than detection limit) + *

+ */ + public DecimalDt getLowerLimit() { + if (myLowerLimit == null) { + myLowerLimit = new DecimalDt(); + } + return myLowerLimit; + } + + /** + * Sets the value(s) for lowerLimit (Lower limit of detection) + * + *

+ * Definition: + * The lower limit of detection of the measured points. This is needed if any of the data points have the value \"L\" (lower than detection limit) + *

+ */ + public SampledDataDt setLowerLimit(DecimalDt theValue) { + myLowerLimit = theValue; + return this; + } + + /** + * Sets the value for lowerLimit (Lower limit of detection) + * + *

+ * Definition: + * The lower limit of detection of the measured points. This is needed if any of the data points have the value \"L\" (lower than detection limit) + *

+ */ + public SampledDataDt setLowerLimit( long theValue) { + myLowerLimit = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for lowerLimit (Lower limit of detection) + * + *

+ * Definition: + * The lower limit of detection of the measured points. This is needed if any of the data points have the value \"L\" (lower than detection limit) + *

+ */ + public SampledDataDt setLowerLimit( double theValue) { + myLowerLimit = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for lowerLimit (Lower limit of detection) + * + *

+ * Definition: + * The lower limit of detection of the measured points. This is needed if any of the data points have the value \"L\" (lower than detection limit) + *

+ */ + public SampledDataDt setLowerLimit( java.math.BigDecimal theValue) { + myLowerLimit = new DecimalDt(theValue); + return this; + } + + + /** + * Gets the value(s) for upperLimit (Upper limit of detection). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The upper limit of detection of the measured points. This is needed if any of the data points have the value \"U\" (higher than detection limit) + *

+ */ + public DecimalDt getUpperLimit() { + if (myUpperLimit == null) { + myUpperLimit = new DecimalDt(); + } + return myUpperLimit; + } + + /** + * Sets the value(s) for upperLimit (Upper limit of detection) + * + *

+ * Definition: + * The upper limit of detection of the measured points. This is needed if any of the data points have the value \"U\" (higher than detection limit) + *

+ */ + public SampledDataDt setUpperLimit(DecimalDt theValue) { + myUpperLimit = theValue; + return this; + } + + /** + * Sets the value for upperLimit (Upper limit of detection) + * + *

+ * Definition: + * The upper limit of detection of the measured points. This is needed if any of the data points have the value \"U\" (higher than detection limit) + *

+ */ + public SampledDataDt setUpperLimit( long theValue) { + myUpperLimit = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for upperLimit (Upper limit of detection) + * + *

+ * Definition: + * The upper limit of detection of the measured points. This is needed if any of the data points have the value \"U\" (higher than detection limit) + *

+ */ + public SampledDataDt setUpperLimit( double theValue) { + myUpperLimit = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for upperLimit (Upper limit of detection) + * + *

+ * Definition: + * The upper limit of detection of the measured points. This is needed if any of the data points have the value \"U\" (higher than detection limit) + *

+ */ + public SampledDataDt setUpperLimit( java.math.BigDecimal theValue) { + myUpperLimit = new DecimalDt(theValue); + return this; + } + + + /** + * Gets the value(s) for dimensions (Number of sample points at each time point). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once + *

+ */ + public IntegerDt getDimensions() { + if (myDimensions == null) { + myDimensions = new IntegerDt(); + } + return myDimensions; + } + + /** + * Sets the value(s) for dimensions (Number of sample points at each time point) + * + *

+ * Definition: + * The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once + *

+ */ + public SampledDataDt setDimensions(IntegerDt theValue) { + myDimensions = theValue; + return this; + } + + /** + * Sets the value for dimensions (Number of sample points at each time point) + * + *

+ * Definition: + * The number of sample points at each time point. If this value is greater than one, then the dimensions will be interlaced - all the sample points for a point in time will be recorded at once + *

+ */ + public SampledDataDt setDimensions( int theInteger) { + myDimensions = new IntegerDt(theInteger); + return this; + } + + + /** + * Gets the value(s) for data (Decimal values with spaces, or \"E\" | \"U\" | \"L\"). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A series of data points which are decimal values separated by a single space (character u20). The special values \"E\" (error), \"L\" (below detection limit) and \"U\" (above detection limit) can also be used in place of a decimal value + *

+ */ + public StringDt getData() { + if (myData == null) { + myData = new StringDt(); + } + return myData; + } + + /** + * Sets the value(s) for data (Decimal values with spaces, or \"E\" | \"U\" | \"L\") + * + *

+ * Definition: + * A series of data points which are decimal values separated by a single space (character u20). The special values \"E\" (error), \"L\" (below detection limit) and \"U\" (above detection limit) can also be used in place of a decimal value + *

+ */ + public SampledDataDt setData(StringDt theValue) { + myData = theValue; + return this; + } + + /** + * Sets the value for data (Decimal values with spaces, or \"E\" | \"U\" | \"L\") + * + *

+ * Definition: + * A series of data points which are decimal values separated by a single space (character u20). The special values \"E\" (error), \"L\" (below detection limit) and \"U\" (above detection limit) can also be used in place of a decimal value + *

+ */ + public SampledDataDt setData( String theString) { + myData = new StringDt(theString); + return this; + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ScheduleDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ScheduleDt.java new file mode 100644 index 00000000000..e13545c60ca --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/composite/ScheduleDt.java @@ -0,0 +1,575 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.composite; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import java.util.Date; +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.ICompositeDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResourceBlock; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +import ca.uhn.fhir.model.api.annotation.Block; +import ca.uhn.fhir.model.api.annotation.Child; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.model.dstu.valueset.EventTimingEnum; +import ca.uhn.fhir.model.dstu.valueset.UnitsOfTimeEnum; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.DecimalDt; +import ca.uhn.fhir.model.primitive.IntegerDt; + +/** + * HAPI/FHIR ScheduleDt Datatype + * (A schedule that specifies an event that may occur multiple times) + * + *

+ * Definition: + * Specifies an event that may occur multiple times. Schedules are used for to reord when things are expected or requested to occur. + *

+ * + *

+ * Requirements: + * Need to able to track schedules. There are several different ways to do scheduling: one or more specified times, a simple rules like three times a day, or before/after meals + *

+ */ +@DatatypeDef(name="ScheduleDt") +public class ScheduleDt + extends BaseIdentifiableElement implements ICompositeDatatype +{ + + /** + * Constructor + */ + public ScheduleDt() { + // nothing + } + + + @Child(name="event", type=PeriodDt.class, order=0, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="When the event occurs", + formalDefinition="Identifies specific time periods when the event should occur" + ) + private java.util.List myEvent; + + @Child(name="repeat", order=1, min=0, max=1) + @Description( + shortDefinition="Only if there is none or one event", + formalDefinition="Identifies a repeating pattern to the intended time periods." + ) + private Repeat myRepeat; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myEvent, myRepeat); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myEvent, myRepeat); + } + + /** + * Gets the value(s) for event (When the event occurs). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies specific time periods when the event should occur + *

+ */ + public java.util.List getEvent() { + if (myEvent == null) { + myEvent = new java.util.ArrayList(); + } + return myEvent; + } + + /** + * Sets the value(s) for event (When the event occurs) + * + *

+ * Definition: + * Identifies specific time periods when the event should occur + *

+ */ + public ScheduleDt setEvent(java.util.List theValue) { + myEvent = theValue; + return this; + } + + /** + * Adds and returns a new value for event (When the event occurs) + * + *

+ * Definition: + * Identifies specific time periods when the event should occur + *

+ */ + public PeriodDt addEvent() { + PeriodDt newType = new PeriodDt(); + getEvent().add(newType); + return newType; + } + + /** + * Gets the first repetition for event (When the event occurs), + * creating it if it does not already exist. + * + *

+ * Definition: + * Identifies specific time periods when the event should occur + *

+ */ + public PeriodDt getEventFirstRep() { + if (getEvent().isEmpty()) { + return addEvent(); + } + return getEvent().get(0); + } + + /** + * Gets the value(s) for repeat (Only if there is none or one event). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies a repeating pattern to the intended time periods. + *

+ */ + public Repeat getRepeat() { + if (myRepeat == null) { + myRepeat = new Repeat(); + } + return myRepeat; + } + + /** + * Sets the value(s) for repeat (Only if there is none or one event) + * + *

+ * Definition: + * Identifies a repeating pattern to the intended time periods. + *

+ */ + public ScheduleDt setRepeat(Repeat theValue) { + myRepeat = theValue; + return this; + } + + + /** + * Block class for child element: Schedule.repeat (Only if there is none or one event) + * + *

+ * Definition: + * Identifies a repeating pattern to the intended time periods. + *

+ */ + @Block() + public static class Repeat extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="frequency", type=IntegerDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Event occurs frequency times per duration", + formalDefinition="Indicates how often the event should occur." + ) + private IntegerDt myFrequency; + + @Child(name="when", type=CodeDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="HS | WAKE | AC | ACM | ACD | ACV | PC | PCM | PCD | PCV - common life events", + formalDefinition="Identifies the occurrence of daily life that determines timing" + ) + private BoundCodeDt myWhen; + + @Child(name="duration", type=DecimalDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="Repeating or event-related duration", + formalDefinition="How long each repetition should last" + ) + private DecimalDt myDuration; + + @Child(name="units", type=CodeDt.class, order=3, min=1, max=1) + @Description( + shortDefinition="s | min | h | d | wk | mo | a - unit of time (UCUM)", + formalDefinition="The units of time for the duration" + ) + private BoundCodeDt myUnits; + + @Child(name="count", type=IntegerDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="Number of times to repeat", + formalDefinition="A total count of the desired number of repetitions" + ) + private IntegerDt myCount; + + @Child(name="end", type=DateTimeDt.class, order=5, min=0, max=1) + @Description( + shortDefinition="When to stop repeats", + formalDefinition="When to stop repeating the schedule" + ) + private DateTimeDt myEnd; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myFrequency, myWhen, myDuration, myUnits, myCount, myEnd); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myFrequency, myWhen, myDuration, myUnits, myCount, myEnd); + } + + /** + * Gets the value(s) for frequency (Event occurs frequency times per duration). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates how often the event should occur. + *

+ */ + public IntegerDt getFrequency() { + if (myFrequency == null) { + myFrequency = new IntegerDt(); + } + return myFrequency; + } + + /** + * Sets the value(s) for frequency (Event occurs frequency times per duration) + * + *

+ * Definition: + * Indicates how often the event should occur. + *

+ */ + public Repeat setFrequency(IntegerDt theValue) { + myFrequency = theValue; + return this; + } + + /** + * Sets the value for frequency (Event occurs frequency times per duration) + * + *

+ * Definition: + * Indicates how often the event should occur. + *

+ */ + public Repeat setFrequency( int theInteger) { + myFrequency = new IntegerDt(theInteger); + return this; + } + + + /** + * Gets the value(s) for when (HS | WAKE | AC | ACM | ACD | ACV | PC | PCM | PCD | PCV - common life events). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the occurrence of daily life that determines timing + *

+ */ + public BoundCodeDt getWhen() { + if (myWhen == null) { + myWhen = new BoundCodeDt(EventTimingEnum.VALUESET_BINDER); + } + return myWhen; + } + + /** + * Sets the value(s) for when (HS | WAKE | AC | ACM | ACD | ACV | PC | PCM | PCD | PCV - common life events) + * + *

+ * Definition: + * Identifies the occurrence of daily life that determines timing + *

+ */ + public Repeat setWhen(BoundCodeDt theValue) { + myWhen = theValue; + return this; + } + + /** + * Sets the value(s) for when (HS | WAKE | AC | ACM | ACD | ACV | PC | PCM | PCD | PCV - common life events) + * + *

+ * Definition: + * Identifies the occurrence of daily life that determines timing + *

+ */ + public Repeat setWhen(EventTimingEnum theValue) { + getWhen().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for duration (Repeating or event-related duration). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * How long each repetition should last + *

+ */ + public DecimalDt getDuration() { + if (myDuration == null) { + myDuration = new DecimalDt(); + } + return myDuration; + } + + /** + * Sets the value(s) for duration (Repeating or event-related duration) + * + *

+ * Definition: + * How long each repetition should last + *

+ */ + public Repeat setDuration(DecimalDt theValue) { + myDuration = theValue; + return this; + } + + /** + * Sets the value for duration (Repeating or event-related duration) + * + *

+ * Definition: + * How long each repetition should last + *

+ */ + public Repeat setDuration( long theValue) { + myDuration = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for duration (Repeating or event-related duration) + * + *

+ * Definition: + * How long each repetition should last + *

+ */ + public Repeat setDuration( double theValue) { + myDuration = new DecimalDt(theValue); + return this; + } + + /** + * Sets the value for duration (Repeating or event-related duration) + * + *

+ * Definition: + * How long each repetition should last + *

+ */ + public Repeat setDuration( java.math.BigDecimal theValue) { + myDuration = new DecimalDt(theValue); + return this; + } + + + /** + * Gets the value(s) for units (s | min | h | d | wk | mo | a - unit of time (UCUM)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The units of time for the duration + *

+ */ + public BoundCodeDt getUnits() { + if (myUnits == null) { + myUnits = new BoundCodeDt(UnitsOfTimeEnum.VALUESET_BINDER); + } + return myUnits; + } + + /** + * Sets the value(s) for units (s | min | h | d | wk | mo | a - unit of time (UCUM)) + * + *

+ * Definition: + * The units of time for the duration + *

+ */ + public Repeat setUnits(BoundCodeDt theValue) { + myUnits = theValue; + return this; + } + + /** + * Sets the value(s) for units (s | min | h | d | wk | mo | a - unit of time (UCUM)) + * + *

+ * Definition: + * The units of time for the duration + *

+ */ + public Repeat setUnits(UnitsOfTimeEnum theValue) { + getUnits().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for count (Number of times to repeat). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A total count of the desired number of repetitions + *

+ */ + public IntegerDt getCount() { + if (myCount == null) { + myCount = new IntegerDt(); + } + return myCount; + } + + /** + * Sets the value(s) for count (Number of times to repeat) + * + *

+ * Definition: + * A total count of the desired number of repetitions + *

+ */ + public Repeat setCount(IntegerDt theValue) { + myCount = theValue; + return this; + } + + /** + * Sets the value for count (Number of times to repeat) + * + *

+ * Definition: + * A total count of the desired number of repetitions + *

+ */ + public Repeat setCount( int theInteger) { + myCount = new IntegerDt(theInteger); + return this; + } + + + /** + * Gets the value(s) for end (When to stop repeats). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * When to stop repeating the schedule + *

+ */ + public DateTimeDt getEnd() { + if (myEnd == null) { + myEnd = new DateTimeDt(); + } + return myEnd; + } + + /** + * Sets the value(s) for end (When to stop repeats) + * + *

+ * Definition: + * When to stop repeating the schedule + *

+ */ + public Repeat setEnd(DateTimeDt theValue) { + myEnd = theValue; + return this; + } + + /** + * Sets the value for end (When to stop repeats) + * + *

+ * Definition: + * When to stop repeating the schedule + *

+ */ + public Repeat setEndWithSecondsPrecision( Date theDate) { + myEnd = new DateTimeDt(theDate); + return this; + } + + /** + * Sets the value for end (When to stop repeats) + * + *

+ * Definition: + * When to stop repeating the schedule + *

+ */ + public Repeat setEnd( Date theDate, TemporalPrecisionEnum thePrecision) { + myEnd = new DateTimeDt(theDate, thePrecision); + return this; + } + + + + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/Conformance.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/Conformance.java new file mode 100644 index 00000000000..d65ed77e4dc --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/Conformance.java @@ -0,0 +1,4885 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.resource; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + + +import java.util.Date; +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.BaseResource; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.IResourceBlock; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +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.ResourceDef; +import ca.uhn.fhir.model.api.annotation.SearchParamDefinition; +import ca.uhn.fhir.model.base.resource.BaseConformance; +import ca.uhn.fhir.model.dstu.composite.BoundCodeableConceptDt_; +import ca.uhn.fhir.model.dstu.composite.CodeableConceptDt; +import ca.uhn.fhir.model.dstu.composite.CodingDt; +import ca.uhn.fhir.model.dstu.composite.ContactDt; +import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.valueset.ConformanceEventModeEnum; +import ca.uhn.fhir.model.dstu.valueset.ConformanceStatementStatusEnum; +import ca.uhn.fhir.model.dstu.valueset.ContactUseEnum; +import ca.uhn.fhir.model.dstu.valueset.DocumentModeEnum; +import ca.uhn.fhir.model.dstu.valueset.MessageSignificanceCategoryEnum; +import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.RestfulConformanceModeEnum; +import ca.uhn.fhir.model.dstu.valueset.RestfulOperationSystemEnum; +import ca.uhn.fhir.model.dstu.valueset.RestfulOperationTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.RestfulSecurityServiceEnum; +import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum; +import ca.uhn.fhir.model.primitive.Base64BinaryDt; +import ca.uhn.fhir.model.primitive.BooleanDt; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.gclient.DateClientParam; +import ca.uhn.fhir.rest.gclient.ReferenceClientParam; +import ca.uhn.fhir.rest.gclient.StringClientParam; +import ca.uhn.fhir.rest.gclient.TokenClientParam; + + +/** + * HAPI/FHIR Conformance Resource + * (A conformance statement) + * + *

+ * Definition: + * A conformance statement is a set of requirements for a desired implementation or a description of how a target application fulfills those requirements in a particular implementation + *

+ * + *

+ * Requirements: + * + *

+ * + *

+ * Profile Definition: + * http://hl7.org/fhir/profiles/Conformance + *

+ * + */ +@ResourceDef(name="Conformance", profile="http://hl7.org/fhir/profiles/Conformance", id="conformance") +public class Conformance extends BaseConformance implements IResource { + + /** + * Search parameter constant for identifier + *

+ * Description: The identifier of the conformance statement
+ * Type: token
+ * Path: Conformance.identifier
+ *

+ */ + @SearchParamDefinition(name="identifier", path="Conformance.identifier", description="The identifier of the conformance statement", type="token" ) + public static final String SP_IDENTIFIER = "identifier"; + + /** + * Fluent Client search parameter constant for identifier + *

+ * Description: The identifier of the conformance statement
+ * Type: token
+ * Path: Conformance.identifier
+ *

+ */ + public static final TokenClientParam IDENTIFIER = new TokenClientParam(SP_IDENTIFIER); + + /** + * Search parameter constant for version + *

+ * Description: The version identifier of the conformance statement
+ * Type: token
+ * Path: Conformance.version
+ *

+ */ + @SearchParamDefinition(name="version", path="Conformance.version", description="The version identifier of the conformance statement", type="token" ) + public static final String SP_VERSION = "version"; + + /** + * Fluent Client search parameter constant for version + *

+ * Description: The version identifier of the conformance statement
+ * Type: token
+ * Path: Conformance.version
+ *

+ */ + public static final TokenClientParam VERSION = new TokenClientParam(SP_VERSION); + + /** + * Search parameter constant for name + *

+ * Description: Name of the conformance statement
+ * Type: string
+ * Path: Conformance.name
+ *

+ */ + @SearchParamDefinition(name="name", path="Conformance.name", description="Name of the conformance statement", type="string" ) + public static final String SP_NAME = "name"; + + /** + * Fluent Client search parameter constant for name + *

+ * Description: Name of the conformance statement
+ * Type: string
+ * Path: Conformance.name
+ *

+ */ + public static final StringClientParam NAME = new StringClientParam(SP_NAME); + + /** + * Search parameter constant for publisher + *

+ * Description: Name of the publisher of the conformance statement
+ * Type: string
+ * Path: Conformance.publisher
+ *

+ */ + @SearchParamDefinition(name="publisher", path="Conformance.publisher", description="Name of the publisher of the conformance statement", type="string" ) + public static final String SP_PUBLISHER = "publisher"; + + /** + * Fluent Client search parameter constant for publisher + *

+ * Description: Name of the publisher of the conformance statement
+ * Type: string
+ * Path: Conformance.publisher
+ *

+ */ + public static final StringClientParam PUBLISHER = new StringClientParam(SP_PUBLISHER); + + /** + * Search parameter constant for description + *

+ * Description: Text search in the description of the conformance statement
+ * Type: string
+ * Path: Conformance.description
+ *

+ */ + @SearchParamDefinition(name="description", path="Conformance.description", description="Text search in the description of the conformance statement", type="string" ) + public static final String SP_DESCRIPTION = "description"; + + /** + * Fluent Client search parameter constant for description + *

+ * Description: Text search in the description of the conformance statement
+ * Type: string
+ * Path: Conformance.description
+ *

+ */ + public static final StringClientParam DESCRIPTION = new StringClientParam(SP_DESCRIPTION); + + /** + * Search parameter constant for status + *

+ * Description: The current status of the conformance statement
+ * Type: token
+ * Path: Conformance.status
+ *

+ */ + @SearchParamDefinition(name="status", path="Conformance.status", description="The current status of the conformance statement", type="token" ) + public static final String SP_STATUS = "status"; + + /** + * Fluent Client search parameter constant for status + *

+ * Description: The current status of the conformance statement
+ * Type: token
+ * Path: Conformance.status
+ *

+ */ + public static final TokenClientParam STATUS = new TokenClientParam(SP_STATUS); + + /** + * Search parameter constant for date + *

+ * Description: The conformance statement publication date
+ * Type: date
+ * Path: Conformance.date
+ *

+ */ + @SearchParamDefinition(name="date", path="Conformance.date", description="The conformance statement publication date", type="date" ) + public static final String SP_DATE = "date"; + + /** + * Fluent Client search parameter constant for date + *

+ * Description: The conformance statement publication date
+ * Type: date
+ * Path: Conformance.date
+ *

+ */ + public static final DateClientParam DATE = new DateClientParam(SP_DATE); + + /** + * Search parameter constant for software + *

+ * Description: Part of a the name of a software application
+ * Type: string
+ * Path: Conformance.software.name
+ *

+ */ + @SearchParamDefinition(name="software", path="Conformance.software.name", description="Part of a the name of a software application", type="string" ) + public static final String SP_SOFTWARE = "software"; + + /** + * Fluent Client search parameter constant for software + *

+ * Description: Part of a the name of a software application
+ * Type: string
+ * Path: Conformance.software.name
+ *

+ */ + public static final StringClientParam SOFTWARE = new StringClientParam(SP_SOFTWARE); + + /** + * Search parameter constant for fhirversion + *

+ * Description: The version of FHIR
+ * Type: token
+ * Path: Conformance.version
+ *

+ */ + @SearchParamDefinition(name="fhirversion", path="Conformance.version", description="The version of FHIR", type="token" ) + public static final String SP_FHIRVERSION = "fhirversion"; + + /** + * Fluent Client search parameter constant for fhirversion + *

+ * Description: The version of FHIR
+ * Type: token
+ * Path: Conformance.version
+ *

+ */ + public static final TokenClientParam FHIRVERSION = new TokenClientParam(SP_FHIRVERSION); + + /** + * Search parameter constant for resource + *

+ * Description: Name of a resource mentioned in a conformance statement
+ * Type: token
+ * Path: Conformance.rest.resource.type
+ *

+ */ + @SearchParamDefinition(name="resource", path="Conformance.rest.resource.type", description="Name of a resource mentioned in a conformance statement", type="token" ) + public static final String SP_RESOURCE = "resource"; + + /** + * Fluent Client search parameter constant for resource + *

+ * Description: Name of a resource mentioned in a conformance statement
+ * Type: token
+ * Path: Conformance.rest.resource.type
+ *

+ */ + public static final TokenClientParam RESOURCE = new TokenClientParam(SP_RESOURCE); + + /** + * Search parameter constant for event + *

+ * Description: Event code in a conformance statement
+ * Type: token
+ * Path: Conformance.messaging.event.code
+ *

+ */ + @SearchParamDefinition(name="event", path="Conformance.messaging.event.code", description="Event code in a conformance statement", type="token" ) + public static final String SP_EVENT = "event"; + + /** + * Fluent Client search parameter constant for event + *

+ * Description: Event code in a conformance statement
+ * Type: token
+ * Path: Conformance.messaging.event.code
+ *

+ */ + public static final TokenClientParam EVENT = new TokenClientParam(SP_EVENT); + + /** + * Search parameter constant for mode + *

+ * Description: Mode - restful (server/client) or messaging (sender/receiver)
+ * Type: token
+ * Path: Conformance.rest.mode
+ *

+ */ + @SearchParamDefinition(name="mode", path="Conformance.rest.mode", description="Mode - restful (server/client) or messaging (sender/receiver)", type="token" ) + public static final String SP_MODE = "mode"; + + /** + * Fluent Client search parameter constant for mode + *

+ * Description: Mode - restful (server/client) or messaging (sender/receiver)
+ * Type: token
+ * Path: Conformance.rest.mode
+ *

+ */ + public static final TokenClientParam MODE = new TokenClientParam(SP_MODE); + + /** + * Search parameter constant for profile + *

+ * Description: A profile id invoked in a conformance statement
+ * Type: reference
+ * Path: Conformance.rest.resource.profile
+ *

+ */ + @SearchParamDefinition(name="profile", path="Conformance.rest.resource.profile", description="A profile id invoked in a conformance statement", type="reference" ) + public static final String SP_PROFILE = "profile"; + + /** + * Fluent Client search parameter constant for profile + *

+ * Description: A profile id invoked in a conformance statement
+ * Type: reference
+ * Path: Conformance.rest.resource.profile
+ *

+ */ + public static final ReferenceClientParam PROFILE = new ReferenceClientParam(SP_PROFILE); + + /** + * Constant for fluent queries to be used to add include statements. Specifies + * the path value of "Conformance.rest.resource.profile". + */ + public static final Include INCLUDE_REST_RESOURCE_PROFILE = new Include("Conformance.rest.resource.profile"); + + /** + * Search parameter constant for format + *

+ * Description:
+ * Type: token
+ * Path: Conformance.format
+ *

+ */ + @SearchParamDefinition(name="format", path="Conformance.format", description="", type="token" ) + public static final String SP_FORMAT = "format"; + + /** + * Fluent Client search parameter constant for format + *

+ * Description:
+ * Type: token
+ * Path: Conformance.format
+ *

+ */ + public static final TokenClientParam FORMAT = new TokenClientParam(SP_FORMAT); + + /** + * Search parameter constant for security + *

+ * Description:
+ * Type: token
+ * Path: Conformance.rest.security
+ *

+ */ + @SearchParamDefinition(name="security", path="Conformance.rest.security", description="", type="token" ) + public static final String SP_SECURITY = "security"; + + /** + * Fluent Client search parameter constant for security + *

+ * Description:
+ * Type: token
+ * Path: Conformance.rest.security
+ *

+ */ + public static final TokenClientParam SECURITY = new TokenClientParam(SP_SECURITY); + + /** + * Search parameter constant for supported-profile + *

+ * Description:
+ * Type: reference
+ * Path: Conformance.profile
+ *

+ */ + @SearchParamDefinition(name="supported-profile", path="Conformance.profile", description="", type="reference" ) + public static final String SP_SUPPORTED_PROFILE = "supported-profile"; + + /** + * Fluent Client search parameter constant for supported-profile + *

+ * Description:
+ * Type: reference
+ * Path: Conformance.profile
+ *

+ */ + public static final ReferenceClientParam SUPPORTED_PROFILE = new ReferenceClientParam(SP_SUPPORTED_PROFILE); + + /** + * Constant for fluent queries to be used to add include statements. Specifies + * the path value of "Conformance.profile". + */ + public static final Include INCLUDE_PROFILE = new Include("Conformance.profile"); + + + @Child(name="identifier", type=StringDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Logical id to reference this statement", + formalDefinition="The identifier that is used to identify this conformance statement when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI)" + ) + private StringDt myIdentifier; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Logical id for this version of the statement", + formalDefinition="The identifier that is used to identify this version of the conformance statement when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp" + ) + private StringDt myVersion; + + @Child(name="name", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Informal name for this conformance statement", + formalDefinition="A free text natural language name identifying the conformance statement" + ) + private StringDt myName; + + @Child(name="publisher", type=StringDt.class, order=3, min=1, max=1) + @Description( + shortDefinition="Publishing Organization", + formalDefinition="Name of Organization publishing this conformance statement" + ) + private StringDt myPublisher; + + @Child(name="telecom", type=ContactDt.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Contacts for Organization", + formalDefinition="Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc." + ) + private java.util.List myTelecom; + + @Child(name="description", type=StringDt.class, order=5, min=0, max=1) + @Description( + shortDefinition="Human description of the conformance statement", + formalDefinition="A free text natural language description of the conformance statement and its use. Typically, this is used when the profile describes a desired rather than an actual solution, for example as a formal expression of requirements as part of an RFP" + ) + private StringDt myDescription; + + @Child(name="status", type=CodeDt.class, order=6, min=0, max=1) + @Description( + shortDefinition="draft | active | retired", + formalDefinition="The status of this conformance statement" + ) + private BoundCodeDt myStatus; + + @Child(name="experimental", type=BooleanDt.class, order=7, min=0, max=1) + @Description( + shortDefinition="If for testing purposes, not real usage", + formalDefinition="A flag to indicate that this conformance statement is authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage" + ) + private BooleanDt myExperimental; + + @Child(name="date", type=DateTimeDt.class, order=8, min=1, max=1) + @Description( + shortDefinition="Publication Date", + formalDefinition="The date when the conformance statement was published" + ) + private DateTimeDt myDate; + + @Child(name="software", order=9, min=0, max=1) + @Description( + shortDefinition="Software that is covered by this conformance statement", + formalDefinition="Software that is covered by this conformance statement. It is used when the profile describes the capabilities of a particular software version, independent of an installation." + ) + private Software mySoftware; + + @Child(name="implementation", order=10, min=0, max=1) + @Description( + shortDefinition="If this describes a specific instance", + formalDefinition="Identifies a specific implementation instance that is described by the conformance statement - i.e. a particular installation, rather than the capabilities of a software program" + ) + private Implementation myImplementation; + + @Child(name="fhirVersion", type=IdDt.class, order=11, min=1, max=1) + @Description( + shortDefinition="FHIR Version", + formalDefinition="The version of the FHIR specification on which this conformance statement is based" + ) + private IdDt myFhirVersion; + + @Child(name="acceptUnknown", type=BooleanDt.class, order=12, min=1, max=1) + @Description( + shortDefinition="True if application accepts unknown elements", + formalDefinition="A flag that indicates whether the application accepts unknown elements as part of a resource." + ) + private BooleanDt myAcceptUnknown; + + @Child(name="format", type=CodeDt.class, order=13, min=1, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="formats supported (xml | json | mime type)", + formalDefinition="A list of the formats supported by this implementation" + ) + private java.util.List myFormat; + + @Child(name="profile", order=14, min=0, max=Child.MAX_UNLIMITED, type={ + ca.uhn.fhir.model.dstu.resource.Profile.class }) + @Description( + shortDefinition="Profiles supported by the system", + formalDefinition="A list of profiles supported by the system. For a server, \"supported by the system\" means the system hosts/produces a set of recourses, conformant to a particular profile, and allows its clients to search using this profile and to find appropriate data. For a client, it means the system will search by this profile and process data according to the guidance implicit in the profile." + ) + private java.util.List myProfile; + + @Child(name="rest", order=15, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="If the endpoint is a RESTful one", + formalDefinition="A definition of the restful capabilities of the solution, if any" + ) + private java.util.List myRest; + + @Child(name="messaging", order=16, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="If messaging is supported", + formalDefinition="A description of the messaging capabilities of the solution" + ) + private java.util.List myMessaging; + + @Child(name="document", order=17, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Document definition", + formalDefinition="A document definition" + ) + private java.util.List myDocument; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myIdentifier, myVersion, myName, myPublisher, myTelecom, myDescription, myStatus, myExperimental, myDate, mySoftware, myImplementation, myFhirVersion, myAcceptUnknown, myFormat, myProfile, myRest, myMessaging, myDocument); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myIdentifier, myVersion, myName, myPublisher, myTelecom, myDescription, myStatus, myExperimental, myDate, mySoftware, myImplementation, myFhirVersion, myAcceptUnknown, myFormat, myProfile, myRest, myMessaging, myDocument); + } + + /** + * Gets the value(s) for identifier (Logical id to reference this statement). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identifier that is used to identify this conformance statement when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public StringDt getIdentifier() { + if (myIdentifier == null) { + myIdentifier = new StringDt(); + } + return myIdentifier; + } + + /** + * Sets the value(s) for identifier (Logical id to reference this statement) + * + *

+ * Definition: + * The identifier that is used to identify this conformance statement when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public Conformance setIdentifier(StringDt theValue) { + myIdentifier = theValue; + return this; + } + + /** + * Sets the value for identifier (Logical id to reference this statement) + * + *

+ * Definition: + * The identifier that is used to identify this conformance statement when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public Conformance setIdentifier( String theString) { + myIdentifier = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for version (Logical id for this version of the statement). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identifier that is used to identify this version of the conformance statement when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public StringDt getVersion() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + /** + * Sets the value(s) for version (Logical id for this version of the statement) + * + *

+ * Definition: + * The identifier that is used to identify this version of the conformance statement when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public Conformance setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + /** + * Sets the value for version (Logical id for this version of the statement) + * + *

+ * Definition: + * The identifier that is used to identify this version of the conformance statement when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public Conformance setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for name (Informal name for this conformance statement). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A free text natural language name identifying the conformance statement + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Informal name for this conformance statement) + * + *

+ * Definition: + * A free text natural language name identifying the conformance statement + *

+ */ + public Conformance setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Informal name for this conformance statement) + * + *

+ * Definition: + * A free text natural language name identifying the conformance statement + *

+ */ + public Conformance setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for publisher (Publishing Organization). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Name of Organization publishing this conformance statement + *

+ */ + public StringDt getPublisherElement() { + if (myPublisher == null) { + myPublisher = new StringDt(); + } + return myPublisher; + } + + /** + * Sets the value(s) for publisher (Publishing Organization) + * + *

+ * Definition: + * Name of Organization publishing this conformance statement + *

+ */ + public Conformance setPublisher(StringDt theValue) { + myPublisher = theValue; + return this; + } + + /** + * Sets the value for publisher (Publishing Organization) + * + *

+ * Definition: + * Name of Organization publishing this conformance statement + *

+ */ + public Conformance setPublisher( String theString) { + myPublisher = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for telecom (Contacts for Organization). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc. + *

+ */ + public java.util.List getTelecom() { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + return myTelecom; + } + + /** + * Sets the value(s) for telecom (Contacts for Organization) + * + *

+ * Definition: + * Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc. + *

+ */ + public Conformance setTelecom(java.util.List theValue) { + myTelecom = theValue; + return this; + } + + /** + * Adds and returns a new value for telecom (Contacts for Organization) + * + *

+ * Definition: + * Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc. + *

+ */ + public ContactDt addTelecom() { + ContactDt newType = new ContactDt(); + getTelecom().add(newType); + return newType; + } + + /** + * Gets the first repetition for telecom (Contacts for Organization), + * creating it if it does not already exist. + * + *

+ * Definition: + * Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc. + *

+ */ + public ContactDt getTelecomFirstRep() { + if (getTelecom().isEmpty()) { + return addTelecom(); + } + return getTelecom().get(0); + } + /** + * Adds a new value for telecom (Contacts for Organization) + * + *

+ * Definition: + * Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc. + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public Conformance addTelecom( ContactUseEnum theContactUse, String theValue) { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + myTelecom.add(new ContactDt(theContactUse, theValue)); + return this; + } + + /** + * Adds a new value for telecom (Contacts for Organization) + * + *

+ * Definition: + * Contacts for Organization relevant to this conformance statement. The contacts may be a website, email, phone numbers, etc. + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public Conformance addTelecom( String theValue) { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + myTelecom.add(new ContactDt(theValue)); + return this; + } + + + /** + * Gets the value(s) for description (Human description of the conformance statement). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A free text natural language description of the conformance statement and its use. Typically, this is used when the profile describes a desired rather than an actual solution, for example as a formal expression of requirements as part of an RFP + *

+ */ + public StringDt getDescriptionElement() { + if (myDescription == null) { + myDescription = new StringDt(); + } + return myDescription; + } + + /** + * Sets the value(s) for description (Human description of the conformance statement) + * + *

+ * Definition: + * A free text natural language description of the conformance statement and its use. Typically, this is used when the profile describes a desired rather than an actual solution, for example as a formal expression of requirements as part of an RFP + *

+ */ + public Conformance setDescription(StringDt theValue) { + myDescription = theValue; + return this; + } + + /** + * Sets the value for description (Human description of the conformance statement) + * + *

+ * Definition: + * A free text natural language description of the conformance statement and its use. Typically, this is used when the profile describes a desired rather than an actual solution, for example as a formal expression of requirements as part of an RFP + *

+ */ + public Conformance setDescription( String theString) { + myDescription = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for status (draft | active | retired). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The status of this conformance statement + *

+ */ + public BoundCodeDt getStatus() { + if (myStatus == null) { + myStatus = new BoundCodeDt(ConformanceStatementStatusEnum.VALUESET_BINDER); + } + return myStatus; + } + + /** + * Sets the value(s) for status (draft | active | retired) + * + *

+ * Definition: + * The status of this conformance statement + *

+ */ + public Conformance setStatus(BoundCodeDt theValue) { + myStatus = theValue; + return this; + } + + /** + * Sets the value(s) for status (draft | active | retired) + * + *

+ * Definition: + * The status of this conformance statement + *

+ */ + public Conformance setStatus(ConformanceStatementStatusEnum theValue) { + getStatus().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for experimental (If for testing purposes, not real usage). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A flag to indicate that this conformance statement is authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public BooleanDt getExperimental() { + if (myExperimental == null) { + myExperimental = new BooleanDt(); + } + return myExperimental; + } + + /** + * Sets the value(s) for experimental (If for testing purposes, not real usage) + * + *

+ * Definition: + * A flag to indicate that this conformance statement is authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public Conformance setExperimental(BooleanDt theValue) { + myExperimental = theValue; + return this; + } + + /** + * Sets the value for experimental (If for testing purposes, not real usage) + * + *

+ * Definition: + * A flag to indicate that this conformance statement is authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public Conformance setExperimental( boolean theBoolean) { + myExperimental = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for date (Publication Date). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The date when the conformance statement was published + *

+ */ + public DateTimeDt getDate() { + if (myDate == null) { + myDate = new DateTimeDt(); + } + return myDate; + } + + /** + * Sets the value(s) for date (Publication Date) + * + *

+ * Definition: + * The date when the conformance statement was published + *

+ */ + public Conformance setDate(DateTimeDt theValue) { + myDate = theValue; + return this; + } + + /** + * Sets the value for date (Publication Date) + * + *

+ * Definition: + * The date when the conformance statement was published + *

+ */ + public Conformance setDateWithSecondsPrecision( Date theDate) { + myDate = new DateTimeDt(theDate); + return this; + } + + /** + * Sets the value for date (Publication Date) + * + *

+ * Definition: + * The date when the conformance statement was published + *

+ */ + public Conformance setDate( Date theDate, TemporalPrecisionEnum thePrecision) { + myDate = new DateTimeDt(theDate, thePrecision); + return this; + } + + + /** + * Gets the value(s) for software (Software that is covered by this conformance statement). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Software that is covered by this conformance statement. It is used when the profile describes the capabilities of a particular software version, independent of an installation. + *

+ */ + public Software getSoftware() { + if (mySoftware == null) { + mySoftware = new Software(); + } + return mySoftware; + } + + /** + * Sets the value(s) for software (Software that is covered by this conformance statement) + * + *

+ * Definition: + * Software that is covered by this conformance statement. It is used when the profile describes the capabilities of a particular software version, independent of an installation. + *

+ */ + public Conformance setSoftware(Software theValue) { + mySoftware = theValue; + return this; + } + + + /** + * Gets the value(s) for implementation (If this describes a specific instance). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies a specific implementation instance that is described by the conformance statement - i.e. a particular installation, rather than the capabilities of a software program + *

+ */ + public Implementation getImplementation() { + if (myImplementation == null) { + myImplementation = new Implementation(); + } + return myImplementation; + } + + /** + * Sets the value(s) for implementation (If this describes a specific instance) + * + *

+ * Definition: + * Identifies a specific implementation instance that is described by the conformance statement - i.e. a particular installation, rather than the capabilities of a software program + *

+ */ + public Conformance setImplementation(Implementation theValue) { + myImplementation = theValue; + return this; + } + + + /** + * Gets the value(s) for fhirVersion (FHIR Version). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version of the FHIR specification on which this conformance statement is based + *

+ */ + public IdDt getFhirVersion() { + if (myFhirVersion == null) { + myFhirVersion = new IdDt(); + } + return myFhirVersion; + } + + /** + * Sets the value(s) for fhirVersion (FHIR Version) + * + *

+ * Definition: + * The version of the FHIR specification on which this conformance statement is based + *

+ */ + public Conformance setFhirVersion(IdDt theValue) { + myFhirVersion = theValue; + return this; + } + + /** + * Sets the value for fhirVersion (FHIR Version) + * + *

+ * Definition: + * The version of the FHIR specification on which this conformance statement is based + *

+ */ + public Conformance setFhirVersion( String theId) { + myFhirVersion = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for acceptUnknown (True if application accepts unknown elements). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A flag that indicates whether the application accepts unknown elements as part of a resource. + *

+ */ + public BooleanDt getAcceptUnknown() { + if (myAcceptUnknown == null) { + myAcceptUnknown = new BooleanDt(); + } + return myAcceptUnknown; + } + + /** + * Sets the value(s) for acceptUnknown (True if application accepts unknown elements) + * + *

+ * Definition: + * A flag that indicates whether the application accepts unknown elements as part of a resource. + *

+ */ + public Conformance setAcceptUnknown(BooleanDt theValue) { + myAcceptUnknown = theValue; + return this; + } + + /** + * Sets the value for acceptUnknown (True if application accepts unknown elements) + * + *

+ * Definition: + * A flag that indicates whether the application accepts unknown elements as part of a resource. + *

+ */ + public Conformance setAcceptUnknown( boolean theBoolean) { + myAcceptUnknown = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for format (formats supported (xml | json | mime type)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A list of the formats supported by this implementation + *

+ */ + public java.util.List getFormat() { + if (myFormat == null) { + myFormat = new java.util.ArrayList(); + } + return myFormat; + } + + /** + * Sets the value(s) for format (formats supported (xml | json | mime type)) + * + *

+ * Definition: + * A list of the formats supported by this implementation + *

+ */ + public Conformance setFormat(java.util.List theValue) { + myFormat = theValue; + return this; + } + + /** + * Adds and returns a new value for format (formats supported (xml | json | mime type)) + * + *

+ * Definition: + * A list of the formats supported by this implementation + *

+ */ + public CodeDt addFormat() { + CodeDt newType = new CodeDt(); + getFormat().add(newType); + return newType; + } + + /** + * Gets the first repetition for format (formats supported (xml | json | mime type)), + * creating it if it does not already exist. + * + *

+ * Definition: + * A list of the formats supported by this implementation + *

+ */ + public CodeDt getFormatFirstRep() { + if (getFormat().isEmpty()) { + return addFormat(); + } + return getFormat().get(0); + } + /** + * Adds a new value for format (formats supported (xml | json | mime type)) + * + *

+ * Definition: + * A list of the formats supported by this implementation + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public Conformance addFormat( String theCode) { + if (myFormat == null) { + myFormat = new java.util.ArrayList(); + } + myFormat.add(new CodeDt(theCode)); + return this; + } + + + /** + * Gets the value(s) for profile (Profiles supported by the system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A list of profiles supported by the system. For a server, \"supported by the system\" means the system hosts/produces a set of recourses, conformant to a particular profile, and allows its clients to search using this profile and to find appropriate data. For a client, it means the system will search by this profile and process data according to the guidance implicit in the profile. + *

+ */ + public java.util.List getProfile() { + if (myProfile == null) { + myProfile = new java.util.ArrayList(); + } + return myProfile; + } + + /** + * Sets the value(s) for profile (Profiles supported by the system) + * + *

+ * Definition: + * A list of profiles supported by the system. For a server, \"supported by the system\" means the system hosts/produces a set of recourses, conformant to a particular profile, and allows its clients to search using this profile and to find appropriate data. For a client, it means the system will search by this profile and process data according to the guidance implicit in the profile. + *

+ */ + public Conformance setProfile(java.util.List theValue) { + myProfile = theValue; + return this; + } + + /** + * Adds and returns a new value for profile (Profiles supported by the system) + * + *

+ * Definition: + * A list of profiles supported by the system. For a server, \"supported by the system\" means the system hosts/produces a set of recourses, conformant to a particular profile, and allows its clients to search using this profile and to find appropriate data. For a client, it means the system will search by this profile and process data according to the guidance implicit in the profile. + *

+ */ + public ResourceReferenceDt addProfile() { + ResourceReferenceDt newType = new ResourceReferenceDt(); + getProfile().add(newType); + return newType; + } + + /** + * Gets the value(s) for rest (If the endpoint is a RESTful one). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A definition of the restful capabilities of the solution, if any + *

+ */ + public java.util.List getRest() { + if (myRest == null) { + myRest = new java.util.ArrayList(); + } + return myRest; + } + + /** + * Sets the value(s) for rest (If the endpoint is a RESTful one) + * + *

+ * Definition: + * A definition of the restful capabilities of the solution, if any + *

+ */ + public Conformance setRest(java.util.List theValue) { + myRest = theValue; + return this; + } + + /** + * Adds and returns a new value for rest (If the endpoint is a RESTful one) + * + *

+ * Definition: + * A definition of the restful capabilities of the solution, if any + *

+ */ + public Rest addRest() { + Rest newType = new Rest(); + getRest().add(newType); + return newType; + } + + /** + * Gets the first repetition for rest (If the endpoint is a RESTful one), + * creating it if it does not already exist. + * + *

+ * Definition: + * A definition of the restful capabilities of the solution, if any + *

+ */ + public Rest getRestFirstRep() { + if (getRest().isEmpty()) { + return addRest(); + } + return getRest().get(0); + } + + /** + * Gets the value(s) for messaging (If messaging is supported). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A description of the messaging capabilities of the solution + *

+ */ + public java.util.List getMessaging() { + if (myMessaging == null) { + myMessaging = new java.util.ArrayList(); + } + return myMessaging; + } + + /** + * Sets the value(s) for messaging (If messaging is supported) + * + *

+ * Definition: + * A description of the messaging capabilities of the solution + *

+ */ + public Conformance setMessaging(java.util.List theValue) { + myMessaging = theValue; + return this; + } + + /** + * Adds and returns a new value for messaging (If messaging is supported) + * + *

+ * Definition: + * A description of the messaging capabilities of the solution + *

+ */ + public Messaging addMessaging() { + Messaging newType = new Messaging(); + getMessaging().add(newType); + return newType; + } + + /** + * Gets the first repetition for messaging (If messaging is supported), + * creating it if it does not already exist. + * + *

+ * Definition: + * A description of the messaging capabilities of the solution + *

+ */ + public Messaging getMessagingFirstRep() { + if (getMessaging().isEmpty()) { + return addMessaging(); + } + return getMessaging().get(0); + } + + /** + * Gets the value(s) for document (Document definition). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A document definition + *

+ */ + public java.util.List getDocument() { + if (myDocument == null) { + myDocument = new java.util.ArrayList(); + } + return myDocument; + } + + /** + * Sets the value(s) for document (Document definition) + * + *

+ * Definition: + * A document definition + *

+ */ + public Conformance setDocument(java.util.List theValue) { + myDocument = theValue; + return this; + } + + /** + * Adds and returns a new value for document (Document definition) + * + *

+ * Definition: + * A document definition + *

+ */ + public Document addDocument() { + Document newType = new Document(); + getDocument().add(newType); + return newType; + } + + /** + * Gets the first repetition for document (Document definition), + * creating it if it does not already exist. + * + *

+ * Definition: + * A document definition + *

+ */ + public Document getDocumentFirstRep() { + if (getDocument().isEmpty()) { + return addDocument(); + } + return getDocument().get(0); + } + + /** + * Block class for child element: Conformance.software (Software that is covered by this conformance statement) + * + *

+ * Definition: + * Software that is covered by this conformance statement. It is used when the profile describes the capabilities of a particular software version, independent of an installation. + *

+ */ + @Block() + public static class Software extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="name", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="A name the software is known by", + formalDefinition="Name software is known by" + ) + private StringDt myName; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Version covered by this statement", + formalDefinition="The version identifier for the software covered by this statement" + ) + private StringDt myVersion; + + @Child(name="releaseDate", type=DateTimeDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Date this version released", + formalDefinition="Date this version of the software released" + ) + private DateTimeDt myReleaseDate; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myName, myVersion, myReleaseDate); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myName, myVersion, myReleaseDate); + } + + /** + * Gets the value(s) for name (A name the software is known by). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Name software is known by + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (A name the software is known by) + * + *

+ * Definition: + * Name software is known by + *

+ */ + public Software setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (A name the software is known by) + * + *

+ * Definition: + * Name software is known by + *

+ */ + public Software setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for version (Version covered by this statement). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version identifier for the software covered by this statement + *

+ */ + public StringDt getVersion() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + /** + * Sets the value(s) for version (Version covered by this statement) + * + *

+ * Definition: + * The version identifier for the software covered by this statement + *

+ */ + public Software setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + /** + * Sets the value for version (Version covered by this statement) + * + *

+ * Definition: + * The version identifier for the software covered by this statement + *

+ */ + public Software setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for releaseDate (Date this version released). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Date this version of the software released + *

+ */ + public DateTimeDt getReleaseDate() { + if (myReleaseDate == null) { + myReleaseDate = new DateTimeDt(); + } + return myReleaseDate; + } + + /** + * Sets the value(s) for releaseDate (Date this version released) + * + *

+ * Definition: + * Date this version of the software released + *

+ */ + public Software setReleaseDate(DateTimeDt theValue) { + myReleaseDate = theValue; + return this; + } + + /** + * Sets the value for releaseDate (Date this version released) + * + *

+ * Definition: + * Date this version of the software released + *

+ */ + public Software setReleaseDateWithSecondsPrecision( Date theDate) { + myReleaseDate = new DateTimeDt(theDate); + return this; + } + + /** + * Sets the value for releaseDate (Date this version released) + * + *

+ * Definition: + * Date this version of the software released + *

+ */ + public Software setReleaseDate( Date theDate, TemporalPrecisionEnum thePrecision) { + myReleaseDate = new DateTimeDt(theDate, thePrecision); + return this; + } + + + + } + + + /** + * Block class for child element: Conformance.implementation (If this describes a specific instance) + * + *

+ * Definition: + * Identifies a specific implementation instance that is described by the conformance statement - i.e. a particular installation, rather than the capabilities of a software program + *

+ */ + @Block() + public static class Implementation extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="description", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Describes this specific instance", + formalDefinition="Information about the specific installation that this conformance statement relates to" + ) + private StringDt myDescription; + + @Child(name="url", type=UriDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Base URL for the installation", + formalDefinition="A base URL for the implementation. This forms the base for REST interfaces as well as the mailbox and document interfaces." + ) + private UriDt myUrl; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myDescription, myUrl); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myDescription, myUrl); + } + + /** + * Gets the value(s) for description (Describes this specific instance). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Information about the specific installation that this conformance statement relates to + *

+ */ + public StringDt getDescription() { + if (myDescription == null) { + myDescription = new StringDt(); + } + return myDescription; + } + + /** + * Sets the value(s) for description (Describes this specific instance) + * + *

+ * Definition: + * Information about the specific installation that this conformance statement relates to + *

+ */ + public Implementation setDescription(StringDt theValue) { + myDescription = theValue; + return this; + } + + /** + * Sets the value for description (Describes this specific instance) + * + *

+ * Definition: + * Information about the specific installation that this conformance statement relates to + *

+ */ + public Implementation setDescription( String theString) { + myDescription = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for url (Base URL for the installation). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A base URL for the implementation. This forms the base for REST interfaces as well as the mailbox and document interfaces. + *

+ */ + public UriDt getUrl() { + if (myUrl == null) { + myUrl = new UriDt(); + } + return myUrl; + } + + /** + * Sets the value(s) for url (Base URL for the installation) + * + *

+ * Definition: + * A base URL for the implementation. This forms the base for REST interfaces as well as the mailbox and document interfaces. + *

+ */ + public Implementation setUrl(UriDt theValue) { + myUrl = theValue; + return this; + } + + /** + * Sets the value for url (Base URL for the installation) + * + *

+ * Definition: + * A base URL for the implementation. This forms the base for REST interfaces as well as the mailbox and document interfaces. + *

+ */ + public Implementation setUrl( String theUri) { + myUrl = new UriDt(theUri); + return this; + } + + + + } + + + /** + * Block class for child element: Conformance.rest (If the endpoint is a RESTful one) + * + *

+ * Definition: + * A definition of the restful capabilities of the solution, if any + *

+ */ + @Block() + public static class Rest extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="mode", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="client | server", + formalDefinition="Identifies whether this portion of the statement is describing ability to initiate or receive restful operations" + ) + private BoundCodeDt myMode; + + @Child(name="documentation", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="General description of implementation", + formalDefinition="Information about the system's restful capabilities that apply across all applications, such as security" + ) + private StringDt myDocumentation; + + @Child(name="security", order=2, min=0, max=1) + @Description( + shortDefinition="Information about security of implementation", + formalDefinition="Information about security of implementation" + ) + private RestSecurity mySecurity; + + @Child(name="resource", order=3, min=1, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Resource served on the REST interface", + formalDefinition="A specification of the restful capabilities of the solution for a specific resource type" + ) + private java.util.List myResource; + + @Child(name="operation", order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="What operations are supported?", + formalDefinition="A specification of restful operations supported by the system" + ) + private java.util.List myOperation; + + @Child(name="query", order=5, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Definition of a named query", + formalDefinition="Definition of a named query and its parameters and their meaning" + ) + private java.util.List myQuery; + + @Child(name="documentMailbox", type=UriDt.class, order=6, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="How documents are accepted in /Mailbox", + formalDefinition="A list of profiles that this server implements for accepting documents in the mailbox. If this list is empty, then documents are not accepted. The base specification has the profile identifier \"http://hl7.org/fhir/documents/mailbox\". Other specifications can declare their own identifier for this purpose" + ) + private java.util.List myDocumentMailbox; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myMode, myDocumentation, mySecurity, myResource, myOperation, myQuery, myDocumentMailbox); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myMode, myDocumentation, mySecurity, myResource, myOperation, myQuery, myDocumentMailbox); + } + + /** + * Gets the value(s) for mode (client | server). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies whether this portion of the statement is describing ability to initiate or receive restful operations + *

+ */ + public BoundCodeDt getMode() { + if (myMode == null) { + myMode = new BoundCodeDt(RestfulConformanceModeEnum.VALUESET_BINDER); + } + return myMode; + } + + /** + * Sets the value(s) for mode (client | server) + * + *

+ * Definition: + * Identifies whether this portion of the statement is describing ability to initiate or receive restful operations + *

+ */ + public Rest setMode(BoundCodeDt theValue) { + myMode = theValue; + return this; + } + + /** + * Sets the value(s) for mode (client | server) + * + *

+ * Definition: + * Identifies whether this portion of the statement is describing ability to initiate or receive restful operations + *

+ */ + public Rest setMode(RestfulConformanceModeEnum theValue) { + getMode().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for documentation (General description of implementation). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Information about the system's restful capabilities that apply across all applications, such as security + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (General description of implementation) + * + *

+ * Definition: + * Information about the system's restful capabilities that apply across all applications, such as security + *

+ */ + public Rest setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (General description of implementation) + * + *

+ * Definition: + * Information about the system's restful capabilities that apply across all applications, such as security + *

+ */ + public Rest setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for security (Information about security of implementation). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Information about security of implementation + *

+ */ + public RestSecurity getSecurity() { + if (mySecurity == null) { + mySecurity = new RestSecurity(); + } + return mySecurity; + } + + /** + * Sets the value(s) for security (Information about security of implementation) + * + *

+ * Definition: + * Information about security of implementation + *

+ */ + public Rest setSecurity(RestSecurity theValue) { + mySecurity = theValue; + return this; + } + + + /** + * Gets the value(s) for resource (Resource served on the REST interface). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A specification of the restful capabilities of the solution for a specific resource type + *

+ */ + public java.util.List getResource() { + if (myResource == null) { + myResource = new java.util.ArrayList(); + } + return myResource; + } + + /** + * Sets the value(s) for resource (Resource served on the REST interface) + * + *

+ * Definition: + * A specification of the restful capabilities of the solution for a specific resource type + *

+ */ + public Rest setResource(java.util.List theValue) { + myResource = theValue; + return this; + } + + /** + * Adds and returns a new value for resource (Resource served on the REST interface) + * + *

+ * Definition: + * A specification of the restful capabilities of the solution for a specific resource type + *

+ */ + public RestResource addResource() { + RestResource newType = new RestResource(); + getResource().add(newType); + return newType; + } + + /** + * Gets the first repetition for resource (Resource served on the REST interface), + * creating it if it does not already exist. + * + *

+ * Definition: + * A specification of the restful capabilities of the solution for a specific resource type + *

+ */ + public RestResource getResourceFirstRep() { + if (getResource().isEmpty()) { + return addResource(); + } + return getResource().get(0); + } + + /** + * Gets the value(s) for operation (What operations are supported?). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A specification of restful operations supported by the system + *

+ */ + public java.util.List getOperation() { + if (myOperation == null) { + myOperation = new java.util.ArrayList(); + } + return myOperation; + } + + /** + * Sets the value(s) for operation (What operations are supported?) + * + *

+ * Definition: + * A specification of restful operations supported by the system + *

+ */ + public Rest setOperation(java.util.List theValue) { + myOperation = theValue; + return this; + } + + /** + * Adds and returns a new value for operation (What operations are supported?) + * + *

+ * Definition: + * A specification of restful operations supported by the system + *

+ */ + public RestOperation addOperation() { + RestOperation newType = new RestOperation(); + getOperation().add(newType); + return newType; + } + + /** + * Gets the first repetition for operation (What operations are supported?), + * creating it if it does not already exist. + * + *

+ * Definition: + * A specification of restful operations supported by the system + *

+ */ + public RestOperation getOperationFirstRep() { + if (getOperation().isEmpty()) { + return addOperation(); + } + return getOperation().get(0); + } + + /** + * Gets the value(s) for query (Definition of a named query). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public java.util.List getQuery() { + if (myQuery == null) { + myQuery = new java.util.ArrayList(); + } + return myQuery; + } + + /** + * Sets the value(s) for query (Definition of a named query) + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public Rest setQuery(java.util.List theValue) { + myQuery = theValue; + return this; + } + + /** + * Adds and returns a new value for query (Definition of a named query) + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public RestQuery addQuery() { + RestQuery newType = new RestQuery(); + getQuery().add(newType); + return newType; + } + + /** + * Gets the first repetition for query (Definition of a named query), + * creating it if it does not already exist. + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public RestQuery getQueryFirstRep() { + if (getQuery().isEmpty()) { + return addQuery(); + } + return getQuery().get(0); + } + + /** + * Gets the value(s) for documentMailbox (How documents are accepted in /Mailbox). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A list of profiles that this server implements for accepting documents in the mailbox. If this list is empty, then documents are not accepted. The base specification has the profile identifier \"http://hl7.org/fhir/documents/mailbox\". Other specifications can declare their own identifier for this purpose + *

+ */ + public java.util.List getDocumentMailbox() { + if (myDocumentMailbox == null) { + myDocumentMailbox = new java.util.ArrayList(); + } + return myDocumentMailbox; + } + + /** + * Sets the value(s) for documentMailbox (How documents are accepted in /Mailbox) + * + *

+ * Definition: + * A list of profiles that this server implements for accepting documents in the mailbox. If this list is empty, then documents are not accepted. The base specification has the profile identifier \"http://hl7.org/fhir/documents/mailbox\". Other specifications can declare their own identifier for this purpose + *

+ */ + public Rest setDocumentMailbox(java.util.List theValue) { + myDocumentMailbox = theValue; + return this; + } + + /** + * Adds and returns a new value for documentMailbox (How documents are accepted in /Mailbox) + * + *

+ * Definition: + * A list of profiles that this server implements for accepting documents in the mailbox. If this list is empty, then documents are not accepted. The base specification has the profile identifier \"http://hl7.org/fhir/documents/mailbox\". Other specifications can declare their own identifier for this purpose + *

+ */ + public UriDt addDocumentMailbox() { + UriDt newType = new UriDt(); + getDocumentMailbox().add(newType); + return newType; + } + + /** + * Gets the first repetition for documentMailbox (How documents are accepted in /Mailbox), + * creating it if it does not already exist. + * + *

+ * Definition: + * A list of profiles that this server implements for accepting documents in the mailbox. If this list is empty, then documents are not accepted. The base specification has the profile identifier \"http://hl7.org/fhir/documents/mailbox\". Other specifications can declare their own identifier for this purpose + *

+ */ + public UriDt getDocumentMailboxFirstRep() { + if (getDocumentMailbox().isEmpty()) { + return addDocumentMailbox(); + } + return getDocumentMailbox().get(0); + } + /** + * Adds a new value for documentMailbox (How documents are accepted in /Mailbox) + * + *

+ * Definition: + * A list of profiles that this server implements for accepting documents in the mailbox. If this list is empty, then documents are not accepted. The base specification has the profile identifier \"http://hl7.org/fhir/documents/mailbox\". Other specifications can declare their own identifier for this purpose + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public Rest addDocumentMailbox( String theUri) { + if (myDocumentMailbox == null) { + myDocumentMailbox = new java.util.ArrayList(); + } + myDocumentMailbox.add(new UriDt(theUri)); + return this; + } + + + + } + + /** + * Block class for child element: Conformance.rest.security (Information about security of implementation) + * + *

+ * Definition: + * Information about security of implementation + *

+ */ + @Block() + public static class RestSecurity extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="cors", type=BooleanDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Adds CORS Headers (http://enable-cors.org/)", + formalDefinition="Server adds CORS headers when responding to requests - this enables javascript applications to yuse the server" + ) + private BooleanDt myCors; + + @Child(name="service", type=CodeableConceptDt.class, order=1, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="OAuth | OAuth2 | NTLM | Basic | Kerberos", + formalDefinition="Types of security services are supported/required by the system" + ) + private java.util.List> myService; + + @Child(name="description", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="General description of how security works", + formalDefinition="General description of how security works" + ) + private StringDt myDescription; + + @Child(name="certificate", order=3, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Certificates associated with security profiles", + formalDefinition="Certificates associated with security profiles" + ) + private java.util.List myCertificate; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCors, myService, myDescription, myCertificate); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCors, myService, myDescription, myCertificate); + } + + /** + * Gets the value(s) for cors (Adds CORS Headers (http://enable-cors.org/)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Server adds CORS headers when responding to requests - this enables javascript applications to yuse the server + *

+ */ + public BooleanDt getCors() { + if (myCors == null) { + myCors = new BooleanDt(); + } + return myCors; + } + + /** + * Sets the value(s) for cors (Adds CORS Headers (http://enable-cors.org/)) + * + *

+ * Definition: + * Server adds CORS headers when responding to requests - this enables javascript applications to yuse the server + *

+ */ + public RestSecurity setCors(BooleanDt theValue) { + myCors = theValue; + return this; + } + + /** + * Sets the value for cors (Adds CORS Headers (http://enable-cors.org/)) + * + *

+ * Definition: + * Server adds CORS headers when responding to requests - this enables javascript applications to yuse the server + *

+ */ + public RestSecurity setCors( boolean theBoolean) { + myCors = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for service (OAuth | OAuth2 | NTLM | Basic | Kerberos). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Types of security services are supported/required by the system + *

+ */ + public java.util.List> getService() { + if (myService == null) { + myService = new java.util.ArrayList>(); + } + return myService; + } + + /** + * Sets the value(s) for service (OAuth | OAuth2 | NTLM | Basic | Kerberos) + * + *

+ * Definition: + * Types of security services are supported/required by the system + *

+ */ + public RestSecurity setService(java.util.List> theValue) { + myService = theValue; + return this; + } + + /** + * Add a value for service (OAuth | OAuth2 | NTLM | Basic | Kerberos) using an enumerated type. This + * is intended as a convenience method for situations where the FHIR defined ValueSets are mandatory + * or contain the desirable codes. If you wish to use codes other than those which are built-in, + * you may also use the {@link #addType()} method. + * + *

+ * Definition: + * Types of security services are supported/required by the system + *

+ */ + public BoundCodeableConceptDt_ addService(RestfulSecurityServiceEnum theValue) { + BoundCodeableConceptDt_ retVal = new BoundCodeableConceptDt_(RestfulSecurityServiceEnum.VALUESET_BINDER, theValue); + getService().add(retVal); + return retVal; + } + + /** + * Gets the first repetition for service (OAuth | OAuth2 | NTLM | Basic | Kerberos), + * creating it if it does not already exist. + * + *

+ * Definition: + * Types of security services are supported/required by the system + *

+ */ + public BoundCodeableConceptDt_ getServiceFirstRep() { + if (getService().size() == 0) { + addService(); + } + return getService().get(0); + } + + /** + * Add a value for service (OAuth | OAuth2 | NTLM | Basic | Kerberos) + * + *

+ * Definition: + * Types of security services are supported/required by the system + *

+ */ + public BoundCodeableConceptDt_ addService() { + BoundCodeableConceptDt_ retVal = new BoundCodeableConceptDt_(RestfulSecurityServiceEnum.VALUESET_BINDER); + getService().add(retVal); + return retVal; + } + + /** + * Sets the value(s), and clears any existing value(s) for service (OAuth | OAuth2 | NTLM | Basic | Kerberos) + * + *

+ * Definition: + * Types of security services are supported/required by the system + *

+ */ + public RestSecurity setService(RestfulSecurityServiceEnum theValue) { + getService().clear(); + addService(theValue); + return this; + } + + + /** + * Gets the value(s) for description (General description of how security works). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * General description of how security works + *

+ */ + public StringDt getDescription() { + if (myDescription == null) { + myDescription = new StringDt(); + } + return myDescription; + } + + /** + * Sets the value(s) for description (General description of how security works) + * + *

+ * Definition: + * General description of how security works + *

+ */ + public RestSecurity setDescription(StringDt theValue) { + myDescription = theValue; + return this; + } + + /** + * Sets the value for description (General description of how security works) + * + *

+ * Definition: + * General description of how security works + *

+ */ + public RestSecurity setDescription( String theString) { + myDescription = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for certificate (Certificates associated with security profiles). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Certificates associated with security profiles + *

+ */ + public java.util.List getCertificate() { + if (myCertificate == null) { + myCertificate = new java.util.ArrayList(); + } + return myCertificate; + } + + /** + * Sets the value(s) for certificate (Certificates associated with security profiles) + * + *

+ * Definition: + * Certificates associated with security profiles + *

+ */ + public RestSecurity setCertificate(java.util.List theValue) { + myCertificate = theValue; + return this; + } + + /** + * Adds and returns a new value for certificate (Certificates associated with security profiles) + * + *

+ * Definition: + * Certificates associated with security profiles + *

+ */ + public RestSecurityCertificate addCertificate() { + RestSecurityCertificate newType = new RestSecurityCertificate(); + getCertificate().add(newType); + return newType; + } + + /** + * Gets the first repetition for certificate (Certificates associated with security profiles), + * creating it if it does not already exist. + * + *

+ * Definition: + * Certificates associated with security profiles + *

+ */ + public RestSecurityCertificate getCertificateFirstRep() { + if (getCertificate().isEmpty()) { + return addCertificate(); + } + return getCertificate().get(0); + } + + + } + + /** + * Block class for child element: Conformance.rest.security.certificate (Certificates associated with security profiles) + * + *

+ * Definition: + * Certificates associated with security profiles + *

+ */ + @Block() + public static class RestSecurityCertificate extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="type", type=CodeDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Mime type for certificate", + formalDefinition="Mime type for certificate" + ) + private CodeDt myType; + + @Child(name="blob", type=Base64BinaryDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Actual certificate", + formalDefinition="Actual certificate" + ) + private Base64BinaryDt myBlob; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myType, myBlob); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myType, myBlob); + } + + /** + * Gets the value(s) for type (Mime type for certificate). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Mime type for certificate + *

+ */ + public CodeDt getType() { + if (myType == null) { + myType = new CodeDt(); + } + return myType; + } + + /** + * Sets the value(s) for type (Mime type for certificate) + * + *

+ * Definition: + * Mime type for certificate + *

+ */ + public RestSecurityCertificate setType(CodeDt theValue) { + myType = theValue; + return this; + } + + /** + * Sets the value for type (Mime type for certificate) + * + *

+ * Definition: + * Mime type for certificate + *

+ */ + public RestSecurityCertificate setType( String theCode) { + myType = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for blob (Actual certificate). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Actual certificate + *

+ */ + public Base64BinaryDt getBlob() { + if (myBlob == null) { + myBlob = new Base64BinaryDt(); + } + return myBlob; + } + + /** + * Sets the value(s) for blob (Actual certificate) + * + *

+ * Definition: + * Actual certificate + *

+ */ + public RestSecurityCertificate setBlob(Base64BinaryDt theValue) { + myBlob = theValue; + return this; + } + + /** + * Sets the value for blob (Actual certificate) + * + *

+ * Definition: + * Actual certificate + *

+ */ + public RestSecurityCertificate setBlob( byte[] theBytes) { + myBlob = new Base64BinaryDt(theBytes); + return this; + } + + + + } + + + + /** + * Block class for child element: Conformance.rest.resource (Resource served on the REST interface) + * + *

+ * Definition: + * A specification of the restful capabilities of the solution for a specific resource type + *

+ */ + @Block() + public static class RestResource extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="type", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="A resource type that is supported", + formalDefinition="A type of resource exposed via the restful interface" + ) + private BoundCodeDt myType; + + @Child(name="profile", order=1, min=0, max=1, type={ + ca.uhn.fhir.model.dstu.resource.Profile.class }) + @Description( + shortDefinition="What structural features are supported", + formalDefinition="A specification of the profile that describes the solution's support for the resource, including any constraints on cardinality, bindings, lengths or other limitations" + ) + private ResourceReferenceDt myProfile; + + @Child(name="operation", order=2, min=1, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="What operations are supported?", + formalDefinition="Identifies a restful operation supported by the solution" + ) + private java.util.List myOperation; + + @Child(name="readHistory", type=BooleanDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Whether vRead can return past versions", + formalDefinition="A flag for whether the server is able to return past versions as part of the vRead operation" + ) + private BooleanDt myReadHistory; + + @Child(name="updateCreate", type=BooleanDt.class, order=4, min=0, max=1) + @Description( + shortDefinition="If allows/uses update to a new location", + formalDefinition="A flag to indicate that the server allows the client to create new identities on the server. If the update operation is used (client) or allowed (server) to a new location where a resource doesn't already exist. This means that the server allows the client to create new identities on the server" + ) + private BooleanDt myUpdateCreate; + + @Child(name="searchInclude", type=StringDt.class, order=5, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="_include values supported by the server", + formalDefinition="A list of _include values supported by the server" + ) + private java.util.List mySearchInclude; + + @Child(name="searchParam", order=6, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Additional search params defined", + formalDefinition="Additional search parameters for implementations to support and/or make use of" + ) + private java.util.List mySearchParam; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myType, myProfile, myOperation, myReadHistory, myUpdateCreate, mySearchInclude, mySearchParam); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myType, myProfile, myOperation, myReadHistory, myUpdateCreate, mySearchInclude, mySearchParam); + } + + /** + * Gets the value(s) for type (A resource type that is supported). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A type of resource exposed via the restful interface + *

+ */ + public BoundCodeDt getType() { + if (myType == null) { + myType = new BoundCodeDt(ResourceTypeEnum.VALUESET_BINDER); + } + return myType; + } + + /** + * Sets the value(s) for type (A resource type that is supported) + * + *

+ * Definition: + * A type of resource exposed via the restful interface + *

+ */ + public RestResource setType(BoundCodeDt theValue) { + myType = theValue; + return this; + } + + /** + * Sets the value(s) for type (A resource type that is supported) + * + *

+ * Definition: + * A type of resource exposed via the restful interface + *

+ */ + public RestResource setType(ResourceTypeEnum theValue) { + getType().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for profile (What structural features are supported). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A specification of the profile that describes the solution's support for the resource, including any constraints on cardinality, bindings, lengths or other limitations + *

+ */ + public ResourceReferenceDt getProfile() { + if (myProfile == null) { + myProfile = new ResourceReferenceDt(); + } + return myProfile; + } + + /** + * Sets the value(s) for profile (What structural features are supported) + * + *

+ * Definition: + * A specification of the profile that describes the solution's support for the resource, including any constraints on cardinality, bindings, lengths or other limitations + *

+ */ + public RestResource setProfile(ResourceReferenceDt theValue) { + myProfile = theValue; + return this; + } + + + /** + * Gets the value(s) for operation (What operations are supported?). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies a restful operation supported by the solution + *

+ */ + public java.util.List getOperation() { + if (myOperation == null) { + myOperation = new java.util.ArrayList(); + } + return myOperation; + } + + /** + * Sets the value(s) for operation (What operations are supported?) + * + *

+ * Definition: + * Identifies a restful operation supported by the solution + *

+ */ + public RestResource setOperation(java.util.List theValue) { + myOperation = theValue; + return this; + } + + /** + * Adds and returns a new value for operation (What operations are supported?) + * + *

+ * Definition: + * Identifies a restful operation supported by the solution + *

+ */ + public RestResourceOperation addOperation() { + RestResourceOperation newType = new RestResourceOperation(); + getOperation().add(newType); + return newType; + } + + /** + * Gets the first repetition for operation (What operations are supported?), + * creating it if it does not already exist. + * + *

+ * Definition: + * Identifies a restful operation supported by the solution + *

+ */ + public RestResourceOperation getOperationFirstRep() { + if (getOperation().isEmpty()) { + return addOperation(); + } + return getOperation().get(0); + } + + /** + * Gets the value(s) for readHistory (Whether vRead can return past versions). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A flag for whether the server is able to return past versions as part of the vRead operation + *

+ */ + public BooleanDt getReadHistory() { + if (myReadHistory == null) { + myReadHistory = new BooleanDt(); + } + return myReadHistory; + } + + /** + * Sets the value(s) for readHistory (Whether vRead can return past versions) + * + *

+ * Definition: + * A flag for whether the server is able to return past versions as part of the vRead operation + *

+ */ + public RestResource setReadHistory(BooleanDt theValue) { + myReadHistory = theValue; + return this; + } + + /** + * Sets the value for readHistory (Whether vRead can return past versions) + * + *

+ * Definition: + * A flag for whether the server is able to return past versions as part of the vRead operation + *

+ */ + public RestResource setReadHistory( boolean theBoolean) { + myReadHistory = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for updateCreate (If allows/uses update to a new location). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A flag to indicate that the server allows the client to create new identities on the server. If the update operation is used (client) or allowed (server) to a new location where a resource doesn't already exist. This means that the server allows the client to create new identities on the server + *

+ */ + public BooleanDt getUpdateCreate() { + if (myUpdateCreate == null) { + myUpdateCreate = new BooleanDt(); + } + return myUpdateCreate; + } + + /** + * Sets the value(s) for updateCreate (If allows/uses update to a new location) + * + *

+ * Definition: + * A flag to indicate that the server allows the client to create new identities on the server. If the update operation is used (client) or allowed (server) to a new location where a resource doesn't already exist. This means that the server allows the client to create new identities on the server + *

+ */ + public RestResource setUpdateCreate(BooleanDt theValue) { + myUpdateCreate = theValue; + return this; + } + + /** + * Sets the value for updateCreate (If allows/uses update to a new location) + * + *

+ * Definition: + * A flag to indicate that the server allows the client to create new identities on the server. If the update operation is used (client) or allowed (server) to a new location where a resource doesn't already exist. This means that the server allows the client to create new identities on the server + *

+ */ + public RestResource setUpdateCreate( boolean theBoolean) { + myUpdateCreate = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for searchInclude (_include values supported by the server). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A list of _include values supported by the server + *

+ */ + public java.util.List getSearchInclude() { + if (mySearchInclude == null) { + mySearchInclude = new java.util.ArrayList(); + } + return mySearchInclude; + } + + /** + * Sets the value(s) for searchInclude (_include values supported by the server) + * + *

+ * Definition: + * A list of _include values supported by the server + *

+ */ + public RestResource setSearchInclude(java.util.List theValue) { + mySearchInclude = theValue; + return this; + } + + /** + * Adds and returns a new value for searchInclude (_include values supported by the server) + * + *

+ * Definition: + * A list of _include values supported by the server + *

+ */ + public StringDt addSearchInclude() { + StringDt newType = new StringDt(); + getSearchInclude().add(newType); + return newType; + } + + /** + * Gets the first repetition for searchInclude (_include values supported by the server), + * creating it if it does not already exist. + * + *

+ * Definition: + * A list of _include values supported by the server + *

+ */ + public StringDt getSearchIncludeFirstRep() { + if (getSearchInclude().isEmpty()) { + return addSearchInclude(); + } + return getSearchInclude().get(0); + } + /** + * Adds a new value for searchInclude (_include values supported by the server) + * + *

+ * Definition: + * A list of _include values supported by the server + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public RestResource addSearchInclude( String theString) { + if (mySearchInclude == null) { + mySearchInclude = new java.util.ArrayList(); + } + mySearchInclude.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for searchParam (Additional search params defined). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public java.util.List getSearchParam() { + if (mySearchParam == null) { + mySearchParam = new java.util.ArrayList(); + } + return mySearchParam; + } + + /** + * Sets the value(s) for searchParam (Additional search params defined) + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public RestResource setSearchParam(java.util.List theValue) { + mySearchParam = theValue; + return this; + } + + /** + * Adds and returns a new value for searchParam (Additional search params defined) + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public RestResourceSearchParam addSearchParam() { + RestResourceSearchParam newType = new RestResourceSearchParam(); + getSearchParam().add(newType); + return newType; + } + + /** + * Gets the first repetition for searchParam (Additional search params defined), + * creating it if it does not already exist. + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public RestResourceSearchParam getSearchParamFirstRep() { + if (getSearchParam().isEmpty()) { + return addSearchParam(); + } + return getSearchParam().get(0); + } + + + } + + /** + * Block class for child element: Conformance.rest.resource.operation (What operations are supported?) + * + *

+ * Definition: + * Identifies a restful operation supported by the solution + *

+ */ + @Block() + public static class RestResourceOperation extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="code", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="read | vread | update | delete | history-instance | validate | history-type | create | search-type", + formalDefinition="Coded identifier of the operation, supported by the system resource" + ) + private BoundCodeDt myCode; + + @Child(name="documentation", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Anything special about operation behavior", + formalDefinition="Guidance specific to the implementation of this operation, such as 'delete is a logical delete' or 'updates are only allowed with version id' or 'creates permitted from pre-authorized certificates only'" + ) + private StringDt myDocumentation; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCode, myDocumentation); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCode, myDocumentation); + } + + /** + * Gets the value(s) for code (read | vread | update | delete | history-instance | validate | history-type | create | search-type). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Coded identifier of the operation, supported by the system resource + *

+ */ + public BoundCodeDt getCode() { + if (myCode == null) { + myCode = new BoundCodeDt(RestfulOperationTypeEnum.VALUESET_BINDER); + } + return myCode; + } + + /** + * Sets the value(s) for code (read | vread | update | delete | history-instance | validate | history-type | create | search-type) + * + *

+ * Definition: + * Coded identifier of the operation, supported by the system resource + *

+ */ + public RestResourceOperation setCode(BoundCodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value(s) for code (read | vread | update | delete | history-instance | validate | history-type | create | search-type) + * + *

+ * Definition: + * Coded identifier of the operation, supported by the system resource + *

+ */ + public RestResourceOperation setCode(RestfulOperationTypeEnum theValue) { + getCode().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for documentation (Anything special about operation behavior). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Guidance specific to the implementation of this operation, such as 'delete is a logical delete' or 'updates are only allowed with version id' or 'creates permitted from pre-authorized certificates only' + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Anything special about operation behavior) + * + *

+ * Definition: + * Guidance specific to the implementation of this operation, such as 'delete is a logical delete' or 'updates are only allowed with version id' or 'creates permitted from pre-authorized certificates only' + *

+ */ + public RestResourceOperation setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Anything special about operation behavior) + * + *

+ * Definition: + * Guidance specific to the implementation of this operation, such as 'delete is a logical delete' or 'updates are only allowed with version id' or 'creates permitted from pre-authorized certificates only' + *

+ */ + public RestResourceOperation setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + + } + + + /** + * Block class for child element: Conformance.rest.resource.searchParam (Additional search params defined) + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + @Block() + public static class RestResourceSearchParam extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="name", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Name of search parameter", + formalDefinition="The name of the search parameter used in the interface" + ) + private StringDt myName; + + @Child(name="definition", type=UriDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Source of definition for parameter", + formalDefinition="A formal reference to where this parameter was first defined, so that a client can be confident of the meaning of the search parameter" + ) + private UriDt myDefinition; + + @Child(name="type", type=CodeDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="number | date | string | token | reference | composite | quantity", + formalDefinition="The type of value a search parameter refers to, and how the content is interpreted" + ) + private BoundCodeDt myType; + + @Child(name="documentation", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Server-specific usage", + formalDefinition="This allows documentation of any distinct behaviors about how the search parameter is used. For example, text matching algorithms." + ) + private StringDt myDocumentation; + + @Child(name="target", type=CodeDt.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Types of resource (if a resource reference)", + formalDefinition="Types of resource (if a resource is referenced)" + ) + private java.util.List> myTarget; + + @Child(name="chain", type=StringDt.class, order=5, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Chained names supported", + formalDefinition="" + ) + private java.util.List myChain; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myName, myDefinition, myType, myDocumentation, myTarget, myChain); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myName, myDefinition, myType, myDocumentation, myTarget, myChain); + } + + /** + * Gets the value(s) for name (Name of search parameter). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of the search parameter used in the interface + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Name of search parameter) + * + *

+ * Definition: + * The name of the search parameter used in the interface + *

+ */ + public RestResourceSearchParam setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Name of search parameter) + * + *

+ * Definition: + * The name of the search parameter used in the interface + *

+ */ + public RestResourceSearchParam setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for definition (Source of definition for parameter). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A formal reference to where this parameter was first defined, so that a client can be confident of the meaning of the search parameter + *

+ */ + public UriDt getDefinition() { + if (myDefinition == null) { + myDefinition = new UriDt(); + } + return myDefinition; + } + + /** + * Sets the value(s) for definition (Source of definition for parameter) + * + *

+ * Definition: + * A formal reference to where this parameter was first defined, so that a client can be confident of the meaning of the search parameter + *

+ */ + public RestResourceSearchParam setDefinition(UriDt theValue) { + myDefinition = theValue; + return this; + } + + /** + * Sets the value for definition (Source of definition for parameter) + * + *

+ * Definition: + * A formal reference to where this parameter was first defined, so that a client can be confident of the meaning of the search parameter + *

+ */ + public RestResourceSearchParam setDefinition( String theUri) { + myDefinition = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for type (number | date | string | token | reference | composite | quantity). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The type of value a search parameter refers to, and how the content is interpreted + *

+ */ + public BoundCodeDt getType() { + if (myType == null) { + myType = new BoundCodeDt(SearchParamTypeEnum.VALUESET_BINDER); + } + return myType; + } + + /** + * Sets the value(s) for type (number | date | string | token | reference | composite | quantity) + * + *

+ * Definition: + * The type of value a search parameter refers to, and how the content is interpreted + *

+ */ + public RestResourceSearchParam setType(BoundCodeDt theValue) { + myType = theValue; + return this; + } + + /** + * Sets the value(s) for type (number | date | string | token | reference | composite | quantity) + * + *

+ * Definition: + * The type of value a search parameter refers to, and how the content is interpreted + *

+ */ + public RestResourceSearchParam setType(SearchParamTypeEnum theValue) { + getType().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for documentation (Server-specific usage). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * This allows documentation of any distinct behaviors about how the search parameter is used. For example, text matching algorithms. + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Server-specific usage) + * + *

+ * Definition: + * This allows documentation of any distinct behaviors about how the search parameter is used. For example, text matching algorithms. + *

+ */ + public RestResourceSearchParam setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Server-specific usage) + * + *

+ * Definition: + * This allows documentation of any distinct behaviors about how the search parameter is used. For example, text matching algorithms. + *

+ */ + public RestResourceSearchParam setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for target (Types of resource (if a resource reference)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public java.util.List> getTarget() { + if (myTarget == null) { + myTarget = new java.util.ArrayList>(); + } + return myTarget; + } + + /** + * Sets the value(s) for target (Types of resource (if a resource reference)) + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public RestResourceSearchParam setTarget(java.util.List> theValue) { + myTarget = theValue; + return this; + } + + /** + * Add a value for target (Types of resource (if a resource reference)) using an enumerated type. This + * is intended as a convenience method for situations where the FHIR defined ValueSets are mandatory + * or contain the desirable codes. If you wish to use codes other than those which are built-in, + * you may also use the {@link #addType()} method. + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public BoundCodeDt addTarget(ResourceTypeEnum theValue) { + BoundCodeDt retVal = new BoundCodeDt(ResourceTypeEnum.VALUESET_BINDER, theValue); + getTarget().add(retVal); + return retVal; + } + + /** + * Gets the first repetition for target (Types of resource (if a resource reference)), + * creating it if it does not already exist. + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public BoundCodeDt getTargetFirstRep() { + if (getTarget().size() == 0) { + addTarget(); + } + return getTarget().get(0); + } + + /** + * Add a value for target (Types of resource (if a resource reference)) + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public BoundCodeDt addTarget() { + BoundCodeDt retVal = new BoundCodeDt(ResourceTypeEnum.VALUESET_BINDER); + getTarget().add(retVal); + return retVal; + } + + /** + * Sets the value(s), and clears any existing value(s) for target (Types of resource (if a resource reference)) + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public RestResourceSearchParam setTarget(ResourceTypeEnum theValue) { + getTarget().clear(); + addTarget(theValue); + return this; + } + + + /** + * Gets the value(s) for chain (Chained names supported). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public java.util.List getChain() { + if (myChain == null) { + myChain = new java.util.ArrayList(); + } + return myChain; + } + + /** + * Sets the value(s) for chain (Chained names supported) + * + *

+ * Definition: + * + *

+ */ + public RestResourceSearchParam setChain(java.util.List theValue) { + myChain = theValue; + return this; + } + + /** + * Adds and returns a new value for chain (Chained names supported) + * + *

+ * Definition: + * + *

+ */ + public StringDt addChain() { + StringDt newType = new StringDt(); + getChain().add(newType); + return newType; + } + + /** + * Gets the first repetition for chain (Chained names supported), + * creating it if it does not already exist. + * + *

+ * Definition: + * + *

+ */ + public StringDt getChainFirstRep() { + if (getChain().isEmpty()) { + return addChain(); + } + return getChain().get(0); + } + /** + * Adds a new value for chain (Chained names supported) + * + *

+ * Definition: + * + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public RestResourceSearchParam addChain( String theString) { + if (myChain == null) { + myChain = new java.util.ArrayList(); + } + myChain.add(new StringDt(theString)); + return this; + } + + + + } + + + + /** + * Block class for child element: Conformance.rest.operation (What operations are supported?) + * + *

+ * Definition: + * A specification of restful operations supported by the system + *

+ */ + @Block() + public static class RestOperation extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="code", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="transaction | search-system | history-system", + formalDefinition="A coded identifier of the operation, supported by the system" + ) + private BoundCodeDt myCode; + + @Child(name="documentation", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Anything special about operation behavior", + formalDefinition="Guidance specific to the implementation of this operation, such as limitations on the kind of transactions allowed, or information about system wide search is implemented" + ) + private StringDt myDocumentation; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCode, myDocumentation); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCode, myDocumentation); + } + + /** + * Gets the value(s) for code (transaction | search-system | history-system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A coded identifier of the operation, supported by the system + *

+ */ + public BoundCodeDt getCode() { + if (myCode == null) { + myCode = new BoundCodeDt(RestfulOperationSystemEnum.VALUESET_BINDER); + } + return myCode; + } + + /** + * Sets the value(s) for code (transaction | search-system | history-system) + * + *

+ * Definition: + * A coded identifier of the operation, supported by the system + *

+ */ + public RestOperation setCode(BoundCodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value(s) for code (transaction | search-system | history-system) + * + *

+ * Definition: + * A coded identifier of the operation, supported by the system + *

+ */ + public RestOperation setCode(RestfulOperationSystemEnum theValue) { + getCode().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for documentation (Anything special about operation behavior). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Guidance specific to the implementation of this operation, such as limitations on the kind of transactions allowed, or information about system wide search is implemented + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Anything special about operation behavior) + * + *

+ * Definition: + * Guidance specific to the implementation of this operation, such as limitations on the kind of transactions allowed, or information about system wide search is implemented + *

+ */ + public RestOperation setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Anything special about operation behavior) + * + *

+ * Definition: + * Guidance specific to the implementation of this operation, such as limitations on the kind of transactions allowed, or information about system wide search is implemented + *

+ */ + public RestOperation setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + + } + + + /** + * Block class for child element: Conformance.rest.query (Definition of a named query) + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + @Block() + public static class RestQuery extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="name", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Special named queries (_query=)", + formalDefinition="The name of a query, which is used in the _query parameter when the query is called" + ) + private StringDt myName; + + @Child(name="definition", type=UriDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="Where query is defined", + formalDefinition="Identifies the custom query, defined either in FHIR core or another profile" + ) + private UriDt myDefinition; + + @Child(name="documentation", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Additional usage guidance", + formalDefinition="Additional information about how the query functions in this particular implementation" + ) + private StringDt myDocumentation; + + @Child(name="parameter", type=RestResourceSearchParam.class, order=3, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Parameter for the named query", + formalDefinition="Identifies which of the parameters for the named query are supported" + ) + private java.util.List myParameter; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myName, myDefinition, myDocumentation, myParameter); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myName, myDefinition, myDocumentation, myParameter); + } + + /** + * Gets the value(s) for name (Special named queries (_query=)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of a query, which is used in the _query parameter when the query is called + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Special named queries (_query=)) + * + *

+ * Definition: + * The name of a query, which is used in the _query parameter when the query is called + *

+ */ + public RestQuery setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Special named queries (_query=)) + * + *

+ * Definition: + * The name of a query, which is used in the _query parameter when the query is called + *

+ */ + public RestQuery setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for definition (Where query is defined). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the custom query, defined either in FHIR core or another profile + *

+ */ + public UriDt getDefinition() { + if (myDefinition == null) { + myDefinition = new UriDt(); + } + return myDefinition; + } + + /** + * Sets the value(s) for definition (Where query is defined) + * + *

+ * Definition: + * Identifies the custom query, defined either in FHIR core or another profile + *

+ */ + public RestQuery setDefinition(UriDt theValue) { + myDefinition = theValue; + return this; + } + + /** + * Sets the value for definition (Where query is defined) + * + *

+ * Definition: + * Identifies the custom query, defined either in FHIR core or another profile + *

+ */ + public RestQuery setDefinition( String theUri) { + myDefinition = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for documentation (Additional usage guidance). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Additional information about how the query functions in this particular implementation + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Additional usage guidance) + * + *

+ * Definition: + * Additional information about how the query functions in this particular implementation + *

+ */ + public RestQuery setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Additional usage guidance) + * + *

+ * Definition: + * Additional information about how the query functions in this particular implementation + *

+ */ + public RestQuery setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for parameter (Parameter for the named query). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies which of the parameters for the named query are supported + *

+ */ + public java.util.List getParameter() { + if (myParameter == null) { + myParameter = new java.util.ArrayList(); + } + return myParameter; + } + + /** + * Sets the value(s) for parameter (Parameter for the named query) + * + *

+ * Definition: + * Identifies which of the parameters for the named query are supported + *

+ */ + public RestQuery setParameter(java.util.List theValue) { + myParameter = theValue; + return this; + } + + /** + * Adds and returns a new value for parameter (Parameter for the named query) + * + *

+ * Definition: + * Identifies which of the parameters for the named query are supported + *

+ */ + public RestResourceSearchParam addParameter() { + RestResourceSearchParam newType = new RestResourceSearchParam(); + getParameter().add(newType); + return newType; + } + + /** + * Gets the first repetition for parameter (Parameter for the named query), + * creating it if it does not already exist. + * + *

+ * Definition: + * Identifies which of the parameters for the named query are supported + *

+ */ + public RestResourceSearchParam getParameterFirstRep() { + if (getParameter().isEmpty()) { + return addParameter(); + } + return getParameter().get(0); + } + + + } + + + + /** + * Block class for child element: Conformance.messaging (If messaging is supported) + * + *

+ * Definition: + * A description of the messaging capabilities of the solution + *

+ */ + @Block() + public static class Messaging extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="endpoint", type=UriDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Actual endpoint being described", + formalDefinition="An address to which messages and/or replies are to be sent." + ) + private UriDt myEndpoint; + + @Child(name="reliableCache", type=IntegerDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Reliable Message Cache Length", + formalDefinition="Length if the receiver's reliable messaging cache (if a receiver) or how long the cache length on the receiver should be (if a sender)" + ) + private IntegerDt myReliableCache; + + @Child(name="documentation", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Messaging interface behavior details", + formalDefinition="Documentation about the system's messaging capabilities for this endpoint not otherwise documented by the conformance statement. For example, process for becoming an authorized messaging exchange partner." + ) + private StringDt myDocumentation; + + @Child(name="event", order=3, min=1, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Declare support for this event", + formalDefinition="A description of the solution's support for an event at this end point." + ) + private java.util.List myEvent; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myEndpoint, myReliableCache, myDocumentation, myEvent); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myEndpoint, myReliableCache, myDocumentation, myEvent); + } + + /** + * Gets the value(s) for endpoint (Actual endpoint being described). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An address to which messages and/or replies are to be sent. + *

+ */ + public UriDt getEndpoint() { + if (myEndpoint == null) { + myEndpoint = new UriDt(); + } + return myEndpoint; + } + + /** + * Sets the value(s) for endpoint (Actual endpoint being described) + * + *

+ * Definition: + * An address to which messages and/or replies are to be sent. + *

+ */ + public Messaging setEndpoint(UriDt theValue) { + myEndpoint = theValue; + return this; + } + + /** + * Sets the value for endpoint (Actual endpoint being described) + * + *

+ * Definition: + * An address to which messages and/or replies are to be sent. + *

+ */ + public Messaging setEndpoint( String theUri) { + myEndpoint = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for reliableCache (Reliable Message Cache Length). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Length if the receiver's reliable messaging cache (if a receiver) or how long the cache length on the receiver should be (if a sender) + *

+ */ + public IntegerDt getReliableCache() { + if (myReliableCache == null) { + myReliableCache = new IntegerDt(); + } + return myReliableCache; + } + + /** + * Sets the value(s) for reliableCache (Reliable Message Cache Length) + * + *

+ * Definition: + * Length if the receiver's reliable messaging cache (if a receiver) or how long the cache length on the receiver should be (if a sender) + *

+ */ + public Messaging setReliableCache(IntegerDt theValue) { + myReliableCache = theValue; + return this; + } + + /** + * Sets the value for reliableCache (Reliable Message Cache Length) + * + *

+ * Definition: + * Length if the receiver's reliable messaging cache (if a receiver) or how long the cache length on the receiver should be (if a sender) + *

+ */ + public Messaging setReliableCache( int theInteger) { + myReliableCache = new IntegerDt(theInteger); + return this; + } + + + /** + * Gets the value(s) for documentation (Messaging interface behavior details). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Documentation about the system's messaging capabilities for this endpoint not otherwise documented by the conformance statement. For example, process for becoming an authorized messaging exchange partner. + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Messaging interface behavior details) + * + *

+ * Definition: + * Documentation about the system's messaging capabilities for this endpoint not otherwise documented by the conformance statement. For example, process for becoming an authorized messaging exchange partner. + *

+ */ + public Messaging setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Messaging interface behavior details) + * + *

+ * Definition: + * Documentation about the system's messaging capabilities for this endpoint not otherwise documented by the conformance statement. For example, process for becoming an authorized messaging exchange partner. + *

+ */ + public Messaging setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for event (Declare support for this event). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A description of the solution's support for an event at this end point. + *

+ */ + public java.util.List getEvent() { + if (myEvent == null) { + myEvent = new java.util.ArrayList(); + } + return myEvent; + } + + /** + * Sets the value(s) for event (Declare support for this event) + * + *

+ * Definition: + * A description of the solution's support for an event at this end point. + *

+ */ + public Messaging setEvent(java.util.List theValue) { + myEvent = theValue; + return this; + } + + /** + * Adds and returns a new value for event (Declare support for this event) + * + *

+ * Definition: + * A description of the solution's support for an event at this end point. + *

+ */ + public MessagingEvent addEvent() { + MessagingEvent newType = new MessagingEvent(); + getEvent().add(newType); + return newType; + } + + /** + * Gets the first repetition for event (Declare support for this event), + * creating it if it does not already exist. + * + *

+ * Definition: + * A description of the solution's support for an event at this end point. + *

+ */ + public MessagingEvent getEventFirstRep() { + if (getEvent().isEmpty()) { + return addEvent(); + } + return getEvent().get(0); + } + + + } + + /** + * Block class for child element: Conformance.messaging.event (Declare support for this event) + * + *

+ * Definition: + * A description of the solution's support for an event at this end point. + *

+ */ + @Block() + public static class MessagingEvent extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="code", type=CodingDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Event type", + formalDefinition="A coded identifier of a supported messaging event" + ) + private CodingDt myCode; + + @Child(name="category", type=CodeDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Consequence | Currency | Notification", + formalDefinition="The impact of the content of the message" + ) + private BoundCodeDt myCategory; + + @Child(name="mode", type=CodeDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="sender | receiver", + formalDefinition="The mode of this event declaration - whether application is sender or receiver" + ) + private BoundCodeDt myMode; + + @Child(name="protocol", type=CodingDt.class, order=3, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="http | ftp | mllp +", + formalDefinition="A list of the messaging transport protocol(s) identifiers, supported by this endpoint" + ) + private java.util.List myProtocol; + + @Child(name="focus", type=CodeDt.class, order=4, min=1, max=1) + @Description( + shortDefinition="Resource that's focus of message", + formalDefinition="A resource associated with the event. This is the resource that defines the event." + ) + private BoundCodeDt myFocus; + + @Child(name="request", order=5, min=1, max=1, type={ + ca.uhn.fhir.model.dstu.resource.Profile.class }) + @Description( + shortDefinition="Profile that describes the request", + formalDefinition="Information about the request for this event" + ) + private ResourceReferenceDt myRequest; + + @Child(name="response", order=6, min=1, max=1, type={ + ca.uhn.fhir.model.dstu.resource.Profile.class }) + @Description( + shortDefinition="Profile that describes the response", + formalDefinition="Information about the response for this event" + ) + private ResourceReferenceDt myResponse; + + @Child(name="documentation", type=StringDt.class, order=7, min=0, max=1) + @Description( + shortDefinition="Endpoint-specific event documentation", + formalDefinition="Guidance on how this event is handled, such as internal system trigger points, business rules, etc." + ) + private StringDt myDocumentation; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCode, myCategory, myMode, myProtocol, myFocus, myRequest, myResponse, myDocumentation); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCode, myCategory, myMode, myProtocol, myFocus, myRequest, myResponse, myDocumentation); + } + + /** + * Gets the value(s) for code (Event type). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A coded identifier of a supported messaging event + *

+ */ + public CodingDt getCode() { + if (myCode == null) { + myCode = new CodingDt(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Event type) + * + *

+ * Definition: + * A coded identifier of a supported messaging event + *

+ */ + public MessagingEvent setCode(CodingDt theValue) { + myCode = theValue; + return this; + } + + + /** + * Gets the value(s) for category (Consequence | Currency | Notification). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The impact of the content of the message + *

+ */ + public BoundCodeDt getCategory() { + if (myCategory == null) { + myCategory = new BoundCodeDt(MessageSignificanceCategoryEnum.VALUESET_BINDER); + } + return myCategory; + } + + /** + * Sets the value(s) for category (Consequence | Currency | Notification) + * + *

+ * Definition: + * The impact of the content of the message + *

+ */ + public MessagingEvent setCategory(BoundCodeDt theValue) { + myCategory = theValue; + return this; + } + + /** + * Sets the value(s) for category (Consequence | Currency | Notification) + * + *

+ * Definition: + * The impact of the content of the message + *

+ */ + public MessagingEvent setCategory(MessageSignificanceCategoryEnum theValue) { + getCategory().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for mode (sender | receiver). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The mode of this event declaration - whether application is sender or receiver + *

+ */ + public BoundCodeDt getMode() { + if (myMode == null) { + myMode = new BoundCodeDt(ConformanceEventModeEnum.VALUESET_BINDER); + } + return myMode; + } + + /** + * Sets the value(s) for mode (sender | receiver) + * + *

+ * Definition: + * The mode of this event declaration - whether application is sender or receiver + *

+ */ + public MessagingEvent setMode(BoundCodeDt theValue) { + myMode = theValue; + return this; + } + + /** + * Sets the value(s) for mode (sender | receiver) + * + *

+ * Definition: + * The mode of this event declaration - whether application is sender or receiver + *

+ */ + public MessagingEvent setMode(ConformanceEventModeEnum theValue) { + getMode().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for protocol (http | ftp | mllp +). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A list of the messaging transport protocol(s) identifiers, supported by this endpoint + *

+ */ + public java.util.List getProtocol() { + if (myProtocol == null) { + myProtocol = new java.util.ArrayList(); + } + return myProtocol; + } + + /** + * Sets the value(s) for protocol (http | ftp | mllp +) + * + *

+ * Definition: + * A list of the messaging transport protocol(s) identifiers, supported by this endpoint + *

+ */ + public MessagingEvent setProtocol(java.util.List theValue) { + myProtocol = theValue; + return this; + } + + /** + * Adds and returns a new value for protocol (http | ftp | mllp +) + * + *

+ * Definition: + * A list of the messaging transport protocol(s) identifiers, supported by this endpoint + *

+ */ + public CodingDt addProtocol() { + CodingDt newType = new CodingDt(); + getProtocol().add(newType); + return newType; + } + + /** + * Gets the first repetition for protocol (http | ftp | mllp +), + * creating it if it does not already exist. + * + *

+ * Definition: + * A list of the messaging transport protocol(s) identifiers, supported by this endpoint + *

+ */ + public CodingDt getProtocolFirstRep() { + if (getProtocol().isEmpty()) { + return addProtocol(); + } + return getProtocol().get(0); + } + + /** + * Gets the value(s) for focus (Resource that's focus of message). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A resource associated with the event. This is the resource that defines the event. + *

+ */ + public BoundCodeDt getFocus() { + if (myFocus == null) { + myFocus = new BoundCodeDt(ResourceTypeEnum.VALUESET_BINDER); + } + return myFocus; + } + + /** + * Sets the value(s) for focus (Resource that's focus of message) + * + *

+ * Definition: + * A resource associated with the event. This is the resource that defines the event. + *

+ */ + public MessagingEvent setFocus(BoundCodeDt theValue) { + myFocus = theValue; + return this; + } + + /** + * Sets the value(s) for focus (Resource that's focus of message) + * + *

+ * Definition: + * A resource associated with the event. This is the resource that defines the event. + *

+ */ + public MessagingEvent setFocus(ResourceTypeEnum theValue) { + getFocus().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for request (Profile that describes the request). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Information about the request for this event + *

+ */ + public ResourceReferenceDt getRequest() { + if (myRequest == null) { + myRequest = new ResourceReferenceDt(); + } + return myRequest; + } + + /** + * Sets the value(s) for request (Profile that describes the request) + * + *

+ * Definition: + * Information about the request for this event + *

+ */ + public MessagingEvent setRequest(ResourceReferenceDt theValue) { + myRequest = theValue; + return this; + } + + + /** + * Gets the value(s) for response (Profile that describes the response). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Information about the response for this event + *

+ */ + public ResourceReferenceDt getResponse() { + if (myResponse == null) { + myResponse = new ResourceReferenceDt(); + } + return myResponse; + } + + /** + * Sets the value(s) for response (Profile that describes the response) + * + *

+ * Definition: + * Information about the response for this event + *

+ */ + public MessagingEvent setResponse(ResourceReferenceDt theValue) { + myResponse = theValue; + return this; + } + + + /** + * Gets the value(s) for documentation (Endpoint-specific event documentation). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Guidance on how this event is handled, such as internal system trigger points, business rules, etc. + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Endpoint-specific event documentation) + * + *

+ * Definition: + * Guidance on how this event is handled, such as internal system trigger points, business rules, etc. + *

+ */ + public MessagingEvent setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Endpoint-specific event documentation) + * + *

+ * Definition: + * Guidance on how this event is handled, such as internal system trigger points, business rules, etc. + *

+ */ + public MessagingEvent setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + + } + + + + /** + * Block class for child element: Conformance.document (Document definition) + * + *

+ * Definition: + * A document definition + *

+ */ + @Block() + public static class Document extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="mode", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="producer | consumer", + formalDefinition="Mode of this document declaration - whether application is producer or consumer" + ) + private BoundCodeDt myMode; + + @Child(name="documentation", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Description of document support", + formalDefinition="A description of how the application supports or uses the specified document profile. For example, when are documents created, what action is taken with consumed documents, etc." + ) + private StringDt myDocumentation; + + @Child(name="profile", order=2, min=1, max=1, type={ + ca.uhn.fhir.model.dstu.resource.Profile.class }) + @Description( + shortDefinition="Constraint on a resource used in the document", + formalDefinition="A constraint on a resource used in the document" + ) + private ResourceReferenceDt myProfile; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myMode, myDocumentation, myProfile); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myMode, myDocumentation, myProfile); + } + + /** + * Gets the value(s) for mode (producer | consumer). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Mode of this document declaration - whether application is producer or consumer + *

+ */ + public BoundCodeDt getMode() { + if (myMode == null) { + myMode = new BoundCodeDt(DocumentModeEnum.VALUESET_BINDER); + } + return myMode; + } + + /** + * Sets the value(s) for mode (producer | consumer) + * + *

+ * Definition: + * Mode of this document declaration - whether application is producer or consumer + *

+ */ + public Document setMode(BoundCodeDt theValue) { + myMode = theValue; + return this; + } + + /** + * Sets the value(s) for mode (producer | consumer) + * + *

+ * Definition: + * Mode of this document declaration - whether application is producer or consumer + *

+ */ + public Document setMode(DocumentModeEnum theValue) { + getMode().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for documentation (Description of document support). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A description of how the application supports or uses the specified document profile. For example, when are documents created, what action is taken with consumed documents, etc. + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Description of document support) + * + *

+ * Definition: + * A description of how the application supports or uses the specified document profile. For example, when are documents created, what action is taken with consumed documents, etc. + *

+ */ + public Document setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Description of document support) + * + *

+ * Definition: + * A description of how the application supports or uses the specified document profile. For example, when are documents created, what action is taken with consumed documents, etc. + *

+ */ + public Document setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for profile (Constraint on a resource used in the document). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A constraint on a resource used in the document + *

+ */ + public ResourceReferenceDt getProfile() { + if (myProfile == null) { + myProfile = new ResourceReferenceDt(); + } + return myProfile; + } + + /** + * Sets the value(s) for profile (Constraint on a resource used in the document) + * + *

+ * Definition: + * A constraint on a resource used in the document + *

+ */ + public Document setProfile(ResourceReferenceDt theValue) { + myProfile = theValue; + return this; + } + + + + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/Profile.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/Profile.java new file mode 100644 index 00000000000..170b3de1b01 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/Profile.java @@ -0,0 +1,5138 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.resource; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + + +import java.util.Date; +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.BaseResource; +import ca.uhn.fhir.model.api.IDatatype; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.IResourceBlock; +import ca.uhn.fhir.model.api.Include; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +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.ResourceDef; +import ca.uhn.fhir.model.api.annotation.SearchParamDefinition; +import ca.uhn.fhir.model.dstu.composite.CodingDt; +import ca.uhn.fhir.model.dstu.composite.ContactDt; +import ca.uhn.fhir.model.dstu.valueset.AggregationModeEnum; +import ca.uhn.fhir.model.dstu.valueset.BindingConformanceEnum; +import ca.uhn.fhir.model.dstu.valueset.ConstraintSeverityEnum; +import ca.uhn.fhir.model.dstu.valueset.ContactUseEnum; +import ca.uhn.fhir.model.dstu.valueset.DataTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.ExtensionContextEnum; +import ca.uhn.fhir.model.dstu.valueset.FHIRDefinedTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.PropertyRepresentationEnum; +import ca.uhn.fhir.model.dstu.valueset.ResourceProfileStatusEnum; +import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum; +import ca.uhn.fhir.model.dstu.valueset.SlicingRulesEnum; +import ca.uhn.fhir.model.primitive.BooleanDt; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.IdDt; +import ca.uhn.fhir.model.primitive.IntegerDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.gclient.DateClientParam; +import ca.uhn.fhir.rest.gclient.ReferenceClientParam; +import ca.uhn.fhir.rest.gclient.StringClientParam; +import ca.uhn.fhir.rest.gclient.TokenClientParam; + + +/** + * HAPI/FHIR Profile Resource + * (Resource Profile) + * + *

+ * Definition: + * A Resource Profile - a statement of use of one or more FHIR Resources. It may include constraints on Resources and Data Types, Terminology Binding Statements and Extension Definitions + *

+ * + *

+ * Requirements: + * + *

+ * + *

+ * Profile Definition: + * http://hl7.org/fhir/profiles/Profile + *

+ * + */ +@ResourceDef(name="Profile", profile="http://hl7.org/fhir/profiles/Profile", id="profile") +public class Profile extends BaseResource implements IResource { + + /** + * Search parameter constant for identifier + *

+ * Description: The identifier of the profile
+ * Type: token
+ * Path: Profile.identifier
+ *

+ */ + @SearchParamDefinition(name="identifier", path="Profile.identifier", description="The identifier of the profile", type="token" ) + public static final String SP_IDENTIFIER = "identifier"; + + /** + * Fluent Client search parameter constant for identifier + *

+ * Description: The identifier of the profile
+ * Type: token
+ * Path: Profile.identifier
+ *

+ */ + public static final TokenClientParam IDENTIFIER = new TokenClientParam(SP_IDENTIFIER); + + /** + * Search parameter constant for version + *

+ * Description: The version identifier of the profile
+ * Type: token
+ * Path: Profile.version
+ *

+ */ + @SearchParamDefinition(name="version", path="Profile.version", description="The version identifier of the profile", type="token" ) + public static final String SP_VERSION = "version"; + + /** + * Fluent Client search parameter constant for version + *

+ * Description: The version identifier of the profile
+ * Type: token
+ * Path: Profile.version
+ *

+ */ + public static final TokenClientParam VERSION = new TokenClientParam(SP_VERSION); + + /** + * Search parameter constant for name + *

+ * Description: Name of the profile
+ * Type: string
+ * Path: Profile.name
+ *

+ */ + @SearchParamDefinition(name="name", path="Profile.name", description="Name of the profile", type="string" ) + public static final String SP_NAME = "name"; + + /** + * Fluent Client search parameter constant for name + *

+ * Description: Name of the profile
+ * Type: string
+ * Path: Profile.name
+ *

+ */ + public static final StringClientParam NAME = new StringClientParam(SP_NAME); + + /** + * Search parameter constant for publisher + *

+ * Description: Name of the publisher of the profile
+ * Type: string
+ * Path: Profile.publisher
+ *

+ */ + @SearchParamDefinition(name="publisher", path="Profile.publisher", description="Name of the publisher of the profile", type="string" ) + public static final String SP_PUBLISHER = "publisher"; + + /** + * Fluent Client search parameter constant for publisher + *

+ * Description: Name of the publisher of the profile
+ * Type: string
+ * Path: Profile.publisher
+ *

+ */ + public static final StringClientParam PUBLISHER = new StringClientParam(SP_PUBLISHER); + + /** + * Search parameter constant for description + *

+ * Description: Text search in the description of the profile
+ * Type: string
+ * Path: Profile.description
+ *

+ */ + @SearchParamDefinition(name="description", path="Profile.description", description="Text search in the description of the profile", type="string" ) + public static final String SP_DESCRIPTION = "description"; + + /** + * Fluent Client search parameter constant for description + *

+ * Description: Text search in the description of the profile
+ * Type: string
+ * Path: Profile.description
+ *

+ */ + public static final StringClientParam DESCRIPTION = new StringClientParam(SP_DESCRIPTION); + + /** + * Search parameter constant for status + *

+ * Description: The current status of the profile
+ * Type: token
+ * Path: Profile.status
+ *

+ */ + @SearchParamDefinition(name="status", path="Profile.status", description="The current status of the profile", type="token" ) + public static final String SP_STATUS = "status"; + + /** + * Fluent Client search parameter constant for status + *

+ * Description: The current status of the profile
+ * Type: token
+ * Path: Profile.status
+ *

+ */ + public static final TokenClientParam STATUS = new TokenClientParam(SP_STATUS); + + /** + * Search parameter constant for date + *

+ * Description: The profile publication date
+ * Type: date
+ * Path: Profile.date
+ *

+ */ + @SearchParamDefinition(name="date", path="Profile.date", description="The profile publication date", type="date" ) + public static final String SP_DATE = "date"; + + /** + * Fluent Client search parameter constant for date + *

+ * Description: The profile publication date
+ * Type: date
+ * Path: Profile.date
+ *

+ */ + public static final DateClientParam DATE = new DateClientParam(SP_DATE); + + /** + * Search parameter constant for code + *

+ * Description: A code for the profile in the format uri::code (server may choose to do subsumption)
+ * Type: token
+ * Path: Profile.code
+ *

+ */ + @SearchParamDefinition(name="code", path="Profile.code", description="A code for the profile in the format uri::code (server may choose to do subsumption)", type="token" ) + public static final String SP_CODE = "code"; + + /** + * Fluent Client search parameter constant for code + *

+ * Description: A code for the profile in the format uri::code (server may choose to do subsumption)
+ * Type: token
+ * Path: Profile.code
+ *

+ */ + public static final TokenClientParam CODE = new TokenClientParam(SP_CODE); + + /** + * Search parameter constant for extension + *

+ * Description: An extension code (use or definition)
+ * Type: token
+ * Path: Profile.extensionDefn.code
+ *

+ */ + @SearchParamDefinition(name="extension", path="Profile.extensionDefn.code", description="An extension code (use or definition)", type="token" ) + public static final String SP_EXTENSION = "extension"; + + /** + * Fluent Client search parameter constant for extension + *

+ * Description: An extension code (use or definition)
+ * Type: token
+ * Path: Profile.extensionDefn.code
+ *

+ */ + public static final TokenClientParam EXTENSION = new TokenClientParam(SP_EXTENSION); + + /** + * Search parameter constant for valueset + *

+ * Description: A vocabulary binding code
+ * Type: reference
+ * Path: Profile.structure.element.definition.binding.reference[x]
+ *

+ */ + @SearchParamDefinition(name="valueset", path="Profile.structure.element.definition.binding.reference[x]", description="A vocabulary binding code", type="reference" ) + public static final String SP_VALUESET = "valueset"; + + /** + * Fluent Client search parameter constant for valueset + *

+ * Description: A vocabulary binding code
+ * Type: reference
+ * Path: Profile.structure.element.definition.binding.reference[x]
+ *

+ */ + public static final ReferenceClientParam VALUESET = new ReferenceClientParam(SP_VALUESET); + + /** + * Constant for fluent queries to be used to add include statements. Specifies + * the path value of "Profile.structure.element.definition.binding.reference[x]". + */ + public static final Include INCLUDE_STRUCTURE_ELEMENT_DEFINITION_BINDING_REFERENCE = new Include("Profile.structure.element.definition.binding.reference[x]"); + + /** + * Search parameter constant for type + *

+ * Description: Type of resource that is constrained in the profile
+ * Type: token
+ * Path: Profile.structure.type
+ *

+ */ + @SearchParamDefinition(name="type", path="Profile.structure.type", description="Type of resource that is constrained in the profile", type="token" ) + public static final String SP_TYPE = "type"; + + /** + * Fluent Client search parameter constant for type + *

+ * Description: Type of resource that is constrained in the profile
+ * Type: token
+ * Path: Profile.structure.type
+ *

+ */ + public static final TokenClientParam TYPE = new TokenClientParam(SP_TYPE); + + + @Child(name="identifier", type=StringDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Logical id to reference this profile", + formalDefinition="The identifier that is used to identify this profile when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI)" + ) + private StringDt myIdentifier; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Logical id for this version of the profile", + formalDefinition="The identifier that is used to identify this version of the profile when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp" + ) + private StringDt myVersion; + + @Child(name="name", type=StringDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="Informal name for this profile", + formalDefinition="A free text natural language name identifying the Profile" + ) + private StringDt myName; + + @Child(name="publisher", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Name of the publisher (Organization or individual)", + formalDefinition="Details of the individual or organization who accepts responsibility for publishing the profile" + ) + private StringDt myPublisher; + + @Child(name="telecom", type=ContactDt.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Contact information of the publisher", + formalDefinition="Contact details to assist a user in finding and communicating with the publisher" + ) + private java.util.List myTelecom; + + @Child(name="description", type=StringDt.class, order=5, min=0, max=1) + @Description( + shortDefinition="Natural language description of the profile", + formalDefinition="A free text natural language description of the profile and its use" + ) + private StringDt myDescription; + + @Child(name="code", type=CodingDt.class, order=6, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Assist with indexing and finding", + formalDefinition="A set of terms from external terminologies that may be used to assist with indexing and searching of templates." + ) + private java.util.List myCode; + + @Child(name="status", type=CodeDt.class, order=7, min=1, max=1) + @Description( + shortDefinition="draft | active | retired", + formalDefinition="The status of the profile" + ) + private BoundCodeDt myStatus; + + @Child(name="experimental", type=BooleanDt.class, order=8, min=0, max=1) + @Description( + shortDefinition="If for testing purposes, not real usage", + formalDefinition="This profile was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage" + ) + private BooleanDt myExperimental; + + @Child(name="date", type=DateTimeDt.class, order=9, min=0, max=1) + @Description( + shortDefinition="Date for this version of the profile", + formalDefinition="The date that this version of the profile was published" + ) + private DateTimeDt myDate; + + @Child(name="requirements", type=StringDt.class, order=10, min=0, max=1) + @Description( + shortDefinition="Scope and Usage this profile is for", + formalDefinition="The Scope and Usage that this profile was created to meet" + ) + private StringDt myRequirements; + + @Child(name="fhirVersion", type=IdDt.class, order=11, min=0, max=1) + @Description( + shortDefinition="FHIR Version this profile targets", + formalDefinition="The version of the FHIR specification on which this profile is based" + ) + private IdDt myFhirVersion; + + @Child(name="mapping", order=12, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="External specification that the content is mapped to", + formalDefinition="An external specification that the content is mapped to" + ) + private java.util.List myMapping; + + @Child(name="structure", order=13, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="A constraint on a resource or a data type", + formalDefinition="A constraint statement about what contents a resource or data type may have" + ) + private java.util.List myStructure; + + @Child(name="extensionDefn", order=14, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Definition of an extension", + formalDefinition="An extension defined as part of the profile" + ) + private java.util.List myExtensionDefn; + + @Child(name="query", order=15, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Definition of a named query", + formalDefinition="Definition of a named query and its parameters and their meaning" + ) + private java.util.List myQuery; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myIdentifier, myVersion, myName, myPublisher, myTelecom, myDescription, myCode, myStatus, myExperimental, myDate, myRequirements, myFhirVersion, myMapping, myStructure, myExtensionDefn, myQuery); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myIdentifier, myVersion, myName, myPublisher, myTelecom, myDescription, myCode, myStatus, myExperimental, myDate, myRequirements, myFhirVersion, myMapping, myStructure, myExtensionDefn, myQuery); + } + + /** + * Gets the value(s) for identifier (Logical id to reference this profile). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identifier that is used to identify this profile when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public StringDt getIdentifier() { + if (myIdentifier == null) { + myIdentifier = new StringDt(); + } + return myIdentifier; + } + + /** + * Sets the value(s) for identifier (Logical id to reference this profile) + * + *

+ * Definition: + * The identifier that is used to identify this profile when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public Profile setIdentifier(StringDt theValue) { + myIdentifier = theValue; + return this; + } + + /** + * Sets the value for identifier (Logical id to reference this profile) + * + *

+ * Definition: + * The identifier that is used to identify this profile when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public Profile setIdentifier( String theString) { + myIdentifier = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for version (Logical id for this version of the profile). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identifier that is used to identify this version of the profile when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public StringDt getVersion() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + /** + * Sets the value(s) for version (Logical id for this version of the profile) + * + *

+ * Definition: + * The identifier that is used to identify this version of the profile when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public Profile setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + /** + * Sets the value for version (Logical id for this version of the profile) + * + *

+ * Definition: + * The identifier that is used to identify this version of the profile when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public Profile setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for name (Informal name for this profile). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A free text natural language name identifying the Profile + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Informal name for this profile) + * + *

+ * Definition: + * A free text natural language name identifying the Profile + *

+ */ + public Profile setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Informal name for this profile) + * + *

+ * Definition: + * A free text natural language name identifying the Profile + *

+ */ + public Profile setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for publisher (Name of the publisher (Organization or individual)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Details of the individual or organization who accepts responsibility for publishing the profile + *

+ */ + public StringDt getPublisher() { + if (myPublisher == null) { + myPublisher = new StringDt(); + } + return myPublisher; + } + + /** + * Sets the value(s) for publisher (Name of the publisher (Organization or individual)) + * + *

+ * Definition: + * Details of the individual or organization who accepts responsibility for publishing the profile + *

+ */ + public Profile setPublisher(StringDt theValue) { + myPublisher = theValue; + return this; + } + + /** + * Sets the value for publisher (Name of the publisher (Organization or individual)) + * + *

+ * Definition: + * Details of the individual or organization who accepts responsibility for publishing the profile + *

+ */ + public Profile setPublisher( String theString) { + myPublisher = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for telecom (Contact information of the publisher). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Contact details to assist a user in finding and communicating with the publisher + *

+ */ + public java.util.List getTelecom() { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + return myTelecom; + } + + /** + * Sets the value(s) for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contact details to assist a user in finding and communicating with the publisher + *

+ */ + public Profile setTelecom(java.util.List theValue) { + myTelecom = theValue; + return this; + } + + /** + * Adds and returns a new value for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contact details to assist a user in finding and communicating with the publisher + *

+ */ + public ContactDt addTelecom() { + ContactDt newType = new ContactDt(); + getTelecom().add(newType); + return newType; + } + + /** + * Gets the first repetition for telecom (Contact information of the publisher), + * creating it if it does not already exist. + * + *

+ * Definition: + * Contact details to assist a user in finding and communicating with the publisher + *

+ */ + public ContactDt getTelecomFirstRep() { + if (getTelecom().isEmpty()) { + return addTelecom(); + } + return getTelecom().get(0); + } + /** + * Adds a new value for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contact details to assist a user in finding and communicating with the publisher + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public Profile addTelecom( ContactUseEnum theContactUse, String theValue) { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + myTelecom.add(new ContactDt(theContactUse, theValue)); + return this; + } + + /** + * Adds a new value for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contact details to assist a user in finding and communicating with the publisher + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public Profile addTelecom( String theValue) { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + myTelecom.add(new ContactDt(theValue)); + return this; + } + + + /** + * Gets the value(s) for description (Natural language description of the profile). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A free text natural language description of the profile and its use + *

+ */ + public StringDt getDescription() { + if (myDescription == null) { + myDescription = new StringDt(); + } + return myDescription; + } + + /** + * Sets the value(s) for description (Natural language description of the profile) + * + *

+ * Definition: + * A free text natural language description of the profile and its use + *

+ */ + public Profile setDescription(StringDt theValue) { + myDescription = theValue; + return this; + } + + /** + * Sets the value for description (Natural language description of the profile) + * + *

+ * Definition: + * A free text natural language description of the profile and its use + *

+ */ + public Profile setDescription( String theString) { + myDescription = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for code (Assist with indexing and finding). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A set of terms from external terminologies that may be used to assist with indexing and searching of templates. + *

+ */ + public java.util.List getCode() { + if (myCode == null) { + myCode = new java.util.ArrayList(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Assist with indexing and finding) + * + *

+ * Definition: + * A set of terms from external terminologies that may be used to assist with indexing and searching of templates. + *

+ */ + public Profile setCode(java.util.List theValue) { + myCode = theValue; + return this; + } + + /** + * Adds and returns a new value for code (Assist with indexing and finding) + * + *

+ * Definition: + * A set of terms from external terminologies that may be used to assist with indexing and searching of templates. + *

+ */ + public CodingDt addCode() { + CodingDt newType = new CodingDt(); + getCode().add(newType); + return newType; + } + + /** + * Gets the first repetition for code (Assist with indexing and finding), + * creating it if it does not already exist. + * + *

+ * Definition: + * A set of terms from external terminologies that may be used to assist with indexing and searching of templates. + *

+ */ + public CodingDt getCodeFirstRep() { + if (getCode().isEmpty()) { + return addCode(); + } + return getCode().get(0); + } + + /** + * Gets the value(s) for status (draft | active | retired). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The status of the profile + *

+ */ + public BoundCodeDt getStatus() { + if (myStatus == null) { + myStatus = new BoundCodeDt(ResourceProfileStatusEnum.VALUESET_BINDER); + } + return myStatus; + } + + /** + * Sets the value(s) for status (draft | active | retired) + * + *

+ * Definition: + * The status of the profile + *

+ */ + public Profile setStatus(BoundCodeDt theValue) { + myStatus = theValue; + return this; + } + + /** + * Sets the value(s) for status (draft | active | retired) + * + *

+ * Definition: + * The status of the profile + *

+ */ + public Profile setStatus(ResourceProfileStatusEnum theValue) { + getStatus().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for experimental (If for testing purposes, not real usage). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * This profile was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public BooleanDt getExperimental() { + if (myExperimental == null) { + myExperimental = new BooleanDt(); + } + return myExperimental; + } + + /** + * Sets the value(s) for experimental (If for testing purposes, not real usage) + * + *

+ * Definition: + * This profile was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public Profile setExperimental(BooleanDt theValue) { + myExperimental = theValue; + return this; + } + + /** + * Sets the value for experimental (If for testing purposes, not real usage) + * + *

+ * Definition: + * This profile was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public Profile setExperimental( boolean theBoolean) { + myExperimental = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for date (Date for this version of the profile). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The date that this version of the profile was published + *

+ */ + public DateTimeDt getDate() { + if (myDate == null) { + myDate = new DateTimeDt(); + } + return myDate; + } + + /** + * Sets the value(s) for date (Date for this version of the profile) + * + *

+ * Definition: + * The date that this version of the profile was published + *

+ */ + public Profile setDate(DateTimeDt theValue) { + myDate = theValue; + return this; + } + + /** + * Sets the value for date (Date for this version of the profile) + * + *

+ * Definition: + * The date that this version of the profile was published + *

+ */ + public Profile setDateWithSecondsPrecision( Date theDate) { + myDate = new DateTimeDt(theDate); + return this; + } + + /** + * Sets the value for date (Date for this version of the profile) + * + *

+ * Definition: + * The date that this version of the profile was published + *

+ */ + public Profile setDate( Date theDate, TemporalPrecisionEnum thePrecision) { + myDate = new DateTimeDt(theDate, thePrecision); + return this; + } + + + /** + * Gets the value(s) for requirements (Scope and Usage this profile is for). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The Scope and Usage that this profile was created to meet + *

+ */ + public StringDt getRequirements() { + if (myRequirements == null) { + myRequirements = new StringDt(); + } + return myRequirements; + } + + /** + * Sets the value(s) for requirements (Scope and Usage this profile is for) + * + *

+ * Definition: + * The Scope and Usage that this profile was created to meet + *

+ */ + public Profile setRequirements(StringDt theValue) { + myRequirements = theValue; + return this; + } + + /** + * Sets the value for requirements (Scope and Usage this profile is for) + * + *

+ * Definition: + * The Scope and Usage that this profile was created to meet + *

+ */ + public Profile setRequirements( String theString) { + myRequirements = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for fhirVersion (FHIR Version this profile targets). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version of the FHIR specification on which this profile is based + *

+ */ + public IdDt getFhirVersion() { + if (myFhirVersion == null) { + myFhirVersion = new IdDt(); + } + return myFhirVersion; + } + + /** + * Sets the value(s) for fhirVersion (FHIR Version this profile targets) + * + *

+ * Definition: + * The version of the FHIR specification on which this profile is based + *

+ */ + public Profile setFhirVersion(IdDt theValue) { + myFhirVersion = theValue; + return this; + } + + /** + * Sets the value for fhirVersion (FHIR Version this profile targets) + * + *

+ * Definition: + * The version of the FHIR specification on which this profile is based + *

+ */ + public Profile setFhirVersion( String theId) { + myFhirVersion = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for mapping (External specification that the content is mapped to). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An external specification that the content is mapped to + *

+ */ + public java.util.List getMapping() { + if (myMapping == null) { + myMapping = new java.util.ArrayList(); + } + return myMapping; + } + + /** + * Sets the value(s) for mapping (External specification that the content is mapped to) + * + *

+ * Definition: + * An external specification that the content is mapped to + *

+ */ + public Profile setMapping(java.util.List theValue) { + myMapping = theValue; + return this; + } + + /** + * Adds and returns a new value for mapping (External specification that the content is mapped to) + * + *

+ * Definition: + * An external specification that the content is mapped to + *

+ */ + public Mapping addMapping() { + Mapping newType = new Mapping(); + getMapping().add(newType); + return newType; + } + + /** + * Gets the first repetition for mapping (External specification that the content is mapped to), + * creating it if it does not already exist. + * + *

+ * Definition: + * An external specification that the content is mapped to + *

+ */ + public Mapping getMappingFirstRep() { + if (getMapping().isEmpty()) { + return addMapping(); + } + return getMapping().get(0); + } + + /** + * Gets the value(s) for structure (A constraint on a resource or a data type). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A constraint statement about what contents a resource or data type may have + *

+ */ + public java.util.List getStructure() { + if (myStructure == null) { + myStructure = new java.util.ArrayList(); + } + return myStructure; + } + + /** + * Sets the value(s) for structure (A constraint on a resource or a data type) + * + *

+ * Definition: + * A constraint statement about what contents a resource or data type may have + *

+ */ + public Profile setStructure(java.util.List theValue) { + myStructure = theValue; + return this; + } + + /** + * Adds and returns a new value for structure (A constraint on a resource or a data type) + * + *

+ * Definition: + * A constraint statement about what contents a resource or data type may have + *

+ */ + public Structure addStructure() { + Structure newType = new Structure(); + getStructure().add(newType); + return newType; + } + + /** + * Gets the first repetition for structure (A constraint on a resource or a data type), + * creating it if it does not already exist. + * + *

+ * Definition: + * A constraint statement about what contents a resource or data type may have + *

+ */ + public Structure getStructureFirstRep() { + if (getStructure().isEmpty()) { + return addStructure(); + } + return getStructure().get(0); + } + + /** + * Gets the value(s) for extensionDefn (Definition of an extension). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An extension defined as part of the profile + *

+ */ + public java.util.List getExtensionDefn() { + if (myExtensionDefn == null) { + myExtensionDefn = new java.util.ArrayList(); + } + return myExtensionDefn; + } + + /** + * Sets the value(s) for extensionDefn (Definition of an extension) + * + *

+ * Definition: + * An extension defined as part of the profile + *

+ */ + public Profile setExtensionDefn(java.util.List theValue) { + myExtensionDefn = theValue; + return this; + } + + /** + * Adds and returns a new value for extensionDefn (Definition of an extension) + * + *

+ * Definition: + * An extension defined as part of the profile + *

+ */ + public ExtensionDefn addExtensionDefn() { + ExtensionDefn newType = new ExtensionDefn(); + getExtensionDefn().add(newType); + return newType; + } + + /** + * Gets the first repetition for extensionDefn (Definition of an extension), + * creating it if it does not already exist. + * + *

+ * Definition: + * An extension defined as part of the profile + *

+ */ + public ExtensionDefn getExtensionDefnFirstRep() { + if (getExtensionDefn().isEmpty()) { + return addExtensionDefn(); + } + return getExtensionDefn().get(0); + } + + /** + * Gets the value(s) for query (Definition of a named query). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public java.util.List getQuery() { + if (myQuery == null) { + myQuery = new java.util.ArrayList(); + } + return myQuery; + } + + /** + * Sets the value(s) for query (Definition of a named query) + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public Profile setQuery(java.util.List theValue) { + myQuery = theValue; + return this; + } + + /** + * Adds and returns a new value for query (Definition of a named query) + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public Query addQuery() { + Query newType = new Query(); + getQuery().add(newType); + return newType; + } + + /** + * Gets the first repetition for query (Definition of a named query), + * creating it if it does not already exist. + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + public Query getQueryFirstRep() { + if (getQuery().isEmpty()) { + return addQuery(); + } + return getQuery().get(0); + } + + /** + * Block class for child element: Profile.mapping (External specification that the content is mapped to) + * + *

+ * Definition: + * An external specification that the content is mapped to + *

+ */ + @Block() + public static class Mapping extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="identity", type=IdDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Internal id when this mapping is used", + formalDefinition="An Internal id that is used to identify this mapping set when specific mappings are made" + ) + private IdDt myIdentity; + + @Child(name="uri", type=UriDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Identifies what this mapping refers to", + formalDefinition="A URI that identifies the specification that this mapping is expressed to" + ) + private UriDt myUri; + + @Child(name="name", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Names what this mapping refers to", + formalDefinition="A name for the specification that is being mapped to" + ) + private StringDt myName; + + @Child(name="comments", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Versions, Issues, Scope limitations etc", + formalDefinition="Comments about this mapping, including version notes, issues, scope limitations, and other important notes for usage" + ) + private StringDt myComments; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myIdentity, myUri, myName, myComments); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myIdentity, myUri, myName, myComments); + } + + /** + * Gets the value(s) for identity (Internal id when this mapping is used). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An Internal id that is used to identify this mapping set when specific mappings are made + *

+ */ + public IdDt getIdentity() { + if (myIdentity == null) { + myIdentity = new IdDt(); + } + return myIdentity; + } + + /** + * Sets the value(s) for identity (Internal id when this mapping is used) + * + *

+ * Definition: + * An Internal id that is used to identify this mapping set when specific mappings are made + *

+ */ + public Mapping setIdentity(IdDt theValue) { + myIdentity = theValue; + return this; + } + + /** + * Sets the value for identity (Internal id when this mapping is used) + * + *

+ * Definition: + * An Internal id that is used to identify this mapping set when specific mappings are made + *

+ */ + public Mapping setIdentity( String theId) { + myIdentity = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for uri (Identifies what this mapping refers to). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A URI that identifies the specification that this mapping is expressed to + *

+ */ + public UriDt getUri() { + if (myUri == null) { + myUri = new UriDt(); + } + return myUri; + } + + /** + * Sets the value(s) for uri (Identifies what this mapping refers to) + * + *

+ * Definition: + * A URI that identifies the specification that this mapping is expressed to + *

+ */ + public Mapping setUri(UriDt theValue) { + myUri = theValue; + return this; + } + + /** + * Sets the value for uri (Identifies what this mapping refers to) + * + *

+ * Definition: + * A URI that identifies the specification that this mapping is expressed to + *

+ */ + public Mapping setUri( String theUri) { + myUri = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for name (Names what this mapping refers to). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A name for the specification that is being mapped to + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Names what this mapping refers to) + * + *

+ * Definition: + * A name for the specification that is being mapped to + *

+ */ + public Mapping setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Names what this mapping refers to) + * + *

+ * Definition: + * A name for the specification that is being mapped to + *

+ */ + public Mapping setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for comments (Versions, Issues, Scope limitations etc). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Comments about this mapping, including version notes, issues, scope limitations, and other important notes for usage + *

+ */ + public StringDt getComments() { + if (myComments == null) { + myComments = new StringDt(); + } + return myComments; + } + + /** + * Sets the value(s) for comments (Versions, Issues, Scope limitations etc) + * + *

+ * Definition: + * Comments about this mapping, including version notes, issues, scope limitations, and other important notes for usage + *

+ */ + public Mapping setComments(StringDt theValue) { + myComments = theValue; + return this; + } + + /** + * Sets the value for comments (Versions, Issues, Scope limitations etc) + * + *

+ * Definition: + * Comments about this mapping, including version notes, issues, scope limitations, and other important notes for usage + *

+ */ + public Mapping setComments( String theString) { + myComments = new StringDt(theString); + return this; + } + + + + } + + + /** + * Block class for child element: Profile.structure (A constraint on a resource or a data type) + * + *

+ * Definition: + * A constraint statement about what contents a resource or data type may have + *

+ */ + @Block() + public static class Structure extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="type", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="The Resource or Data Type being described", + formalDefinition="The Resource or Data type being described" + ) + private BoundCodeDt myType; + + @Child(name="name", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Name for this particular structure (reference target)", + formalDefinition="The name of this resource constraint statement (to refer to it from other resource constraints - from Profile.structure.element.definition.type.profile)" + ) + private StringDt myName; + + @Child(name="publish", type=BooleanDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="This definition is published (i.e. for validation)", + formalDefinition="This definition of a profile on a structure is published as a formal statement. Some structural definitions might be defined purely for internal use within the profile, and not intended to be used outside that context" + ) + private BooleanDt myPublish; + + @Child(name="purpose", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Human summary: why describe this resource?", + formalDefinition="Human summary: why describe this resource?" + ) + private StringDt myPurpose; + + @Child(name="element", order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Definition of elements in the resource (if no profile)", + formalDefinition="Captures constraints on each element within the resource" + ) + private java.util.List myElement; + + @Child(name="searchParam", order=5, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Search params defined", + formalDefinition="Additional search parameters for implementations to support and/or make use of" + ) + private java.util.List mySearchParam; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myType, myName, myPublish, myPurpose, myElement, mySearchParam); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myType, myName, myPublish, myPurpose, myElement, mySearchParam); + } + + /** + * Gets the value(s) for type (The Resource or Data Type being described). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The Resource or Data type being described + *

+ */ + public BoundCodeDt getType() { + if (myType == null) { + myType = new BoundCodeDt(FHIRDefinedTypeEnum.VALUESET_BINDER); + } + return myType; + } + + /** + * Sets the value(s) for type (The Resource or Data Type being described) + * + *

+ * Definition: + * The Resource or Data type being described + *

+ */ + public Structure setType(BoundCodeDt theValue) { + myType = theValue; + return this; + } + + /** + * Sets the value(s) for type (The Resource or Data Type being described) + * + *

+ * Definition: + * The Resource or Data type being described + *

+ */ + public Structure setType(FHIRDefinedTypeEnum theValue) { + getType().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for name (Name for this particular structure (reference target)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of this resource constraint statement (to refer to it from other resource constraints - from Profile.structure.element.definition.type.profile) + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Name for this particular structure (reference target)) + * + *

+ * Definition: + * The name of this resource constraint statement (to refer to it from other resource constraints - from Profile.structure.element.definition.type.profile) + *

+ */ + public Structure setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Name for this particular structure (reference target)) + * + *

+ * Definition: + * The name of this resource constraint statement (to refer to it from other resource constraints - from Profile.structure.element.definition.type.profile) + *

+ */ + public Structure setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for publish (This definition is published (i.e. for validation)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * This definition of a profile on a structure is published as a formal statement. Some structural definitions might be defined purely for internal use within the profile, and not intended to be used outside that context + *

+ */ + public BooleanDt getPublish() { + if (myPublish == null) { + myPublish = new BooleanDt(); + } + return myPublish; + } + + /** + * Sets the value(s) for publish (This definition is published (i.e. for validation)) + * + *

+ * Definition: + * This definition of a profile on a structure is published as a formal statement. Some structural definitions might be defined purely for internal use within the profile, and not intended to be used outside that context + *

+ */ + public Structure setPublish(BooleanDt theValue) { + myPublish = theValue; + return this; + } + + /** + * Sets the value for publish (This definition is published (i.e. for validation)) + * + *

+ * Definition: + * This definition of a profile on a structure is published as a formal statement. Some structural definitions might be defined purely for internal use within the profile, and not intended to be used outside that context + *

+ */ + public Structure setPublish( boolean theBoolean) { + myPublish = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for purpose (Human summary: why describe this resource?). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Human summary: why describe this resource? + *

+ */ + public StringDt getPurpose() { + if (myPurpose == null) { + myPurpose = new StringDt(); + } + return myPurpose; + } + + /** + * Sets the value(s) for purpose (Human summary: why describe this resource?) + * + *

+ * Definition: + * Human summary: why describe this resource? + *

+ */ + public Structure setPurpose(StringDt theValue) { + myPurpose = theValue; + return this; + } + + /** + * Sets the value for purpose (Human summary: why describe this resource?) + * + *

+ * Definition: + * Human summary: why describe this resource? + *

+ */ + public Structure setPurpose( String theString) { + myPurpose = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for element (Definition of elements in the resource (if no profile)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Captures constraints on each element within the resource + *

+ */ + public java.util.List getElement() { + if (myElement == null) { + myElement = new java.util.ArrayList(); + } + return myElement; + } + + /** + * Sets the value(s) for element (Definition of elements in the resource (if no profile)) + * + *

+ * Definition: + * Captures constraints on each element within the resource + *

+ */ + public Structure setElement(java.util.List theValue) { + myElement = theValue; + return this; + } + + /** + * Adds and returns a new value for element (Definition of elements in the resource (if no profile)) + * + *

+ * Definition: + * Captures constraints on each element within the resource + *

+ */ + public StructureElement addElement() { + StructureElement newType = new StructureElement(); + getElement().add(newType); + return newType; + } + + /** + * Gets the first repetition for element (Definition of elements in the resource (if no profile)), + * creating it if it does not already exist. + * + *

+ * Definition: + * Captures constraints on each element within the resource + *

+ */ + public StructureElement getElementFirstRep() { + if (getElement().isEmpty()) { + return addElement(); + } + return getElement().get(0); + } + + /** + * Gets the value(s) for searchParam (Search params defined). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public java.util.List getSearchParam() { + if (mySearchParam == null) { + mySearchParam = new java.util.ArrayList(); + } + return mySearchParam; + } + + /** + * Sets the value(s) for searchParam (Search params defined) + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public Structure setSearchParam(java.util.List theValue) { + mySearchParam = theValue; + return this; + } + + /** + * Adds and returns a new value for searchParam (Search params defined) + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public StructureSearchParam addSearchParam() { + StructureSearchParam newType = new StructureSearchParam(); + getSearchParam().add(newType); + return newType; + } + + /** + * Gets the first repetition for searchParam (Search params defined), + * creating it if it does not already exist. + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + public StructureSearchParam getSearchParamFirstRep() { + if (getSearchParam().isEmpty()) { + return addSearchParam(); + } + return getSearchParam().get(0); + } + + + } + + /** + * Block class for child element: Profile.structure.element (Definition of elements in the resource (if no profile)) + * + *

+ * Definition: + * Captures constraints on each element within the resource + *

+ */ + @Block() + public static class StructureElement extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="path", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="The path of the element (see the formal definitions)", + formalDefinition="The path identifies the element and is expressed as a \".\"-separated list of ancestor elements, beginning with the name of the resource" + ) + private StringDt myPath; + + @Child(name="representation", type=CodeDt.class, order=1, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="How this element is represented in instances", + formalDefinition="Codes that define how this element is represented in instances, when the deviation varies from the normal case" + ) + private java.util.List> myRepresentation; + + @Child(name="name", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Name for this particular element definition (reference target)", + formalDefinition="The name of this element definition (to refer to it from other element definitions using Profile.structure.element.definition.nameReference). This is a unique name referring to a specific set of constraints applied to this element. One use of this is to provide a name to different slices of the same element" + ) + private StringDt myName; + + @Child(name="slicing", order=3, min=0, max=1) + @Description( + shortDefinition="This element is sliced - slices follow", + formalDefinition="Indicates that the element is sliced into a set of alternative definitions (there are multiple definitions on a single element in the base resource). The set of slices is any elements that come after this in the element sequence that have the same path, until a shorter path occurs (the shorter path terminates the set)" + ) + private StructureElementSlicing mySlicing; + + @Child(name="definition", order=4, min=0, max=1) + @Description( + shortDefinition="More specific definition of the element", + formalDefinition="Definition of the content of the element to provide a more specific definition than that contained for the element in the base resource" + ) + private StructureElementDefinition myDefinition; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myPath, myRepresentation, myName, mySlicing, myDefinition); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myPath, myRepresentation, myName, mySlicing, myDefinition); + } + + /** + * Gets the value(s) for path (The path of the element (see the formal definitions)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The path identifies the element and is expressed as a \".\"-separated list of ancestor elements, beginning with the name of the resource + *

+ */ + public StringDt getPath() { + if (myPath == null) { + myPath = new StringDt(); + } + return myPath; + } + + /** + * Sets the value(s) for path (The path of the element (see the formal definitions)) + * + *

+ * Definition: + * The path identifies the element and is expressed as a \".\"-separated list of ancestor elements, beginning with the name of the resource + *

+ */ + public StructureElement setPath(StringDt theValue) { + myPath = theValue; + return this; + } + + /** + * Sets the value for path (The path of the element (see the formal definitions)) + * + *

+ * Definition: + * The path identifies the element and is expressed as a \".\"-separated list of ancestor elements, beginning with the name of the resource + *

+ */ + public StructureElement setPath( String theString) { + myPath = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for representation (How this element is represented in instances). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Codes that define how this element is represented in instances, when the deviation varies from the normal case + *

+ */ + public java.util.List> getRepresentation() { + if (myRepresentation == null) { + myRepresentation = new java.util.ArrayList>(); + } + return myRepresentation; + } + + /** + * Sets the value(s) for representation (How this element is represented in instances) + * + *

+ * Definition: + * Codes that define how this element is represented in instances, when the deviation varies from the normal case + *

+ */ + public StructureElement setRepresentation(java.util.List> theValue) { + myRepresentation = theValue; + return this; + } + + /** + * Add a value for representation (How this element is represented in instances) using an enumerated type. This + * is intended as a convenience method for situations where the FHIR defined ValueSets are mandatory + * or contain the desirable codes. If you wish to use codes other than those which are built-in, + * you may also use the {@link #addType()} method. + * + *

+ * Definition: + * Codes that define how this element is represented in instances, when the deviation varies from the normal case + *

+ */ + public BoundCodeDt addRepresentation(PropertyRepresentationEnum theValue) { + BoundCodeDt retVal = new BoundCodeDt(PropertyRepresentationEnum.VALUESET_BINDER, theValue); + getRepresentation().add(retVal); + return retVal; + } + + /** + * Gets the first repetition for representation (How this element is represented in instances), + * creating it if it does not already exist. + * + *

+ * Definition: + * Codes that define how this element is represented in instances, when the deviation varies from the normal case + *

+ */ + public BoundCodeDt getRepresentationFirstRep() { + if (getRepresentation().size() == 0) { + addRepresentation(); + } + return getRepresentation().get(0); + } + + /** + * Add a value for representation (How this element is represented in instances) + * + *

+ * Definition: + * Codes that define how this element is represented in instances, when the deviation varies from the normal case + *

+ */ + public BoundCodeDt addRepresentation() { + BoundCodeDt retVal = new BoundCodeDt(PropertyRepresentationEnum.VALUESET_BINDER); + getRepresentation().add(retVal); + return retVal; + } + + /** + * Sets the value(s), and clears any existing value(s) for representation (How this element is represented in instances) + * + *

+ * Definition: + * Codes that define how this element is represented in instances, when the deviation varies from the normal case + *

+ */ + public StructureElement setRepresentation(PropertyRepresentationEnum theValue) { + getRepresentation().clear(); + addRepresentation(theValue); + return this; + } + + + /** + * Gets the value(s) for name (Name for this particular element definition (reference target)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of this element definition (to refer to it from other element definitions using Profile.structure.element.definition.nameReference). This is a unique name referring to a specific set of constraints applied to this element. One use of this is to provide a name to different slices of the same element + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Name for this particular element definition (reference target)) + * + *

+ * Definition: + * The name of this element definition (to refer to it from other element definitions using Profile.structure.element.definition.nameReference). This is a unique name referring to a specific set of constraints applied to this element. One use of this is to provide a name to different slices of the same element + *

+ */ + public StructureElement setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Name for this particular element definition (reference target)) + * + *

+ * Definition: + * The name of this element definition (to refer to it from other element definitions using Profile.structure.element.definition.nameReference). This is a unique name referring to a specific set of constraints applied to this element. One use of this is to provide a name to different slices of the same element + *

+ */ + public StructureElement setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for slicing (This element is sliced - slices follow). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates that the element is sliced into a set of alternative definitions (there are multiple definitions on a single element in the base resource). The set of slices is any elements that come after this in the element sequence that have the same path, until a shorter path occurs (the shorter path terminates the set) + *

+ */ + public StructureElementSlicing getSlicing() { + if (mySlicing == null) { + mySlicing = new StructureElementSlicing(); + } + return mySlicing; + } + + /** + * Sets the value(s) for slicing (This element is sliced - slices follow) + * + *

+ * Definition: + * Indicates that the element is sliced into a set of alternative definitions (there are multiple definitions on a single element in the base resource). The set of slices is any elements that come after this in the element sequence that have the same path, until a shorter path occurs (the shorter path terminates the set) + *

+ */ + public StructureElement setSlicing(StructureElementSlicing theValue) { + mySlicing = theValue; + return this; + } + + + /** + * Gets the value(s) for definition (More specific definition of the element). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Definition of the content of the element to provide a more specific definition than that contained for the element in the base resource + *

+ */ + public StructureElementDefinition getDefinition() { + if (myDefinition == null) { + myDefinition = new StructureElementDefinition(); + } + return myDefinition; + } + + /** + * Sets the value(s) for definition (More specific definition of the element) + * + *

+ * Definition: + * Definition of the content of the element to provide a more specific definition than that contained for the element in the base resource + *

+ */ + public StructureElement setDefinition(StructureElementDefinition theValue) { + myDefinition = theValue; + return this; + } + + + + } + + /** + * Block class for child element: Profile.structure.element.slicing (This element is sliced - slices follow) + * + *

+ * Definition: + * Indicates that the element is sliced into a set of alternative definitions (there are multiple definitions on a single element in the base resource). The set of slices is any elements that come after this in the element sequence that have the same path, until a shorter path occurs (the shorter path terminates the set) + *

+ */ + @Block() + public static class StructureElementSlicing extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="discriminator", type=IdDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Element that used to distinguish the slices", + formalDefinition="Designates which child element is used to discriminate between the slices when processing an instance. The value of the child element in the instance SHALL completely distinguish which slice the element in the resource matches based on the allowed values for that element in each of the slices" + ) + private IdDt myDiscriminator; + + @Child(name="ordered", type=BooleanDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="If elements must be in same order as slices", + formalDefinition="If the matching elements have to occur in the same order as defined in the profile" + ) + private BooleanDt myOrdered; + + @Child(name="rules", type=CodeDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="closed | open | openAtEnd", + formalDefinition="Whether additional slices are allowed or not. When the slices are ordered, profile authors can also say that additional slices are only allowed at the end" + ) + private BoundCodeDt myRules; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myDiscriminator, myOrdered, myRules); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myDiscriminator, myOrdered, myRules); + } + + /** + * Gets the value(s) for discriminator (Element that used to distinguish the slices). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Designates which child element is used to discriminate between the slices when processing an instance. The value of the child element in the instance SHALL completely distinguish which slice the element in the resource matches based on the allowed values for that element in each of the slices + *

+ */ + public IdDt getDiscriminator() { + if (myDiscriminator == null) { + myDiscriminator = new IdDt(); + } + return myDiscriminator; + } + + /** + * Sets the value(s) for discriminator (Element that used to distinguish the slices) + * + *

+ * Definition: + * Designates which child element is used to discriminate between the slices when processing an instance. The value of the child element in the instance SHALL completely distinguish which slice the element in the resource matches based on the allowed values for that element in each of the slices + *

+ */ + public StructureElementSlicing setDiscriminator(IdDt theValue) { + myDiscriminator = theValue; + return this; + } + + /** + * Sets the value for discriminator (Element that used to distinguish the slices) + * + *

+ * Definition: + * Designates which child element is used to discriminate between the slices when processing an instance. The value of the child element in the instance SHALL completely distinguish which slice the element in the resource matches based on the allowed values for that element in each of the slices + *

+ */ + public StructureElementSlicing setDiscriminator( String theId) { + myDiscriminator = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for ordered (If elements must be in same order as slices). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * If the matching elements have to occur in the same order as defined in the profile + *

+ */ + public BooleanDt getOrdered() { + if (myOrdered == null) { + myOrdered = new BooleanDt(); + } + return myOrdered; + } + + /** + * Sets the value(s) for ordered (If elements must be in same order as slices) + * + *

+ * Definition: + * If the matching elements have to occur in the same order as defined in the profile + *

+ */ + public StructureElementSlicing setOrdered(BooleanDt theValue) { + myOrdered = theValue; + return this; + } + + /** + * Sets the value for ordered (If elements must be in same order as slices) + * + *

+ * Definition: + * If the matching elements have to occur in the same order as defined in the profile + *

+ */ + public StructureElementSlicing setOrdered( boolean theBoolean) { + myOrdered = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for rules (closed | open | openAtEnd). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Whether additional slices are allowed or not. When the slices are ordered, profile authors can also say that additional slices are only allowed at the end + *

+ */ + public BoundCodeDt getRules() { + if (myRules == null) { + myRules = new BoundCodeDt(SlicingRulesEnum.VALUESET_BINDER); + } + return myRules; + } + + /** + * Sets the value(s) for rules (closed | open | openAtEnd) + * + *

+ * Definition: + * Whether additional slices are allowed or not. When the slices are ordered, profile authors can also say that additional slices are only allowed at the end + *

+ */ + public StructureElementSlicing setRules(BoundCodeDt theValue) { + myRules = theValue; + return this; + } + + /** + * Sets the value(s) for rules (closed | open | openAtEnd) + * + *

+ * Definition: + * Whether additional slices are allowed or not. When the slices are ordered, profile authors can also say that additional slices are only allowed at the end + *

+ */ + public StructureElementSlicing setRules(SlicingRulesEnum theValue) { + getRules().setValueAsEnum(theValue); + return this; + } + + + + } + + + /** + * Block class for child element: Profile.structure.element.definition (More specific definition of the element) + * + *

+ * Definition: + * Definition of the content of the element to provide a more specific definition than that contained for the element in the base resource + *

+ */ + @Block() + public static class StructureElementDefinition extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="short", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Concise definition for xml presentation", + formalDefinition="A concise definition that is shown in the generated XML format that summarizes profiles (used throughout the specification)" + ) + private StringDt myShort; + + @Child(name="formal", type=StringDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="Full formal definition in human language", + formalDefinition="The definition SHALL be consistent with the base definition, but convey the meaning of the element in the particular context of use of the resource" + ) + private StringDt myFormal; + + @Child(name="comments", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Comments about the use of this element", + formalDefinition="Comments about the use of the element, including notes about how to use the data properly, exceptions to proper use, etc." + ) + private StringDt myComments; + + @Child(name="requirements", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Why is this needed?", + formalDefinition="Explains why this element is needed and why it's been constrained as it has" + ) + private StringDt myRequirements; + + @Child(name="synonym", type=StringDt.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Other names", + formalDefinition="Identifies additional names by which this element might also be known" + ) + private java.util.List mySynonym; + + @Child(name="min", type=IntegerDt.class, order=5, min=1, max=1) + @Description( + shortDefinition="Minimum Cardinality", + formalDefinition="The minimum number of times this element SHALL appear in the instance" + ) + private IntegerDt myMin; + + @Child(name="max", type=StringDt.class, order=6, min=1, max=1) + @Description( + shortDefinition="Maximum Cardinality (a number or *)", + formalDefinition="The maximum number of times this element is permitted to appear in the instance" + ) + private StringDt myMax; + + @Child(name="type", order=7, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Data type and Profile for this element", + formalDefinition="The data type or resource that the value of this element is permitted to be" + ) + private java.util.List myType; + + @Child(name="nameReference", type=StringDt.class, order=8, min=0, max=1) + @Description( + shortDefinition="To another element constraint (by element.name)", + formalDefinition="Identifies the name of a slice defined elsewhere in the profile whose constraints should be applied to the current element" + ) + private StringDt myNameReference; + + @Child(name="value", type=IDatatype.class, order=9, min=0, max=1) + @Description( + shortDefinition="Fixed value: [as defined for a primitive type]", + formalDefinition="Specifies a primitive value that SHALL hold for this element in the instance" + ) + private IDatatype myValue; + + @Child(name="example", type=IDatatype.class, order=10, min=0, max=1) + @Description( + shortDefinition="Example value: [as defined for type]", + formalDefinition="An example value for this element" + ) + private IDatatype myExample; + + @Child(name="maxLength", type=IntegerDt.class, order=11, min=0, max=1) + @Description( + shortDefinition="Length for strings", + formalDefinition="Indicates the shortest length that SHALL be supported by conformant instances without truncation" + ) + private IntegerDt myMaxLength; + + @Child(name="condition", type=IdDt.class, order=12, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Reference to invariant about presence", + formalDefinition="A reference to an invariant that may make additional statements about the cardinality or value in the instance" + ) + private java.util.List myCondition; + + @Child(name="constraint", order=13, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Condition that must evaluate to true", + formalDefinition="Formal constraints such as co-occurrence and other constraints that can be computationally evaluated within the context of the instance" + ) + private java.util.List myConstraint; + + @Child(name="mustSupport", type=BooleanDt.class, order=14, min=0, max=1) + @Description( + shortDefinition="If the element must supported", + formalDefinition="If true, conformant resource authors SHALL be capable of providing a value for the element and resource consumers SHALL be capable of extracting and doing something useful with the data element. If false, the element may be ignored and not supported" + ) + private BooleanDt myMustSupport; + + @Child(name="isModifier", type=BooleanDt.class, order=15, min=1, max=1) + @Description( + shortDefinition="If this modifies the meaning of other elements", + formalDefinition="If true, the value of this element affects the interpretation of the element or resource that contains it, and the value of the element cannot be ignored. Typically, this is used for status, negation and qualification codes. The effect of this is that the element cannot be ignored by systems: they SHALL either recognize the element and process it, and/or a pre-determination has been made that it is not relevant to their particular system." + ) + private BooleanDt myIsModifier; + + @Child(name="binding", order=16, min=0, max=1) + @Description( + shortDefinition="ValueSet details if this is coded", + formalDefinition="Binds to a value set if this element is coded (code, Coding, CodeableConcept)" + ) + private StructureElementDefinitionBinding myBinding; + + @Child(name="mapping", order=17, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Map element to another set of definitions", + formalDefinition="Identifies a concept from an external specification that roughly corresponds to this element" + ) + private java.util.List myMapping; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myShort, myFormal, myComments, myRequirements, mySynonym, myMin, myMax, myType, myNameReference, myValue, myExample, myMaxLength, myCondition, myConstraint, myMustSupport, myIsModifier, myBinding, myMapping); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myShort, myFormal, myComments, myRequirements, mySynonym, myMin, myMax, myType, myNameReference, myValue, myExample, myMaxLength, myCondition, myConstraint, myMustSupport, myIsModifier, myBinding, myMapping); + } + + /** + * Gets the value(s) for short (Concise definition for xml presentation). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A concise definition that is shown in the generated XML format that summarizes profiles (used throughout the specification) + *

+ */ + public StringDt getShort() { + if (myShort == null) { + myShort = new StringDt(); + } + return myShort; + } + + /** + * Sets the value(s) for short (Concise definition for xml presentation) + * + *

+ * Definition: + * A concise definition that is shown in the generated XML format that summarizes profiles (used throughout the specification) + *

+ */ + public StructureElementDefinition setShort(StringDt theValue) { + myShort = theValue; + return this; + } + + /** + * Sets the value for short (Concise definition for xml presentation) + * + *

+ * Definition: + * A concise definition that is shown in the generated XML format that summarizes profiles (used throughout the specification) + *

+ */ + public StructureElementDefinition setShort( String theString) { + myShort = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for formal (Full formal definition in human language). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The definition SHALL be consistent with the base definition, but convey the meaning of the element in the particular context of use of the resource + *

+ */ + public StringDt getFormal() { + if (myFormal == null) { + myFormal = new StringDt(); + } + return myFormal; + } + + /** + * Sets the value(s) for formal (Full formal definition in human language) + * + *

+ * Definition: + * The definition SHALL be consistent with the base definition, but convey the meaning of the element in the particular context of use of the resource + *

+ */ + public StructureElementDefinition setFormal(StringDt theValue) { + myFormal = theValue; + return this; + } + + /** + * Sets the value for formal (Full formal definition in human language) + * + *

+ * Definition: + * The definition SHALL be consistent with the base definition, but convey the meaning of the element in the particular context of use of the resource + *

+ */ + public StructureElementDefinition setFormal( String theString) { + myFormal = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for comments (Comments about the use of this element). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Comments about the use of the element, including notes about how to use the data properly, exceptions to proper use, etc. + *

+ */ + public StringDt getComments() { + if (myComments == null) { + myComments = new StringDt(); + } + return myComments; + } + + /** + * Sets the value(s) for comments (Comments about the use of this element) + * + *

+ * Definition: + * Comments about the use of the element, including notes about how to use the data properly, exceptions to proper use, etc. + *

+ */ + public StructureElementDefinition setComments(StringDt theValue) { + myComments = theValue; + return this; + } + + /** + * Sets the value for comments (Comments about the use of this element) + * + *

+ * Definition: + * Comments about the use of the element, including notes about how to use the data properly, exceptions to proper use, etc. + *

+ */ + public StructureElementDefinition setComments( String theString) { + myComments = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for requirements (Why is this needed?). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Explains why this element is needed and why it's been constrained as it has + *

+ */ + public StringDt getRequirements() { + if (myRequirements == null) { + myRequirements = new StringDt(); + } + return myRequirements; + } + + /** + * Sets the value(s) for requirements (Why is this needed?) + * + *

+ * Definition: + * Explains why this element is needed and why it's been constrained as it has + *

+ */ + public StructureElementDefinition setRequirements(StringDt theValue) { + myRequirements = theValue; + return this; + } + + /** + * Sets the value for requirements (Why is this needed?) + * + *

+ * Definition: + * Explains why this element is needed and why it's been constrained as it has + *

+ */ + public StructureElementDefinition setRequirements( String theString) { + myRequirements = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for synonym (Other names). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies additional names by which this element might also be known + *

+ */ + public java.util.List getSynonym() { + if (mySynonym == null) { + mySynonym = new java.util.ArrayList(); + } + return mySynonym; + } + + /** + * Sets the value(s) for synonym (Other names) + * + *

+ * Definition: + * Identifies additional names by which this element might also be known + *

+ */ + public StructureElementDefinition setSynonym(java.util.List theValue) { + mySynonym = theValue; + return this; + } + + /** + * Adds and returns a new value for synonym (Other names) + * + *

+ * Definition: + * Identifies additional names by which this element might also be known + *

+ */ + public StringDt addSynonym() { + StringDt newType = new StringDt(); + getSynonym().add(newType); + return newType; + } + + /** + * Gets the first repetition for synonym (Other names), + * creating it if it does not already exist. + * + *

+ * Definition: + * Identifies additional names by which this element might also be known + *

+ */ + public StringDt getSynonymFirstRep() { + if (getSynonym().isEmpty()) { + return addSynonym(); + } + return getSynonym().get(0); + } + /** + * Adds a new value for synonym (Other names) + * + *

+ * Definition: + * Identifies additional names by which this element might also be known + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public StructureElementDefinition addSynonym( String theString) { + if (mySynonym == null) { + mySynonym = new java.util.ArrayList(); + } + mySynonym.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for min (Minimum Cardinality). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The minimum number of times this element SHALL appear in the instance + *

+ */ + public IntegerDt getMin() { + if (myMin == null) { + myMin = new IntegerDt(); + } + return myMin; + } + + /** + * Sets the value(s) for min (Minimum Cardinality) + * + *

+ * Definition: + * The minimum number of times this element SHALL appear in the instance + *

+ */ + public StructureElementDefinition setMin(IntegerDt theValue) { + myMin = theValue; + return this; + } + + /** + * Sets the value for min (Minimum Cardinality) + * + *

+ * Definition: + * The minimum number of times this element SHALL appear in the instance + *

+ */ + public StructureElementDefinition setMin( int theInteger) { + myMin = new IntegerDt(theInteger); + return this; + } + + + /** + * Gets the value(s) for max (Maximum Cardinality (a number or *)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The maximum number of times this element is permitted to appear in the instance + *

+ */ + public StringDt getMax() { + if (myMax == null) { + myMax = new StringDt(); + } + return myMax; + } + + /** + * Sets the value(s) for max (Maximum Cardinality (a number or *)) + * + *

+ * Definition: + * The maximum number of times this element is permitted to appear in the instance + *

+ */ + public StructureElementDefinition setMax(StringDt theValue) { + myMax = theValue; + return this; + } + + /** + * Sets the value for max (Maximum Cardinality (a number or *)) + * + *

+ * Definition: + * The maximum number of times this element is permitted to appear in the instance + *

+ */ + public StructureElementDefinition setMax( String theString) { + myMax = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for type (Data type and Profile for this element). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The data type or resource that the value of this element is permitted to be + *

+ */ + public java.util.List getType() { + if (myType == null) { + myType = new java.util.ArrayList(); + } + return myType; + } + + /** + * Sets the value(s) for type (Data type and Profile for this element) + * + *

+ * Definition: + * The data type or resource that the value of this element is permitted to be + *

+ */ + public StructureElementDefinition setType(java.util.List theValue) { + myType = theValue; + return this; + } + + /** + * Adds and returns a new value for type (Data type and Profile for this element) + * + *

+ * Definition: + * The data type or resource that the value of this element is permitted to be + *

+ */ + public StructureElementDefinitionType addType() { + StructureElementDefinitionType newType = new StructureElementDefinitionType(); + getType().add(newType); + return newType; + } + + /** + * Gets the first repetition for type (Data type and Profile for this element), + * creating it if it does not already exist. + * + *

+ * Definition: + * The data type or resource that the value of this element is permitted to be + *

+ */ + public StructureElementDefinitionType getTypeFirstRep() { + if (getType().isEmpty()) { + return addType(); + } + return getType().get(0); + } + + /** + * Gets the value(s) for nameReference (To another element constraint (by element.name)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the name of a slice defined elsewhere in the profile whose constraints should be applied to the current element + *

+ */ + public StringDt getNameReference() { + if (myNameReference == null) { + myNameReference = new StringDt(); + } + return myNameReference; + } + + /** + * Sets the value(s) for nameReference (To another element constraint (by element.name)) + * + *

+ * Definition: + * Identifies the name of a slice defined elsewhere in the profile whose constraints should be applied to the current element + *

+ */ + public StructureElementDefinition setNameReference(StringDt theValue) { + myNameReference = theValue; + return this; + } + + /** + * Sets the value for nameReference (To another element constraint (by element.name)) + * + *

+ * Definition: + * Identifies the name of a slice defined elsewhere in the profile whose constraints should be applied to the current element + *

+ */ + public StructureElementDefinition setNameReference( String theString) { + myNameReference = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for value[x] (Fixed value: [as defined for a primitive type]). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Specifies a primitive value that SHALL hold for this element in the instance + *

+ */ + public IDatatype getValue() { + return myValue; + } + + /** + * Sets the value(s) for value[x] (Fixed value: [as defined for a primitive type]) + * + *

+ * Definition: + * Specifies a primitive value that SHALL hold for this element in the instance + *

+ */ + public StructureElementDefinition setValue(IDatatype theValue) { + myValue = theValue; + return this; + } + + + /** + * Gets the value(s) for example[x] (Example value: [as defined for type]). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An example value for this element + *

+ */ + public IDatatype getExample() { + return myExample; + } + + /** + * Sets the value(s) for example[x] (Example value: [as defined for type]) + * + *

+ * Definition: + * An example value for this element + *

+ */ + public StructureElementDefinition setExample(IDatatype theValue) { + myExample = theValue; + return this; + } + + + /** + * Gets the value(s) for maxLength (Length for strings). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates the shortest length that SHALL be supported by conformant instances without truncation + *

+ */ + public IntegerDt getMaxLength() { + if (myMaxLength == null) { + myMaxLength = new IntegerDt(); + } + return myMaxLength; + } + + /** + * Sets the value(s) for maxLength (Length for strings) + * + *

+ * Definition: + * Indicates the shortest length that SHALL be supported by conformant instances without truncation + *

+ */ + public StructureElementDefinition setMaxLength(IntegerDt theValue) { + myMaxLength = theValue; + return this; + } + + /** + * Sets the value for maxLength (Length for strings) + * + *

+ * Definition: + * Indicates the shortest length that SHALL be supported by conformant instances without truncation + *

+ */ + public StructureElementDefinition setMaxLength( int theInteger) { + myMaxLength = new IntegerDt(theInteger); + return this; + } + + + /** + * Gets the value(s) for condition (Reference to invariant about presence). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A reference to an invariant that may make additional statements about the cardinality or value in the instance + *

+ */ + public java.util.List getCondition() { + if (myCondition == null) { + myCondition = new java.util.ArrayList(); + } + return myCondition; + } + + /** + * Sets the value(s) for condition (Reference to invariant about presence) + * + *

+ * Definition: + * A reference to an invariant that may make additional statements about the cardinality or value in the instance + *

+ */ + public StructureElementDefinition setCondition(java.util.List theValue) { + myCondition = theValue; + return this; + } + + /** + * Adds and returns a new value for condition (Reference to invariant about presence) + * + *

+ * Definition: + * A reference to an invariant that may make additional statements about the cardinality or value in the instance + *

+ */ + public IdDt addCondition() { + IdDt newType = new IdDt(); + getCondition().add(newType); + return newType; + } + + /** + * Gets the first repetition for condition (Reference to invariant about presence), + * creating it if it does not already exist. + * + *

+ * Definition: + * A reference to an invariant that may make additional statements about the cardinality or value in the instance + *

+ */ + public IdDt getConditionFirstRep() { + if (getCondition().isEmpty()) { + return addCondition(); + } + return getCondition().get(0); + } + /** + * Adds a new value for condition (Reference to invariant about presence) + * + *

+ * Definition: + * A reference to an invariant that may make additional statements about the cardinality or value in the instance + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public StructureElementDefinition addCondition( String theId) { + if (myCondition == null) { + myCondition = new java.util.ArrayList(); + } + myCondition.add(new IdDt(theId)); + return this; + } + + + /** + * Gets the value(s) for constraint (Condition that must evaluate to true). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Formal constraints such as co-occurrence and other constraints that can be computationally evaluated within the context of the instance + *

+ */ + public java.util.List getConstraint() { + if (myConstraint == null) { + myConstraint = new java.util.ArrayList(); + } + return myConstraint; + } + + /** + * Sets the value(s) for constraint (Condition that must evaluate to true) + * + *

+ * Definition: + * Formal constraints such as co-occurrence and other constraints that can be computationally evaluated within the context of the instance + *

+ */ + public StructureElementDefinition setConstraint(java.util.List theValue) { + myConstraint = theValue; + return this; + } + + /** + * Adds and returns a new value for constraint (Condition that must evaluate to true) + * + *

+ * Definition: + * Formal constraints such as co-occurrence and other constraints that can be computationally evaluated within the context of the instance + *

+ */ + public StructureElementDefinitionConstraint addConstraint() { + StructureElementDefinitionConstraint newType = new StructureElementDefinitionConstraint(); + getConstraint().add(newType); + return newType; + } + + /** + * Gets the first repetition for constraint (Condition that must evaluate to true), + * creating it if it does not already exist. + * + *

+ * Definition: + * Formal constraints such as co-occurrence and other constraints that can be computationally evaluated within the context of the instance + *

+ */ + public StructureElementDefinitionConstraint getConstraintFirstRep() { + if (getConstraint().isEmpty()) { + return addConstraint(); + } + return getConstraint().get(0); + } + + /** + * Gets the value(s) for mustSupport (If the element must supported). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * If true, conformant resource authors SHALL be capable of providing a value for the element and resource consumers SHALL be capable of extracting and doing something useful with the data element. If false, the element may be ignored and not supported + *

+ */ + public BooleanDt getMustSupport() { + if (myMustSupport == null) { + myMustSupport = new BooleanDt(); + } + return myMustSupport; + } + + /** + * Sets the value(s) for mustSupport (If the element must supported) + * + *

+ * Definition: + * If true, conformant resource authors SHALL be capable of providing a value for the element and resource consumers SHALL be capable of extracting and doing something useful with the data element. If false, the element may be ignored and not supported + *

+ */ + public StructureElementDefinition setMustSupport(BooleanDt theValue) { + myMustSupport = theValue; + return this; + } + + /** + * Sets the value for mustSupport (If the element must supported) + * + *

+ * Definition: + * If true, conformant resource authors SHALL be capable of providing a value for the element and resource consumers SHALL be capable of extracting and doing something useful with the data element. If false, the element may be ignored and not supported + *

+ */ + public StructureElementDefinition setMustSupport( boolean theBoolean) { + myMustSupport = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for isModifier (If this modifies the meaning of other elements). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * If true, the value of this element affects the interpretation of the element or resource that contains it, and the value of the element cannot be ignored. Typically, this is used for status, negation and qualification codes. The effect of this is that the element cannot be ignored by systems: they SHALL either recognize the element and process it, and/or a pre-determination has been made that it is not relevant to their particular system. + *

+ */ + public BooleanDt getIsModifier() { + if (myIsModifier == null) { + myIsModifier = new BooleanDt(); + } + return myIsModifier; + } + + /** + * Sets the value(s) for isModifier (If this modifies the meaning of other elements) + * + *

+ * Definition: + * If true, the value of this element affects the interpretation of the element or resource that contains it, and the value of the element cannot be ignored. Typically, this is used for status, negation and qualification codes. The effect of this is that the element cannot be ignored by systems: they SHALL either recognize the element and process it, and/or a pre-determination has been made that it is not relevant to their particular system. + *

+ */ + public StructureElementDefinition setIsModifier(BooleanDt theValue) { + myIsModifier = theValue; + return this; + } + + /** + * Sets the value for isModifier (If this modifies the meaning of other elements) + * + *

+ * Definition: + * If true, the value of this element affects the interpretation of the element or resource that contains it, and the value of the element cannot be ignored. Typically, this is used for status, negation and qualification codes. The effect of this is that the element cannot be ignored by systems: they SHALL either recognize the element and process it, and/or a pre-determination has been made that it is not relevant to their particular system. + *

+ */ + public StructureElementDefinition setIsModifier( boolean theBoolean) { + myIsModifier = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for binding (ValueSet details if this is coded). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Binds to a value set if this element is coded (code, Coding, CodeableConcept) + *

+ */ + public StructureElementDefinitionBinding getBinding() { + if (myBinding == null) { + myBinding = new StructureElementDefinitionBinding(); + } + return myBinding; + } + + /** + * Sets the value(s) for binding (ValueSet details if this is coded) + * + *

+ * Definition: + * Binds to a value set if this element is coded (code, Coding, CodeableConcept) + *

+ */ + public StructureElementDefinition setBinding(StructureElementDefinitionBinding theValue) { + myBinding = theValue; + return this; + } + + + /** + * Gets the value(s) for mapping (Map element to another set of definitions). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies a concept from an external specification that roughly corresponds to this element + *

+ */ + public java.util.List getMapping() { + if (myMapping == null) { + myMapping = new java.util.ArrayList(); + } + return myMapping; + } + + /** + * Sets the value(s) for mapping (Map element to another set of definitions) + * + *

+ * Definition: + * Identifies a concept from an external specification that roughly corresponds to this element + *

+ */ + public StructureElementDefinition setMapping(java.util.List theValue) { + myMapping = theValue; + return this; + } + + /** + * Adds and returns a new value for mapping (Map element to another set of definitions) + * + *

+ * Definition: + * Identifies a concept from an external specification that roughly corresponds to this element + *

+ */ + public StructureElementDefinitionMapping addMapping() { + StructureElementDefinitionMapping newType = new StructureElementDefinitionMapping(); + getMapping().add(newType); + return newType; + } + + /** + * Gets the first repetition for mapping (Map element to another set of definitions), + * creating it if it does not already exist. + * + *

+ * Definition: + * Identifies a concept from an external specification that roughly corresponds to this element + *

+ */ + public StructureElementDefinitionMapping getMappingFirstRep() { + if (getMapping().isEmpty()) { + return addMapping(); + } + return getMapping().get(0); + } + + + } + + /** + * Block class for child element: Profile.structure.element.definition.type (Data type and Profile for this element) + * + *

+ * Definition: + * The data type or resource that the value of this element is permitted to be + *

+ */ + @Block() + public static class StructureElementDefinitionType extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="code", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Name of Data type or Resource", + formalDefinition="" + ) + private BoundCodeDt myCode; + + @Child(name="profile", type=UriDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Profile.structure to apply", + formalDefinition="Identifies a profile that SHALL hold for resources or datatypes referenced as the type of this element. Can be a local reference - to another structure in this profile, or a reference to a structure in another profile" + ) + private UriDt myProfile; + + @Child(name="aggregation", type=CodeDt.class, order=2, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="contained | referenced | bundled - how aggregated", + formalDefinition="If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle" + ) + private java.util.List> myAggregation; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCode, myProfile, myAggregation); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCode, myProfile, myAggregation); + } + + /** + * Gets the value(s) for code (Name of Data type or Resource). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public BoundCodeDt getCode() { + if (myCode == null) { + myCode = new BoundCodeDt(DataTypeEnum.VALUESET_BINDER); + } + return myCode; + } + + /** + * Sets the value(s) for code (Name of Data type or Resource) + * + *

+ * Definition: + * + *

+ */ + public StructureElementDefinitionType setCode(BoundCodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value(s) for code (Name of Data type or Resource) + * + *

+ * Definition: + * + *

+ */ + public StructureElementDefinitionType setCode(DataTypeEnum theValue) { + getCode().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for profile (Profile.structure to apply). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies a profile that SHALL hold for resources or datatypes referenced as the type of this element. Can be a local reference - to another structure in this profile, or a reference to a structure in another profile + *

+ */ + public UriDt getProfile() { + if (myProfile == null) { + myProfile = new UriDt(); + } + return myProfile; + } + + /** + * Sets the value(s) for profile (Profile.structure to apply) + * + *

+ * Definition: + * Identifies a profile that SHALL hold for resources or datatypes referenced as the type of this element. Can be a local reference - to another structure in this profile, or a reference to a structure in another profile + *

+ */ + public StructureElementDefinitionType setProfile(UriDt theValue) { + myProfile = theValue; + return this; + } + + /** + * Sets the value for profile (Profile.structure to apply) + * + *

+ * Definition: + * Identifies a profile that SHALL hold for resources or datatypes referenced as the type of this element. Can be a local reference - to another structure in this profile, or a reference to a structure in another profile + *

+ */ + public StructureElementDefinitionType setProfile( String theUri) { + myProfile = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for aggregation (contained | referenced | bundled - how aggregated). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle + *

+ */ + public java.util.List> getAggregation() { + if (myAggregation == null) { + myAggregation = new java.util.ArrayList>(); + } + return myAggregation; + } + + /** + * Sets the value(s) for aggregation (contained | referenced | bundled - how aggregated) + * + *

+ * Definition: + * If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle + *

+ */ + public StructureElementDefinitionType setAggregation(java.util.List> theValue) { + myAggregation = theValue; + return this; + } + + /** + * Add a value for aggregation (contained | referenced | bundled - how aggregated) using an enumerated type. This + * is intended as a convenience method for situations where the FHIR defined ValueSets are mandatory + * or contain the desirable codes. If you wish to use codes other than those which are built-in, + * you may also use the {@link #addType()} method. + * + *

+ * Definition: + * If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle + *

+ */ + public BoundCodeDt addAggregation(AggregationModeEnum theValue) { + BoundCodeDt retVal = new BoundCodeDt(AggregationModeEnum.VALUESET_BINDER, theValue); + getAggregation().add(retVal); + return retVal; + } + + /** + * Gets the first repetition for aggregation (contained | referenced | bundled - how aggregated), + * creating it if it does not already exist. + * + *

+ * Definition: + * If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle + *

+ */ + public BoundCodeDt getAggregationFirstRep() { + if (getAggregation().size() == 0) { + addAggregation(); + } + return getAggregation().get(0); + } + + /** + * Add a value for aggregation (contained | referenced | bundled - how aggregated) + * + *

+ * Definition: + * If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle + *

+ */ + public BoundCodeDt addAggregation() { + BoundCodeDt retVal = new BoundCodeDt(AggregationModeEnum.VALUESET_BINDER); + getAggregation().add(retVal); + return retVal; + } + + /** + * Sets the value(s), and clears any existing value(s) for aggregation (contained | referenced | bundled - how aggregated) + * + *

+ * Definition: + * If the type is a reference to another resource, how the resource is or can be aggreated - is it a contained resource, or a reference, and if the context is a bundle, is it included in the bundle + *

+ */ + public StructureElementDefinitionType setAggregation(AggregationModeEnum theValue) { + getAggregation().clear(); + addAggregation(theValue); + return this; + } + + + + } + + + /** + * Block class for child element: Profile.structure.element.definition.constraint (Condition that must evaluate to true) + * + *

+ * Definition: + * Formal constraints such as co-occurrence and other constraints that can be computationally evaluated within the context of the instance + *

+ */ + @Block() + public static class StructureElementDefinitionConstraint extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="key", type=IdDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Target of 'condition' reference above", + formalDefinition="Allows identification of which elements have their cardinalities impacted by the constraint. Will not be referenced for constraints that do not affect cardinality" + ) + private IdDt myKey; + + @Child(name="name", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Short human label", + formalDefinition="Used to label the constraint in OCL or in short displays incapable of displaying the full human description" + ) + private StringDt myName; + + @Child(name="severity", type=CodeDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="error | warning", + formalDefinition="Identifies the impact constraint violation has on the conformance of the instance" + ) + private BoundCodeDt mySeverity; + + @Child(name="human", type=StringDt.class, order=3, min=1, max=1) + @Description( + shortDefinition="Human description of constraint", + formalDefinition="Text that can be used to describe the constraint in messages identifying that the constraint has been violated" + ) + private StringDt myHuman; + + @Child(name="xpath", type=StringDt.class, order=4, min=1, max=1) + @Description( + shortDefinition="XPath expression of constraint", + formalDefinition="XPath expression of constraint" + ) + private StringDt myXpath; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myKey, myName, mySeverity, myHuman, myXpath); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myKey, myName, mySeverity, myHuman, myXpath); + } + + /** + * Gets the value(s) for key (Target of 'condition' reference above). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Allows identification of which elements have their cardinalities impacted by the constraint. Will not be referenced for constraints that do not affect cardinality + *

+ */ + public IdDt getKey() { + if (myKey == null) { + myKey = new IdDt(); + } + return myKey; + } + + /** + * Sets the value(s) for key (Target of 'condition' reference above) + * + *

+ * Definition: + * Allows identification of which elements have their cardinalities impacted by the constraint. Will not be referenced for constraints that do not affect cardinality + *

+ */ + public StructureElementDefinitionConstraint setKey(IdDt theValue) { + myKey = theValue; + return this; + } + + /** + * Sets the value for key (Target of 'condition' reference above) + * + *

+ * Definition: + * Allows identification of which elements have their cardinalities impacted by the constraint. Will not be referenced for constraints that do not affect cardinality + *

+ */ + public StructureElementDefinitionConstraint setKey( String theId) { + myKey = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for name (Short human label). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Used to label the constraint in OCL or in short displays incapable of displaying the full human description + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Short human label) + * + *

+ * Definition: + * Used to label the constraint in OCL or in short displays incapable of displaying the full human description + *

+ */ + public StructureElementDefinitionConstraint setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Short human label) + * + *

+ * Definition: + * Used to label the constraint in OCL or in short displays incapable of displaying the full human description + *

+ */ + public StructureElementDefinitionConstraint setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for severity (error | warning). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the impact constraint violation has on the conformance of the instance + *

+ */ + public BoundCodeDt getSeverity() { + if (mySeverity == null) { + mySeverity = new BoundCodeDt(ConstraintSeverityEnum.VALUESET_BINDER); + } + return mySeverity; + } + + /** + * Sets the value(s) for severity (error | warning) + * + *

+ * Definition: + * Identifies the impact constraint violation has on the conformance of the instance + *

+ */ + public StructureElementDefinitionConstraint setSeverity(BoundCodeDt theValue) { + mySeverity = theValue; + return this; + } + + /** + * Sets the value(s) for severity (error | warning) + * + *

+ * Definition: + * Identifies the impact constraint violation has on the conformance of the instance + *

+ */ + public StructureElementDefinitionConstraint setSeverity(ConstraintSeverityEnum theValue) { + getSeverity().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for human (Human description of constraint). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Text that can be used to describe the constraint in messages identifying that the constraint has been violated + *

+ */ + public StringDt getHuman() { + if (myHuman == null) { + myHuman = new StringDt(); + } + return myHuman; + } + + /** + * Sets the value(s) for human (Human description of constraint) + * + *

+ * Definition: + * Text that can be used to describe the constraint in messages identifying that the constraint has been violated + *

+ */ + public StructureElementDefinitionConstraint setHuman(StringDt theValue) { + myHuman = theValue; + return this; + } + + /** + * Sets the value for human (Human description of constraint) + * + *

+ * Definition: + * Text that can be used to describe the constraint in messages identifying that the constraint has been violated + *

+ */ + public StructureElementDefinitionConstraint setHuman( String theString) { + myHuman = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for xpath (XPath expression of constraint). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * XPath expression of constraint + *

+ */ + public StringDt getXpath() { + if (myXpath == null) { + myXpath = new StringDt(); + } + return myXpath; + } + + /** + * Sets the value(s) for xpath (XPath expression of constraint) + * + *

+ * Definition: + * XPath expression of constraint + *

+ */ + public StructureElementDefinitionConstraint setXpath(StringDt theValue) { + myXpath = theValue; + return this; + } + + /** + * Sets the value for xpath (XPath expression of constraint) + * + *

+ * Definition: + * XPath expression of constraint + *

+ */ + public StructureElementDefinitionConstraint setXpath( String theString) { + myXpath = new StringDt(theString); + return this; + } + + + + } + + + /** + * Block class for child element: Profile.structure.element.definition.binding (ValueSet details if this is coded) + * + *

+ * Definition: + * Binds to a value set if this element is coded (code, Coding, CodeableConcept) + *

+ */ + @Block() + public static class StructureElementDefinitionBinding extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="name", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Descriptive Name", + formalDefinition="A descriptive name for this - can be useful for generating implementation artifacts" + ) + private StringDt myName; + + @Child(name="isExtensible", type=BooleanDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="Can additional codes be used?", + formalDefinition="If true, then conformant systems may use additional codes or (where the data type permits) text alone to convey concepts not covered by the set of codes identified in the binding. If false, then conformant systems are constrained to the provided codes alone" + ) + private BooleanDt myIsExtensible; + + @Child(name="conformance", type=CodeDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="required | preferred | example", + formalDefinition="Indicates the degree of conformance expectations associated with this binding" + ) + private BoundCodeDt myConformance; + + @Child(name="description", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Human explanation of the value set", + formalDefinition="Describes the intended use of this particular set of codes" + ) + private StringDt myDescription; + + @Child(name="reference", order=4, min=0, max=1, type={ + UriDt.class, ValueSet.class }) + @Description( + shortDefinition="Source of value set", + formalDefinition="Points to the value set or external definition that identifies the set of codes to be used" + ) + private IDatatype myReference; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myName, myIsExtensible, myConformance, myDescription, myReference); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myName, myIsExtensible, myConformance, myDescription, myReference); + } + + /** + * Gets the value(s) for name (Descriptive Name). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A descriptive name for this - can be useful for generating implementation artifacts + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Descriptive Name) + * + *

+ * Definition: + * A descriptive name for this - can be useful for generating implementation artifacts + *

+ */ + public StructureElementDefinitionBinding setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Descriptive Name) + * + *

+ * Definition: + * A descriptive name for this - can be useful for generating implementation artifacts + *

+ */ + public StructureElementDefinitionBinding setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for isExtensible (Can additional codes be used?). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * If true, then conformant systems may use additional codes or (where the data type permits) text alone to convey concepts not covered by the set of codes identified in the binding. If false, then conformant systems are constrained to the provided codes alone + *

+ */ + public BooleanDt getIsExtensible() { + if (myIsExtensible == null) { + myIsExtensible = new BooleanDt(); + } + return myIsExtensible; + } + + /** + * Sets the value(s) for isExtensible (Can additional codes be used?) + * + *

+ * Definition: + * If true, then conformant systems may use additional codes or (where the data type permits) text alone to convey concepts not covered by the set of codes identified in the binding. If false, then conformant systems are constrained to the provided codes alone + *

+ */ + public StructureElementDefinitionBinding setIsExtensible(BooleanDt theValue) { + myIsExtensible = theValue; + return this; + } + + /** + * Sets the value for isExtensible (Can additional codes be used?) + * + *

+ * Definition: + * If true, then conformant systems may use additional codes or (where the data type permits) text alone to convey concepts not covered by the set of codes identified in the binding. If false, then conformant systems are constrained to the provided codes alone + *

+ */ + public StructureElementDefinitionBinding setIsExtensible( boolean theBoolean) { + myIsExtensible = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for conformance (required | preferred | example). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Indicates the degree of conformance expectations associated with this binding + *

+ */ + public BoundCodeDt getConformance() { + if (myConformance == null) { + myConformance = new BoundCodeDt(BindingConformanceEnum.VALUESET_BINDER); + } + return myConformance; + } + + /** + * Sets the value(s) for conformance (required | preferred | example) + * + *

+ * Definition: + * Indicates the degree of conformance expectations associated with this binding + *

+ */ + public StructureElementDefinitionBinding setConformance(BoundCodeDt theValue) { + myConformance = theValue; + return this; + } + + /** + * Sets the value(s) for conformance (required | preferred | example) + * + *

+ * Definition: + * Indicates the degree of conformance expectations associated with this binding + *

+ */ + public StructureElementDefinitionBinding setConformance(BindingConformanceEnum theValue) { + getConformance().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for description (Human explanation of the value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Describes the intended use of this particular set of codes + *

+ */ + public StringDt getDescription() { + if (myDescription == null) { + myDescription = new StringDt(); + } + return myDescription; + } + + /** + * Sets the value(s) for description (Human explanation of the value set) + * + *

+ * Definition: + * Describes the intended use of this particular set of codes + *

+ */ + public StructureElementDefinitionBinding setDescription(StringDt theValue) { + myDescription = theValue; + return this; + } + + /** + * Sets the value for description (Human explanation of the value set) + * + *

+ * Definition: + * Describes the intended use of this particular set of codes + *

+ */ + public StructureElementDefinitionBinding setDescription( String theString) { + myDescription = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for reference[x] (Source of value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Points to the value set or external definition that identifies the set of codes to be used + *

+ */ + public IDatatype getReference() { + return myReference; + } + + /** + * Sets the value(s) for reference[x] (Source of value set) + * + *

+ * Definition: + * Points to the value set or external definition that identifies the set of codes to be used + *

+ */ + public StructureElementDefinitionBinding setReference(IDatatype theValue) { + myReference = theValue; + return this; + } + + + + } + + + /** + * Block class for child element: Profile.structure.element.definition.mapping (Map element to another set of definitions) + * + *

+ * Definition: + * Identifies a concept from an external specification that roughly corresponds to this element + *

+ */ + @Block() + public static class StructureElementDefinitionMapping extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="identity", type=IdDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Reference to mapping declaration", + formalDefinition="An internal reference to the definition of a mapping" + ) + private IdDt myIdentity; + + @Child(name="map", type=StringDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="Details of the mapping", + formalDefinition="Expresses what part of the target specification corresponds to this element" + ) + private StringDt myMap; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myIdentity, myMap); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myIdentity, myMap); + } + + /** + * Gets the value(s) for identity (Reference to mapping declaration). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An internal reference to the definition of a mapping + *

+ */ + public IdDt getIdentity() { + if (myIdentity == null) { + myIdentity = new IdDt(); + } + return myIdentity; + } + + /** + * Sets the value(s) for identity (Reference to mapping declaration) + * + *

+ * Definition: + * An internal reference to the definition of a mapping + *

+ */ + public StructureElementDefinitionMapping setIdentity(IdDt theValue) { + myIdentity = theValue; + return this; + } + + /** + * Sets the value for identity (Reference to mapping declaration) + * + *

+ * Definition: + * An internal reference to the definition of a mapping + *

+ */ + public StructureElementDefinitionMapping setIdentity( String theId) { + myIdentity = new IdDt(theId); + return this; + } + + + /** + * Gets the value(s) for map (Details of the mapping). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Expresses what part of the target specification corresponds to this element + *

+ */ + public StringDt getMap() { + if (myMap == null) { + myMap = new StringDt(); + } + return myMap; + } + + /** + * Sets the value(s) for map (Details of the mapping) + * + *

+ * Definition: + * Expresses what part of the target specification corresponds to this element + *

+ */ + public StructureElementDefinitionMapping setMap(StringDt theValue) { + myMap = theValue; + return this; + } + + /** + * Sets the value for map (Details of the mapping) + * + *

+ * Definition: + * Expresses what part of the target specification corresponds to this element + *

+ */ + public StructureElementDefinitionMapping setMap( String theString) { + myMap = new StringDt(theString); + return this; + } + + + + } + + + + + /** + * Block class for child element: Profile.structure.searchParam (Search params defined) + * + *

+ * Definition: + * Additional search parameters for implementations to support and/or make use of + *

+ */ + @Block() + public static class StructureSearchParam extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="name", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Name of search parameter", + formalDefinition="The name of the standard or custom search parameter" + ) + private StringDt myName; + + @Child(name="type", type=CodeDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="number | date | string | token | reference | composite | quantity", + formalDefinition="The type of value a search parameter refers to, and how the content is interpreted" + ) + private BoundCodeDt myType; + + @Child(name="documentation", type=StringDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="Contents and meaning of search parameter", + formalDefinition="A specification for search parameters. For standard parameters, provides additional information on how the parameter is used in this solution. For custom parameters, provides a description of what the parameter does" + ) + private StringDt myDocumentation; + + @Child(name="xpath", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="XPath that extracts the parameter set", + formalDefinition="An XPath expression that returns a set of elements for the search parameter" + ) + private StringDt myXpath; + + @Child(name="target", type=CodeDt.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Types of resource (if a resource reference)", + formalDefinition="Types of resource (if a resource is referenced)" + ) + private java.util.List> myTarget; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myName, myType, myDocumentation, myXpath, myTarget); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myName, myType, myDocumentation, myXpath, myTarget); + } + + /** + * Gets the value(s) for name (Name of search parameter). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of the standard or custom search parameter + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Name of search parameter) + * + *

+ * Definition: + * The name of the standard or custom search parameter + *

+ */ + public StructureSearchParam setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Name of search parameter) + * + *

+ * Definition: + * The name of the standard or custom search parameter + *

+ */ + public StructureSearchParam setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for type (number | date | string | token | reference | composite | quantity). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The type of value a search parameter refers to, and how the content is interpreted + *

+ */ + public BoundCodeDt getType() { + if (myType == null) { + myType = new BoundCodeDt(SearchParamTypeEnum.VALUESET_BINDER); + } + return myType; + } + + /** + * Sets the value(s) for type (number | date | string | token | reference | composite | quantity) + * + *

+ * Definition: + * The type of value a search parameter refers to, and how the content is interpreted + *

+ */ + public StructureSearchParam setType(BoundCodeDt theValue) { + myType = theValue; + return this; + } + + /** + * Sets the value(s) for type (number | date | string | token | reference | composite | quantity) + * + *

+ * Definition: + * The type of value a search parameter refers to, and how the content is interpreted + *

+ */ + public StructureSearchParam setType(SearchParamTypeEnum theValue) { + getType().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for documentation (Contents and meaning of search parameter). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A specification for search parameters. For standard parameters, provides additional information on how the parameter is used in this solution. For custom parameters, provides a description of what the parameter does + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Contents and meaning of search parameter) + * + *

+ * Definition: + * A specification for search parameters. For standard parameters, provides additional information on how the parameter is used in this solution. For custom parameters, provides a description of what the parameter does + *

+ */ + public StructureSearchParam setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Contents and meaning of search parameter) + * + *

+ * Definition: + * A specification for search parameters. For standard parameters, provides additional information on how the parameter is used in this solution. For custom parameters, provides a description of what the parameter does + *

+ */ + public StructureSearchParam setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for xpath (XPath that extracts the parameter set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An XPath expression that returns a set of elements for the search parameter + *

+ */ + public StringDt getXpath() { + if (myXpath == null) { + myXpath = new StringDt(); + } + return myXpath; + } + + /** + * Sets the value(s) for xpath (XPath that extracts the parameter set) + * + *

+ * Definition: + * An XPath expression that returns a set of elements for the search parameter + *

+ */ + public StructureSearchParam setXpath(StringDt theValue) { + myXpath = theValue; + return this; + } + + /** + * Sets the value for xpath (XPath that extracts the parameter set) + * + *

+ * Definition: + * An XPath expression that returns a set of elements for the search parameter + *

+ */ + public StructureSearchParam setXpath( String theString) { + myXpath = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for target (Types of resource (if a resource reference)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public java.util.List> getTarget() { + if (myTarget == null) { + myTarget = new java.util.ArrayList>(); + } + return myTarget; + } + + /** + * Sets the value(s) for target (Types of resource (if a resource reference)) + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public StructureSearchParam setTarget(java.util.List> theValue) { + myTarget = theValue; + return this; + } + + /** + * Add a value for target (Types of resource (if a resource reference)) using an enumerated type. This + * is intended as a convenience method for situations where the FHIR defined ValueSets are mandatory + * or contain the desirable codes. If you wish to use codes other than those which are built-in, + * you may also use the {@link #addType()} method. + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public BoundCodeDt addTarget(ResourceTypeEnum theValue) { + BoundCodeDt retVal = new BoundCodeDt(ResourceTypeEnum.VALUESET_BINDER, theValue); + getTarget().add(retVal); + return retVal; + } + + /** + * Gets the first repetition for target (Types of resource (if a resource reference)), + * creating it if it does not already exist. + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public BoundCodeDt getTargetFirstRep() { + if (getTarget().size() == 0) { + addTarget(); + } + return getTarget().get(0); + } + + /** + * Add a value for target (Types of resource (if a resource reference)) + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public BoundCodeDt addTarget() { + BoundCodeDt retVal = new BoundCodeDt(ResourceTypeEnum.VALUESET_BINDER); + getTarget().add(retVal); + return retVal; + } + + /** + * Sets the value(s), and clears any existing value(s) for target (Types of resource (if a resource reference)) + * + *

+ * Definition: + * Types of resource (if a resource is referenced) + *

+ */ + public StructureSearchParam setTarget(ResourceTypeEnum theValue) { + getTarget().clear(); + addTarget(theValue); + return this; + } + + + + } + + + + /** + * Block class for child element: Profile.extensionDefn (Definition of an extension) + * + *

+ * Definition: + * An extension defined as part of the profile + *

+ */ + @Block() + public static class ExtensionDefn extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="code", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Identifies the extension in this profile", + formalDefinition="A unique code (within the profile) used to identify the extension" + ) + private CodeDt myCode; + + @Child(name="display", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Use this name when displaying the value", + formalDefinition="Defined so that applications can use this name when displaying the value of the extension to the user" + ) + private StringDt myDisplay; + + @Child(name="contextType", type=CodeDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="resource | datatype | mapping | extension", + formalDefinition="Identifies the type of context to which the extension applies" + ) + private BoundCodeDt myContextType; + + @Child(name="context", type=StringDt.class, order=3, min=1, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Where the extension can be used in instances", + formalDefinition="Identifies the types of resource or data type elements to which the extension can be applied" + ) + private java.util.List myContext; + + @Child(name="definition", type=StructureElementDefinition.class, order=4, min=1, max=1) + @Description( + shortDefinition="Definition of the extension and its content", + formalDefinition="Definition of the extension and its content" + ) + private StructureElementDefinition myDefinition; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCode, myDisplay, myContextType, myContext, myDefinition); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCode, myDisplay, myContextType, myContext, myDefinition); + } + + /** + * Gets the value(s) for code (Identifies the extension in this profile). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A unique code (within the profile) used to identify the extension + *

+ */ + public CodeDt getCode() { + if (myCode == null) { + myCode = new CodeDt(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Identifies the extension in this profile) + * + *

+ * Definition: + * A unique code (within the profile) used to identify the extension + *

+ */ + public ExtensionDefn setCode(CodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value for code (Identifies the extension in this profile) + * + *

+ * Definition: + * A unique code (within the profile) used to identify the extension + *

+ */ + public ExtensionDefn setCode( String theCode) { + myCode = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for display (Use this name when displaying the value). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Defined so that applications can use this name when displaying the value of the extension to the user + *

+ */ + public StringDt getDisplay() { + if (myDisplay == null) { + myDisplay = new StringDt(); + } + return myDisplay; + } + + /** + * Sets the value(s) for display (Use this name when displaying the value) + * + *

+ * Definition: + * Defined so that applications can use this name when displaying the value of the extension to the user + *

+ */ + public ExtensionDefn setDisplay(StringDt theValue) { + myDisplay = theValue; + return this; + } + + /** + * Sets the value for display (Use this name when displaying the value) + * + *

+ * Definition: + * Defined so that applications can use this name when displaying the value of the extension to the user + *

+ */ + public ExtensionDefn setDisplay( String theString) { + myDisplay = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for contextType (resource | datatype | mapping | extension). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the type of context to which the extension applies + *

+ */ + public BoundCodeDt getContextType() { + if (myContextType == null) { + myContextType = new BoundCodeDt(ExtensionContextEnum.VALUESET_BINDER); + } + return myContextType; + } + + /** + * Sets the value(s) for contextType (resource | datatype | mapping | extension) + * + *

+ * Definition: + * Identifies the type of context to which the extension applies + *

+ */ + public ExtensionDefn setContextType(BoundCodeDt theValue) { + myContextType = theValue; + return this; + } + + /** + * Sets the value(s) for contextType (resource | datatype | mapping | extension) + * + *

+ * Definition: + * Identifies the type of context to which the extension applies + *

+ */ + public ExtensionDefn setContextType(ExtensionContextEnum theValue) { + getContextType().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for context (Where the extension can be used in instances). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Identifies the types of resource or data type elements to which the extension can be applied + *

+ */ + public java.util.List getContext() { + if (myContext == null) { + myContext = new java.util.ArrayList(); + } + return myContext; + } + + /** + * Sets the value(s) for context (Where the extension can be used in instances) + * + *

+ * Definition: + * Identifies the types of resource or data type elements to which the extension can be applied + *

+ */ + public ExtensionDefn setContext(java.util.List theValue) { + myContext = theValue; + return this; + } + + /** + * Adds and returns a new value for context (Where the extension can be used in instances) + * + *

+ * Definition: + * Identifies the types of resource or data type elements to which the extension can be applied + *

+ */ + public StringDt addContext() { + StringDt newType = new StringDt(); + getContext().add(newType); + return newType; + } + + /** + * Gets the first repetition for context (Where the extension can be used in instances), + * creating it if it does not already exist. + * + *

+ * Definition: + * Identifies the types of resource or data type elements to which the extension can be applied + *

+ */ + public StringDt getContextFirstRep() { + if (getContext().isEmpty()) { + return addContext(); + } + return getContext().get(0); + } + /** + * Adds a new value for context (Where the extension can be used in instances) + * + *

+ * Definition: + * Identifies the types of resource or data type elements to which the extension can be applied + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public ExtensionDefn addContext( String theString) { + if (myContext == null) { + myContext = new java.util.ArrayList(); + } + myContext.add(new StringDt(theString)); + return this; + } + + + /** + * Gets the value(s) for definition (Definition of the extension and its content). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Definition of the extension and its content + *

+ */ + public StructureElementDefinition getDefinition() { + if (myDefinition == null) { + myDefinition = new StructureElementDefinition(); + } + return myDefinition; + } + + /** + * Sets the value(s) for definition (Definition of the extension and its content) + * + *

+ * Definition: + * Definition of the extension and its content + *

+ */ + public ExtensionDefn setDefinition(StructureElementDefinition theValue) { + myDefinition = theValue; + return this; + } + + + + } + + + /** + * Block class for child element: Profile.query (Definition of a named query) + * + *

+ * Definition: + * Definition of a named query and its parameters and their meaning + *

+ */ + @Block() + public static class Query extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="name", type=StringDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Special named queries (_query=)", + formalDefinition="The name of a query, which is used in the URI from Conformance statements declaring use of the query. Typically this will also be the name for the _query parameter when the query is called, though in some cases it may be aliased by a server to avoid collisions" + ) + private StringDt myName; + + @Child(name="documentation", type=StringDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="Describes the named query", + formalDefinition="Description of the query - the functionality it offers, and considerations about how it functions and to use it" + ) + private StringDt myDocumentation; + + @Child(name="parameter", type=StructureSearchParam.class, order=2, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Parameter for the named query", + formalDefinition="A parameter of a named query" + ) + private java.util.List myParameter; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myName, myDocumentation, myParameter); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myName, myDocumentation, myParameter); + } + + /** + * Gets the value(s) for name (Special named queries (_query=)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of a query, which is used in the URI from Conformance statements declaring use of the query. Typically this will also be the name for the _query parameter when the query is called, though in some cases it may be aliased by a server to avoid collisions + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Special named queries (_query=)) + * + *

+ * Definition: + * The name of a query, which is used in the URI from Conformance statements declaring use of the query. Typically this will also be the name for the _query parameter when the query is called, though in some cases it may be aliased by a server to avoid collisions + *

+ */ + public Query setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Special named queries (_query=)) + * + *

+ * Definition: + * The name of a query, which is used in the URI from Conformance statements declaring use of the query. Typically this will also be the name for the _query parameter when the query is called, though in some cases it may be aliased by a server to avoid collisions + *

+ */ + public Query setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for documentation (Describes the named query). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Description of the query - the functionality it offers, and considerations about how it functions and to use it + *

+ */ + public StringDt getDocumentation() { + if (myDocumentation == null) { + myDocumentation = new StringDt(); + } + return myDocumentation; + } + + /** + * Sets the value(s) for documentation (Describes the named query) + * + *

+ * Definition: + * Description of the query - the functionality it offers, and considerations about how it functions and to use it + *

+ */ + public Query setDocumentation(StringDt theValue) { + myDocumentation = theValue; + return this; + } + + /** + * Sets the value for documentation (Describes the named query) + * + *

+ * Definition: + * Description of the query - the functionality it offers, and considerations about how it functions and to use it + *

+ */ + public Query setDocumentation( String theString) { + myDocumentation = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for parameter (Parameter for the named query). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A parameter of a named query + *

+ */ + public java.util.List getParameter() { + if (myParameter == null) { + myParameter = new java.util.ArrayList(); + } + return myParameter; + } + + /** + * Sets the value(s) for parameter (Parameter for the named query) + * + *

+ * Definition: + * A parameter of a named query + *

+ */ + public Query setParameter(java.util.List theValue) { + myParameter = theValue; + return this; + } + + /** + * Adds and returns a new value for parameter (Parameter for the named query) + * + *

+ * Definition: + * A parameter of a named query + *

+ */ + public StructureSearchParam addParameter() { + StructureSearchParam newType = new StructureSearchParam(); + getParameter().add(newType); + return newType; + } + + /** + * Gets the first repetition for parameter (Parameter for the named query), + * creating it if it does not already exist. + * + *

+ * Definition: + * A parameter of a named query + *

+ */ + public StructureSearchParam getParameterFirstRep() { + if (getParameter().isEmpty()) { + return addParameter(); + } + return getParameter().get(0); + } + + + } + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/ValueSet.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/ValueSet.java new file mode 100644 index 00000000000..eb69bea10a0 --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/dstu/resource/ValueSet.java @@ -0,0 +1,2773 @@ + + + + + + + + + + + + + + + + +package ca.uhn.fhir.model.dstu.resource; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + + +import java.util.Date; +import java.util.List; + +import ca.uhn.fhir.model.api.BaseIdentifiableElement; +import ca.uhn.fhir.model.api.BaseResource; +import ca.uhn.fhir.model.api.IElement; +import ca.uhn.fhir.model.api.IResource; +import ca.uhn.fhir.model.api.IResourceBlock; +import ca.uhn.fhir.model.api.TemporalPrecisionEnum; +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.ResourceDef; +import ca.uhn.fhir.model.api.annotation.SearchParamDefinition; +import ca.uhn.fhir.model.dstu.composite.ContactDt; +import ca.uhn.fhir.model.dstu.composite.IdentifierDt; +import ca.uhn.fhir.model.dstu.valueset.ContactUseEnum; +import ca.uhn.fhir.model.dstu.valueset.FilterOperatorEnum; +import ca.uhn.fhir.model.dstu.valueset.IdentifierUseEnum; +import ca.uhn.fhir.model.dstu.valueset.ValueSetStatusEnum; +import ca.uhn.fhir.model.primitive.BooleanDt; +import ca.uhn.fhir.model.primitive.BoundCodeDt; +import ca.uhn.fhir.model.primitive.CodeDt; +import ca.uhn.fhir.model.primitive.DateTimeDt; +import ca.uhn.fhir.model.primitive.InstantDt; +import ca.uhn.fhir.model.primitive.StringDt; +import ca.uhn.fhir.model.primitive.UriDt; +import ca.uhn.fhir.rest.gclient.DateClientParam; +import ca.uhn.fhir.rest.gclient.StringClientParam; +import ca.uhn.fhir.rest.gclient.TokenClientParam; + + +/** + * HAPI/FHIR ValueSet Resource + * (A set of codes drawn from one or more code systems) + * + *

+ * Definition: + * A value set specifies a set of codes drawn from one or more code systems + *

+ * + *

+ * Requirements: + * + *

+ * + *

+ * Profile Definition: + * http://hl7.org/fhir/profiles/ValueSet + *

+ * + */ +@ResourceDef(name="ValueSet", profile="http://hl7.org/fhir/profiles/ValueSet", id="valueset") +public class ValueSet extends BaseResource implements IResource { + + /** + * Search parameter constant for identifier + *

+ * Description: The identifier of the value set
+ * Type: token
+ * Path: ValueSet.identifier
+ *

+ */ + @SearchParamDefinition(name="identifier", path="ValueSet.identifier", description="The identifier of the value set", type="token" ) + public static final String SP_IDENTIFIER = "identifier"; + + /** + * Fluent Client search parameter constant for identifier + *

+ * Description: The identifier of the value set
+ * Type: token
+ * Path: ValueSet.identifier
+ *

+ */ + public static final TokenClientParam IDENTIFIER = new TokenClientParam(SP_IDENTIFIER); + + /** + * Search parameter constant for version + *

+ * Description: The version identifier of the value set
+ * Type: token
+ * Path: ValueSet.version
+ *

+ */ + @SearchParamDefinition(name="version", path="ValueSet.version", description="The version identifier of the value set", type="token" ) + public static final String SP_VERSION = "version"; + + /** + * Fluent Client search parameter constant for version + *

+ * Description: The version identifier of the value set
+ * Type: token
+ * Path: ValueSet.version
+ *

+ */ + public static final TokenClientParam VERSION = new TokenClientParam(SP_VERSION); + + /** + * Search parameter constant for name + *

+ * Description: The name of the value set
+ * Type: string
+ * Path: ValueSet.name
+ *

+ */ + @SearchParamDefinition(name="name", path="ValueSet.name", description="The name of the value set", type="string" ) + public static final String SP_NAME = "name"; + + /** + * Fluent Client search parameter constant for name + *

+ * Description: The name of the value set
+ * Type: string
+ * Path: ValueSet.name
+ *

+ */ + public static final StringClientParam NAME = new StringClientParam(SP_NAME); + + /** + * Search parameter constant for publisher + *

+ * Description: Name of the publisher of the value set
+ * Type: string
+ * Path: ValueSet.publisher
+ *

+ */ + @SearchParamDefinition(name="publisher", path="ValueSet.publisher", description="Name of the publisher of the value set", type="string" ) + public static final String SP_PUBLISHER = "publisher"; + + /** + * Fluent Client search parameter constant for publisher + *

+ * Description: Name of the publisher of the value set
+ * Type: string
+ * Path: ValueSet.publisher
+ *

+ */ + public static final StringClientParam PUBLISHER = new StringClientParam(SP_PUBLISHER); + + /** + * Search parameter constant for description + *

+ * Description: Text search in the description of the value set
+ * Type: string
+ * Path: ValueSet.description
+ *

+ */ + @SearchParamDefinition(name="description", path="ValueSet.description", description="Text search in the description of the value set", type="string" ) + public static final String SP_DESCRIPTION = "description"; + + /** + * Fluent Client search parameter constant for description + *

+ * Description: Text search in the description of the value set
+ * Type: string
+ * Path: ValueSet.description
+ *

+ */ + public static final StringClientParam DESCRIPTION = new StringClientParam(SP_DESCRIPTION); + + /** + * Search parameter constant for status + *

+ * Description: The status of the value set
+ * Type: token
+ * Path: ValueSet.status
+ *

+ */ + @SearchParamDefinition(name="status", path="ValueSet.status", description="The status of the value set", type="token" ) + public static final String SP_STATUS = "status"; + + /** + * Fluent Client search parameter constant for status + *

+ * Description: The status of the value set
+ * Type: token
+ * Path: ValueSet.status
+ *

+ */ + public static final TokenClientParam STATUS = new TokenClientParam(SP_STATUS); + + /** + * Search parameter constant for date + *

+ * Description: The value set publication date
+ * Type: date
+ * Path: ValueSet.date
+ *

+ */ + @SearchParamDefinition(name="date", path="ValueSet.date", description="The value set publication date", type="date" ) + public static final String SP_DATE = "date"; + + /** + * Fluent Client search parameter constant for date + *

+ * Description: The value set publication date
+ * Type: date
+ * Path: ValueSet.date
+ *

+ */ + public static final DateClientParam DATE = new DateClientParam(SP_DATE); + + /** + * Search parameter constant for system + *

+ * Description: The system for any codes defined by this value set
+ * Type: token
+ * Path: ValueSet.define.system
+ *

+ */ + @SearchParamDefinition(name="system", path="ValueSet.define.system", description="The system for any codes defined by this value set", type="token" ) + public static final String SP_SYSTEM = "system"; + + /** + * Fluent Client search parameter constant for system + *

+ * Description: The system for any codes defined by this value set
+ * Type: token
+ * Path: ValueSet.define.system
+ *

+ */ + public static final TokenClientParam SYSTEM = new TokenClientParam(SP_SYSTEM); + + /** + * Search parameter constant for code + *

+ * Description: A code defined in the value set
+ * Type: token
+ * Path: ValueSet.define.concept.code
+ *

+ */ + @SearchParamDefinition(name="code", path="ValueSet.define.concept.code", description="A code defined in the value set", type="token" ) + public static final String SP_CODE = "code"; + + /** + * Fluent Client search parameter constant for code + *

+ * Description: A code defined in the value set
+ * Type: token
+ * Path: ValueSet.define.concept.code
+ *

+ */ + public static final TokenClientParam CODE = new TokenClientParam(SP_CODE); + + /** + * Search parameter constant for reference + *

+ * Description: A code system included or excluded in the value set or an imported value set
+ * Type: token
+ * Path: ValueSet.compose.include.system
+ *

+ */ + @SearchParamDefinition(name="reference", path="ValueSet.compose.include.system", description="A code system included or excluded in the value set or an imported value set", type="token" ) + public static final String SP_REFERENCE = "reference"; + + /** + * Fluent Client search parameter constant for reference + *

+ * Description: A code system included or excluded in the value set or an imported value set
+ * Type: token
+ * Path: ValueSet.compose.include.system
+ *

+ */ + public static final TokenClientParam REFERENCE = new TokenClientParam(SP_REFERENCE); + + + @Child(name="identifier", type=StringDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Logical id to reference this value set", + formalDefinition="The identifier that is used to identify this value set when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI)" + ) + private StringDt myIdentifier; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Logical id for this version of the value set", + formalDefinition="The identifier that is used to identify this version of the value set when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp" + ) + private StringDt myVersion; + + @Child(name="name", type=StringDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="Informal name for this value set", + formalDefinition="A free text natural language name describing the value set" + ) + private StringDt myName; + + @Child(name="publisher", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Name of the publisher (Organization or individual)", + formalDefinition="The name of the individual or organization that published the value set" + ) + private StringDt myPublisher; + + @Child(name="telecom", type=ContactDt.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Contact information of the publisher", + formalDefinition="Contacts of the publisher to assist a user in finding and communicating with the publisher" + ) + private java.util.List myTelecom; + + @Child(name="description", type=StringDt.class, order=5, min=1, max=1) + @Description( + shortDefinition="Human language description of the value set", + formalDefinition="A free text natural language description of the use of the value set - reason for definition, conditions of use, etc." + ) + private StringDt myDescription; + + @Child(name="copyright", type=StringDt.class, order=6, min=0, max=1) + @Description( + shortDefinition="About the value set or its content", + formalDefinition="A copyright statement relating to the value set and/or its contents" + ) + private StringDt myCopyright; + + @Child(name="status", type=CodeDt.class, order=7, min=1, max=1) + @Description( + shortDefinition="draft | active | retired", + formalDefinition="The status of the value set" + ) + private BoundCodeDt myStatus; + + @Child(name="experimental", type=BooleanDt.class, order=8, min=0, max=1) + @Description( + shortDefinition="If for testing purposes, not real usage", + formalDefinition="This valueset was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage" + ) + private BooleanDt myExperimental; + + @Child(name="extensible", type=BooleanDt.class, order=9, min=0, max=1) + @Description( + shortDefinition="Whether this is intended to be used with an extensible binding", + formalDefinition="Whether this is intended to be used with an extensible binding or not" + ) + private BooleanDt myExtensible; + + @Child(name="date", type=DateTimeDt.class, order=10, min=0, max=1) + @Description( + shortDefinition="Date for given status", + formalDefinition="The date that the value set status was last changed" + ) + private DateTimeDt myDate; + + @Child(name="define", order=11, min=0, max=1) + @Description( + shortDefinition="When value set defines its own codes", + formalDefinition="" + ) + private Define myDefine; + + @Child(name="compose", order=12, min=0, max=1) + @Description( + shortDefinition="When value set includes codes from elsewhere", + formalDefinition="" + ) + private Compose myCompose; + + @Child(name="expansion", order=13, min=0, max=1) + @Description( + shortDefinition="When value set is an expansion", + formalDefinition="" + ) + private Expansion myExpansion; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myIdentifier, myVersion, myName, myPublisher, myTelecom, myDescription, myCopyright, myStatus, myExperimental, myExtensible, myDate, myDefine, myCompose, myExpansion); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myIdentifier, myVersion, myName, myPublisher, myTelecom, myDescription, myCopyright, myStatus, myExperimental, myExtensible, myDate, myDefine, myCompose, myExpansion); + } + + /** + * Gets the value(s) for identifier (Logical id to reference this value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identifier that is used to identify this value set when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public StringDt getIdentifier() { + if (myIdentifier == null) { + myIdentifier = new StringDt(); + } + return myIdentifier; + } + + /** + * Sets the value(s) for identifier (Logical id to reference this value set) + * + *

+ * Definition: + * The identifier that is used to identify this value set when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public ValueSet setIdentifier(StringDt theValue) { + myIdentifier = theValue; + return this; + } + + /** + * Sets the value for identifier (Logical id to reference this value set) + * + *

+ * Definition: + * The identifier that is used to identify this value set when it is referenced in a specification, model, design or an instance (should be globally unique OID, UUID, or URI) + *

+ */ + public ValueSet setIdentifier( String theString) { + myIdentifier = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for version (Logical id for this version of the value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The identifier that is used to identify this version of the value set when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public StringDt getVersion() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + /** + * Sets the value(s) for version (Logical id for this version of the value set) + * + *

+ * Definition: + * The identifier that is used to identify this version of the value set when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public ValueSet setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + /** + * Sets the value for version (Logical id for this version of the value set) + * + *

+ * Definition: + * The identifier that is used to identify this version of the value set when it is referenced in a specification, model, design or instance. This is an arbitrary value managed by the profile author manually and the value should be a timestamp + *

+ */ + public ValueSet setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for name (Informal name for this value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A free text natural language name describing the value set + *

+ */ + public StringDt getName() { + if (myName == null) { + myName = new StringDt(); + } + return myName; + } + + /** + * Sets the value(s) for name (Informal name for this value set) + * + *

+ * Definition: + * A free text natural language name describing the value set + *

+ */ + public ValueSet setName(StringDt theValue) { + myName = theValue; + return this; + } + + /** + * Sets the value for name (Informal name for this value set) + * + *

+ * Definition: + * A free text natural language name describing the value set + *

+ */ + public ValueSet setName( String theString) { + myName = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for publisher (Name of the publisher (Organization or individual)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The name of the individual or organization that published the value set + *

+ */ + public StringDt getPublisher() { + if (myPublisher == null) { + myPublisher = new StringDt(); + } + return myPublisher; + } + + /** + * Sets the value(s) for publisher (Name of the publisher (Organization or individual)) + * + *

+ * Definition: + * The name of the individual or organization that published the value set + *

+ */ + public ValueSet setPublisher(StringDt theValue) { + myPublisher = theValue; + return this; + } + + /** + * Sets the value for publisher (Name of the publisher (Organization or individual)) + * + *

+ * Definition: + * The name of the individual or organization that published the value set + *

+ */ + public ValueSet setPublisher( String theString) { + myPublisher = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for telecom (Contact information of the publisher). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Contacts of the publisher to assist a user in finding and communicating with the publisher + *

+ */ + public java.util.List getTelecom() { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + return myTelecom; + } + + /** + * Sets the value(s) for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contacts of the publisher to assist a user in finding and communicating with the publisher + *

+ */ + public ValueSet setTelecom(java.util.List theValue) { + myTelecom = theValue; + return this; + } + + /** + * Adds and returns a new value for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contacts of the publisher to assist a user in finding and communicating with the publisher + *

+ */ + public ContactDt addTelecom() { + ContactDt newType = new ContactDt(); + getTelecom().add(newType); + return newType; + } + + /** + * Gets the first repetition for telecom (Contact information of the publisher), + * creating it if it does not already exist. + * + *

+ * Definition: + * Contacts of the publisher to assist a user in finding and communicating with the publisher + *

+ */ + public ContactDt getTelecomFirstRep() { + if (getTelecom().isEmpty()) { + return addTelecom(); + } + return getTelecom().get(0); + } + /** + * Adds a new value for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contacts of the publisher to assist a user in finding and communicating with the publisher + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public ValueSet addTelecom( ContactUseEnum theContactUse, String theValue) { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + myTelecom.add(new ContactDt(theContactUse, theValue)); + return this; + } + + /** + * Adds a new value for telecom (Contact information of the publisher) + * + *

+ * Definition: + * Contacts of the publisher to assist a user in finding and communicating with the publisher + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public ValueSet addTelecom( String theValue) { + if (myTelecom == null) { + myTelecom = new java.util.ArrayList(); + } + myTelecom.add(new ContactDt(theValue)); + return this; + } + + + /** + * Gets the value(s) for description (Human language description of the value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A free text natural language description of the use of the value set - reason for definition, conditions of use, etc. + *

+ */ + public StringDt getDescription() { + if (myDescription == null) { + myDescription = new StringDt(); + } + return myDescription; + } + + /** + * Sets the value(s) for description (Human language description of the value set) + * + *

+ * Definition: + * A free text natural language description of the use of the value set - reason for definition, conditions of use, etc. + *

+ */ + public ValueSet setDescription(StringDt theValue) { + myDescription = theValue; + return this; + } + + /** + * Sets the value for description (Human language description of the value set) + * + *

+ * Definition: + * A free text natural language description of the use of the value set - reason for definition, conditions of use, etc. + *

+ */ + public ValueSet setDescription( String theString) { + myDescription = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for copyright (About the value set or its content). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A copyright statement relating to the value set and/or its contents + *

+ */ + public StringDt getCopyright() { + if (myCopyright == null) { + myCopyright = new StringDt(); + } + return myCopyright; + } + + /** + * Sets the value(s) for copyright (About the value set or its content) + * + *

+ * Definition: + * A copyright statement relating to the value set and/or its contents + *

+ */ + public ValueSet setCopyright(StringDt theValue) { + myCopyright = theValue; + return this; + } + + /** + * Sets the value for copyright (About the value set or its content) + * + *

+ * Definition: + * A copyright statement relating to the value set and/or its contents + *

+ */ + public ValueSet setCopyright( String theString) { + myCopyright = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for status (draft | active | retired). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The status of the value set + *

+ */ + public BoundCodeDt getStatus() { + if (myStatus == null) { + myStatus = new BoundCodeDt(ValueSetStatusEnum.VALUESET_BINDER); + } + return myStatus; + } + + /** + * Sets the value(s) for status (draft | active | retired) + * + *

+ * Definition: + * The status of the value set + *

+ */ + public ValueSet setStatus(BoundCodeDt theValue) { + myStatus = theValue; + return this; + } + + /** + * Sets the value(s) for status (draft | active | retired) + * + *

+ * Definition: + * The status of the value set + *

+ */ + public ValueSet setStatus(ValueSetStatusEnum theValue) { + getStatus().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for experimental (If for testing purposes, not real usage). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * This valueset was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public BooleanDt getExperimental() { + if (myExperimental == null) { + myExperimental = new BooleanDt(); + } + return myExperimental; + } + + /** + * Sets the value(s) for experimental (If for testing purposes, not real usage) + * + *

+ * Definition: + * This valueset was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public ValueSet setExperimental(BooleanDt theValue) { + myExperimental = theValue; + return this; + } + + /** + * Sets the value for experimental (If for testing purposes, not real usage) + * + *

+ * Definition: + * This valueset was authored for testing purposes (or education/evaluation/marketing), and is not intended to be used for genuine usage + *

+ */ + public ValueSet setExperimental( boolean theBoolean) { + myExperimental = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for extensible (Whether this is intended to be used with an extensible binding). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Whether this is intended to be used with an extensible binding or not + *

+ */ + public BooleanDt getExtensible() { + if (myExtensible == null) { + myExtensible = new BooleanDt(); + } + return myExtensible; + } + + /** + * Sets the value(s) for extensible (Whether this is intended to be used with an extensible binding) + * + *

+ * Definition: + * Whether this is intended to be used with an extensible binding or not + *

+ */ + public ValueSet setExtensible(BooleanDt theValue) { + myExtensible = theValue; + return this; + } + + /** + * Sets the value for extensible (Whether this is intended to be used with an extensible binding) + * + *

+ * Definition: + * Whether this is intended to be used with an extensible binding or not + *

+ */ + public ValueSet setExtensible( boolean theBoolean) { + myExtensible = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for date (Date for given status). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The date that the value set status was last changed + *

+ */ + public DateTimeDt getDate() { + if (myDate == null) { + myDate = new DateTimeDt(); + } + return myDate; + } + + /** + * Sets the value(s) for date (Date for given status) + * + *

+ * Definition: + * The date that the value set status was last changed + *

+ */ + public ValueSet setDate(DateTimeDt theValue) { + myDate = theValue; + return this; + } + + /** + * Sets the value for date (Date for given status) + * + *

+ * Definition: + * The date that the value set status was last changed + *

+ */ + public ValueSet setDateWithSecondsPrecision( Date theDate) { + myDate = new DateTimeDt(theDate); + return this; + } + + /** + * Sets the value for date (Date for given status) + * + *

+ * Definition: + * The date that the value set status was last changed + *

+ */ + public ValueSet setDate( Date theDate, TemporalPrecisionEnum thePrecision) { + myDate = new DateTimeDt(theDate, thePrecision); + return this; + } + + + /** + * Gets the value(s) for define (When value set defines its own codes). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public Define getDefine() { + if (myDefine == null) { + myDefine = new Define(); + } + return myDefine; + } + + /** + * Sets the value(s) for define (When value set defines its own codes) + * + *

+ * Definition: + * + *

+ */ + public ValueSet setDefine(Define theValue) { + myDefine = theValue; + return this; + } + + + /** + * Gets the value(s) for compose (When value set includes codes from elsewhere). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public Compose getCompose() { + if (myCompose == null) { + myCompose = new Compose(); + } + return myCompose; + } + + /** + * Sets the value(s) for compose (When value set includes codes from elsewhere) + * + *

+ * Definition: + * + *

+ */ + public ValueSet setCompose(Compose theValue) { + myCompose = theValue; + return this; + } + + + /** + * Gets the value(s) for expansion (When value set is an expansion). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public Expansion getExpansion() { + if (myExpansion == null) { + myExpansion = new Expansion(); + } + return myExpansion; + } + + /** + * Sets the value(s) for expansion (When value set is an expansion) + * + *

+ * Definition: + * + *

+ */ + public ValueSet setExpansion(Expansion theValue) { + myExpansion = theValue; + return this; + } + + + /** + * Block class for child element: ValueSet.define (When value set defines its own codes) + * + *

+ * Definition: + * + *

+ */ + @Block() + public static class Define extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="system", type=UriDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="URI to identify the code system", + formalDefinition="" + ) + private UriDt mySystem; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Version of this system", + formalDefinition="The version of this code system that defines the codes. Note that the version is optional because a well maintained code system does not suffer from versioning, and therefore the version does not need to be maintained. However many code systems are not well maintained, and the version needs to be defined and tracked" + ) + private StringDt myVersion; + + @Child(name="caseSensitive", type=BooleanDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="If code comparison is case sensitive", + formalDefinition="If code comparison is case sensitive when codes within this system are compared to each other" + ) + private BooleanDt myCaseSensitive; + + @Child(name="concept", order=3, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Concepts in the code system", + formalDefinition="" + ) + private java.util.List myConcept; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( mySystem, myVersion, myCaseSensitive, myConcept); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, mySystem, myVersion, myCaseSensitive, myConcept); + } + + /** + * Gets the value(s) for system (URI to identify the code system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public UriDt getSystem() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + /** + * Sets the value(s) for system (URI to identify the code system) + * + *

+ * Definition: + * + *

+ */ + public Define setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + /** + * Sets the value for system (URI to identify the code system) + * + *

+ * Definition: + * + *

+ */ + public Define setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for version (Version of this system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version of this code system that defines the codes. Note that the version is optional because a well maintained code system does not suffer from versioning, and therefore the version does not need to be maintained. However many code systems are not well maintained, and the version needs to be defined and tracked + *

+ */ + public StringDt getVersion() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + /** + * Sets the value(s) for version (Version of this system) + * + *

+ * Definition: + * The version of this code system that defines the codes. Note that the version is optional because a well maintained code system does not suffer from versioning, and therefore the version does not need to be maintained. However many code systems are not well maintained, and the version needs to be defined and tracked + *

+ */ + public Define setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + /** + * Sets the value for version (Version of this system) + * + *

+ * Definition: + * The version of this code system that defines the codes. Note that the version is optional because a well maintained code system does not suffer from versioning, and therefore the version does not need to be maintained. However many code systems are not well maintained, and the version needs to be defined and tracked + *

+ */ + public Define setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for caseSensitive (If code comparison is case sensitive). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * If code comparison is case sensitive when codes within this system are compared to each other + *

+ */ + public BooleanDt getCaseSensitive() { + if (myCaseSensitive == null) { + myCaseSensitive = new BooleanDt(); + } + return myCaseSensitive; + } + + /** + * Sets the value(s) for caseSensitive (If code comparison is case sensitive) + * + *

+ * Definition: + * If code comparison is case sensitive when codes within this system are compared to each other + *

+ */ + public Define setCaseSensitive(BooleanDt theValue) { + myCaseSensitive = theValue; + return this; + } + + /** + * Sets the value for caseSensitive (If code comparison is case sensitive) + * + *

+ * Definition: + * If code comparison is case sensitive when codes within this system are compared to each other + *

+ */ + public Define setCaseSensitive( boolean theBoolean) { + myCaseSensitive = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for concept (Concepts in the code system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public java.util.List getConcept() { + if (myConcept == null) { + myConcept = new java.util.ArrayList(); + } + return myConcept; + } + + /** + * Sets the value(s) for concept (Concepts in the code system) + * + *

+ * Definition: + * + *

+ */ + public Define setConcept(java.util.List theValue) { + myConcept = theValue; + return this; + } + + /** + * Adds and returns a new value for concept (Concepts in the code system) + * + *

+ * Definition: + * + *

+ */ + public DefineConcept addConcept() { + DefineConcept newType = new DefineConcept(); + getConcept().add(newType); + return newType; + } + + /** + * Gets the first repetition for concept (Concepts in the code system), + * creating it if it does not already exist. + * + *

+ * Definition: + * + *

+ */ + public DefineConcept getConceptFirstRep() { + if (getConcept().isEmpty()) { + return addConcept(); + } + return getConcept().get(0); + } + + + } + + /** + * Block class for child element: ValueSet.define.concept (Concepts in the code system) + * + *

+ * Definition: + * + *

+ */ + @Block() + public static class DefineConcept extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="code", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="Code that identifies concept", + formalDefinition="" + ) + private CodeDt myCode; + + @Child(name="abstract", type=BooleanDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="If this code is not for use as a real concept", + formalDefinition="If this code is not for use as a real concept" + ) + private BooleanDt myAbstract; + + @Child(name="display", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="Text to Display to the user", + formalDefinition="" + ) + private StringDt myDisplay; + + @Child(name="definition", type=StringDt.class, order=3, min=0, max=1) + @Description( + shortDefinition="Formal Definition", + formalDefinition="The formal definition of the concept. Formal definitions are not required, because of the prevalence of legacy systems without them, but they are highly recommended, as without them there is no formal meaning associated with the concept" + ) + private StringDt myDefinition; + + @Child(name="concept", type=DefineConcept.class, order=4, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Child Concepts (is-a / contains)", + formalDefinition="" + ) + private java.util.List myConcept; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myCode, myAbstract, myDisplay, myDefinition, myConcept); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myCode, myAbstract, myDisplay, myDefinition, myConcept); + } + + /** + * Gets the value(s) for code (Code that identifies concept). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public CodeDt getCode() { + if (myCode == null) { + myCode = new CodeDt(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Code that identifies concept) + * + *

+ * Definition: + * + *

+ */ + public DefineConcept setCode(CodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value for code (Code that identifies concept) + * + *

+ * Definition: + * + *

+ */ + public DefineConcept setCode( String theCode) { + myCode = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for abstract (If this code is not for use as a real concept). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * If this code is not for use as a real concept + *

+ */ + public BooleanDt getAbstract() { + if (myAbstract == null) { + myAbstract = new BooleanDt(); + } + return myAbstract; + } + + /** + * Sets the value(s) for abstract (If this code is not for use as a real concept) + * + *

+ * Definition: + * If this code is not for use as a real concept + *

+ */ + public DefineConcept setAbstract(BooleanDt theValue) { + myAbstract = theValue; + return this; + } + + /** + * Sets the value for abstract (If this code is not for use as a real concept) + * + *

+ * Definition: + * If this code is not for use as a real concept + *

+ */ + public DefineConcept setAbstract( boolean theBoolean) { + myAbstract = new BooleanDt(theBoolean); + return this; + } + + + /** + * Gets the value(s) for display (Text to Display to the user). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public StringDt getDisplay() { + if (myDisplay == null) { + myDisplay = new StringDt(); + } + return myDisplay; + } + + /** + * Sets the value(s) for display (Text to Display to the user) + * + *

+ * Definition: + * + *

+ */ + public DefineConcept setDisplay(StringDt theValue) { + myDisplay = theValue; + return this; + } + + /** + * Sets the value for display (Text to Display to the user) + * + *

+ * Definition: + * + *

+ */ + public DefineConcept setDisplay( String theString) { + myDisplay = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for definition (Formal Definition). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The formal definition of the concept. Formal definitions are not required, because of the prevalence of legacy systems without them, but they are highly recommended, as without them there is no formal meaning associated with the concept + *

+ */ + public StringDt getDefinition() { + if (myDefinition == null) { + myDefinition = new StringDt(); + } + return myDefinition; + } + + /** + * Sets the value(s) for definition (Formal Definition) + * + *

+ * Definition: + * The formal definition of the concept. Formal definitions are not required, because of the prevalence of legacy systems without them, but they are highly recommended, as without them there is no formal meaning associated with the concept + *

+ */ + public DefineConcept setDefinition(StringDt theValue) { + myDefinition = theValue; + return this; + } + + /** + * Sets the value for definition (Formal Definition) + * + *

+ * Definition: + * The formal definition of the concept. Formal definitions are not required, because of the prevalence of legacy systems without them, but they are highly recommended, as without them there is no formal meaning associated with the concept + *

+ */ + public DefineConcept setDefinition( String theString) { + myDefinition = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for concept (Child Concepts (is-a / contains)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public java.util.List getConcept() { + if (myConcept == null) { + myConcept = new java.util.ArrayList(); + } + return myConcept; + } + + /** + * Sets the value(s) for concept (Child Concepts (is-a / contains)) + * + *

+ * Definition: + * + *

+ */ + public DefineConcept setConcept(java.util.List theValue) { + myConcept = theValue; + return this; + } + + /** + * Adds and returns a new value for concept (Child Concepts (is-a / contains)) + * + *

+ * Definition: + * + *

+ */ + public DefineConcept addConcept() { + DefineConcept newType = new DefineConcept(); + getConcept().add(newType); + return newType; + } + + /** + * Gets the first repetition for concept (Child Concepts (is-a / contains)), + * creating it if it does not already exist. + * + *

+ * Definition: + * + *

+ */ + public DefineConcept getConceptFirstRep() { + if (getConcept().isEmpty()) { + return addConcept(); + } + return getConcept().get(0); + } + + + } + + + + /** + * Block class for child element: ValueSet.compose (When value set includes codes from elsewhere) + * + *

+ * Definition: + * + *

+ */ + @Block() + public static class Compose extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="import", type=UriDt.class, order=0, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Import the contents of another value set", + formalDefinition="Includes the contents of the referenced value set as a part of the contents of this value set" + ) + private java.util.List myImport; + + @Child(name="include", order=1, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Include one or more codes from a code system", + formalDefinition="Include one or more codes from a code system" + ) + private java.util.List myInclude; + + @Child(name="exclude", type=ComposeInclude.class, order=2, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Explicitly exclude codes", + formalDefinition="Exclude one or more codes from the value set" + ) + private java.util.List myExclude; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myImport, myInclude, myExclude); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myImport, myInclude, myExclude); + } + + /** + * Gets the value(s) for import (Import the contents of another value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Includes the contents of the referenced value set as a part of the contents of this value set + *

+ */ + public java.util.List getImport() { + if (myImport == null) { + myImport = new java.util.ArrayList(); + } + return myImport; + } + + /** + * Sets the value(s) for import (Import the contents of another value set) + * + *

+ * Definition: + * Includes the contents of the referenced value set as a part of the contents of this value set + *

+ */ + public Compose setImport(java.util.List theValue) { + myImport = theValue; + return this; + } + + /** + * Adds and returns a new value for import (Import the contents of another value set) + * + *

+ * Definition: + * Includes the contents of the referenced value set as a part of the contents of this value set + *

+ */ + public UriDt addImport() { + UriDt newType = new UriDt(); + getImport().add(newType); + return newType; + } + + /** + * Gets the first repetition for import (Import the contents of another value set), + * creating it if it does not already exist. + * + *

+ * Definition: + * Includes the contents of the referenced value set as a part of the contents of this value set + *

+ */ + public UriDt getImportFirstRep() { + if (getImport().isEmpty()) { + return addImport(); + } + return getImport().get(0); + } + /** + * Adds a new value for import (Import the contents of another value set) + * + *

+ * Definition: + * Includes the contents of the referenced value set as a part of the contents of this value set + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public Compose addImport( String theUri) { + if (myImport == null) { + myImport = new java.util.ArrayList(); + } + myImport.add(new UriDt(theUri)); + return this; + } + + + /** + * Gets the value(s) for include (Include one or more codes from a code system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Include one or more codes from a code system + *

+ */ + public java.util.List getInclude() { + if (myInclude == null) { + myInclude = new java.util.ArrayList(); + } + return myInclude; + } + + /** + * Sets the value(s) for include (Include one or more codes from a code system) + * + *

+ * Definition: + * Include one or more codes from a code system + *

+ */ + public Compose setInclude(java.util.List theValue) { + myInclude = theValue; + return this; + } + + /** + * Adds and returns a new value for include (Include one or more codes from a code system) + * + *

+ * Definition: + * Include one or more codes from a code system + *

+ */ + public ComposeInclude addInclude() { + ComposeInclude newType = new ComposeInclude(); + getInclude().add(newType); + return newType; + } + + /** + * Gets the first repetition for include (Include one or more codes from a code system), + * creating it if it does not already exist. + * + *

+ * Definition: + * Include one or more codes from a code system + *

+ */ + public ComposeInclude getIncludeFirstRep() { + if (getInclude().isEmpty()) { + return addInclude(); + } + return getInclude().get(0); + } + + /** + * Gets the value(s) for exclude (Explicitly exclude codes). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Exclude one or more codes from the value set + *

+ */ + public java.util.List getExclude() { + if (myExclude == null) { + myExclude = new java.util.ArrayList(); + } + return myExclude; + } + + /** + * Sets the value(s) for exclude (Explicitly exclude codes) + * + *

+ * Definition: + * Exclude one or more codes from the value set + *

+ */ + public Compose setExclude(java.util.List theValue) { + myExclude = theValue; + return this; + } + + /** + * Adds and returns a new value for exclude (Explicitly exclude codes) + * + *

+ * Definition: + * Exclude one or more codes from the value set + *

+ */ + public ComposeInclude addExclude() { + ComposeInclude newType = new ComposeInclude(); + getExclude().add(newType); + return newType; + } + + /** + * Gets the first repetition for exclude (Explicitly exclude codes), + * creating it if it does not already exist. + * + *

+ * Definition: + * Exclude one or more codes from the value set + *

+ */ + public ComposeInclude getExcludeFirstRep() { + if (getExclude().isEmpty()) { + return addExclude(); + } + return getExclude().get(0); + } + + + } + + /** + * Block class for child element: ValueSet.compose.include (Include one or more codes from a code system) + * + *

+ * Definition: + * Include one or more codes from a code system + *

+ */ + @Block() + public static class ComposeInclude extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="system", type=UriDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="The system the codes come from", + formalDefinition="The code system from which the selected codes come from" + ) + private UriDt mySystem; + + @Child(name="version", type=StringDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Specific version of the code system referred to", + formalDefinition="The version of the code system that the codes are selected from" + ) + private StringDt myVersion; + + @Child(name="code", type=CodeDt.class, order=2, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Code or concept from system", + formalDefinition="Specifies a code or concept to be included or excluded. The list of codes is considered ordered, though the order may not have any particular significance" + ) + private java.util.List myCode; + + @Child(name="filter", order=3, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Select codes/concepts by their properties (including relationships)", + formalDefinition="Select concepts by specify a matching criteria based on the properties (including relationships) defined by the system. If multiple filters are specified, they SHALL all be true." + ) + private java.util.List myFilter; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( mySystem, myVersion, myCode, myFilter); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, mySystem, myVersion, myCode, myFilter); + } + + /** + * Gets the value(s) for system (The system the codes come from). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The code system from which the selected codes come from + *

+ */ + public UriDt getSystem() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + /** + * Sets the value(s) for system (The system the codes come from) + * + *

+ * Definition: + * The code system from which the selected codes come from + *

+ */ + public ComposeInclude setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + /** + * Sets the value for system (The system the codes come from) + * + *

+ * Definition: + * The code system from which the selected codes come from + *

+ */ + public ComposeInclude setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for version (Specific version of the code system referred to). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The version of the code system that the codes are selected from + *

+ */ + public StringDt getVersion() { + if (myVersion == null) { + myVersion = new StringDt(); + } + return myVersion; + } + + /** + * Sets the value(s) for version (Specific version of the code system referred to) + * + *

+ * Definition: + * The version of the code system that the codes are selected from + *

+ */ + public ComposeInclude setVersion(StringDt theValue) { + myVersion = theValue; + return this; + } + + /** + * Sets the value for version (Specific version of the code system referred to) + * + *

+ * Definition: + * The version of the code system that the codes are selected from + *

+ */ + public ComposeInclude setVersion( String theString) { + myVersion = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for code (Code or concept from system). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Specifies a code or concept to be included or excluded. The list of codes is considered ordered, though the order may not have any particular significance + *

+ */ + public java.util.List getCode() { + if (myCode == null) { + myCode = new java.util.ArrayList(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Code or concept from system) + * + *

+ * Definition: + * Specifies a code or concept to be included or excluded. The list of codes is considered ordered, though the order may not have any particular significance + *

+ */ + public ComposeInclude setCode(java.util.List theValue) { + myCode = theValue; + return this; + } + + /** + * Adds and returns a new value for code (Code or concept from system) + * + *

+ * Definition: + * Specifies a code or concept to be included or excluded. The list of codes is considered ordered, though the order may not have any particular significance + *

+ */ + public CodeDt addCode() { + CodeDt newType = new CodeDt(); + getCode().add(newType); + return newType; + } + + /** + * Gets the first repetition for code (Code or concept from system), + * creating it if it does not already exist. + * + *

+ * Definition: + * Specifies a code or concept to be included or excluded. The list of codes is considered ordered, though the order may not have any particular significance + *

+ */ + public CodeDt getCodeFirstRep() { + if (getCode().isEmpty()) { + return addCode(); + } + return getCode().get(0); + } + /** + * Adds a new value for code (Code or concept from system) + * + *

+ * Definition: + * Specifies a code or concept to be included or excluded. The list of codes is considered ordered, though the order may not have any particular significance + *

+ * + * @return Returns a reference to this object, to allow for simple chaining. + */ + public ComposeInclude addCode( String theCode) { + if (myCode == null) { + myCode = new java.util.ArrayList(); + } + myCode.add(new CodeDt(theCode)); + return this; + } + + + /** + * Gets the value(s) for filter (Select codes/concepts by their properties (including relationships)). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * Select concepts by specify a matching criteria based on the properties (including relationships) defined by the system. If multiple filters are specified, they SHALL all be true. + *

+ */ + public java.util.List getFilter() { + if (myFilter == null) { + myFilter = new java.util.ArrayList(); + } + return myFilter; + } + + /** + * Sets the value(s) for filter (Select codes/concepts by their properties (including relationships)) + * + *

+ * Definition: + * Select concepts by specify a matching criteria based on the properties (including relationships) defined by the system. If multiple filters are specified, they SHALL all be true. + *

+ */ + public ComposeInclude setFilter(java.util.List theValue) { + myFilter = theValue; + return this; + } + + /** + * Adds and returns a new value for filter (Select codes/concepts by their properties (including relationships)) + * + *

+ * Definition: + * Select concepts by specify a matching criteria based on the properties (including relationships) defined by the system. If multiple filters are specified, they SHALL all be true. + *

+ */ + public ComposeIncludeFilter addFilter() { + ComposeIncludeFilter newType = new ComposeIncludeFilter(); + getFilter().add(newType); + return newType; + } + + /** + * Gets the first repetition for filter (Select codes/concepts by their properties (including relationships)), + * creating it if it does not already exist. + * + *

+ * Definition: + * Select concepts by specify a matching criteria based on the properties (including relationships) defined by the system. If multiple filters are specified, they SHALL all be true. + *

+ */ + public ComposeIncludeFilter getFilterFirstRep() { + if (getFilter().isEmpty()) { + return addFilter(); + } + return getFilter().get(0); + } + + + } + + /** + * Block class for child element: ValueSet.compose.include.filter (Select codes/concepts by their properties (including relationships)) + * + *

+ * Definition: + * Select concepts by specify a matching criteria based on the properties (including relationships) defined by the system. If multiple filters are specified, they SHALL all be true. + *

+ */ + @Block() + public static class ComposeIncludeFilter extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="property", type=CodeDt.class, order=0, min=1, max=1) + @Description( + shortDefinition="", + formalDefinition="A code that identifies a property defined in the code system" + ) + private CodeDt myProperty; + + @Child(name="op", type=CodeDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="= | is-a | is-not-a | regex | in | not in", + formalDefinition="The kind of operation to perform as a part of the filter criteria" + ) + private BoundCodeDt myOp; + + @Child(name="value", type=CodeDt.class, order=2, min=1, max=1) + @Description( + shortDefinition="Code from the system, or regex criteria", + formalDefinition="The match value may be either a code defined by the system, or a string value which is used a regex match on the literal string of the property value" + ) + private CodeDt myValue; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myProperty, myOp, myValue); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myProperty, myOp, myValue); + } + + /** + * Gets the value(s) for property (). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * A code that identifies a property defined in the code system + *

+ */ + public CodeDt getProperty() { + if (myProperty == null) { + myProperty = new CodeDt(); + } + return myProperty; + } + + /** + * Sets the value(s) for property () + * + *

+ * Definition: + * A code that identifies a property defined in the code system + *

+ */ + public ComposeIncludeFilter setProperty(CodeDt theValue) { + myProperty = theValue; + return this; + } + + /** + * Sets the value for property () + * + *

+ * Definition: + * A code that identifies a property defined in the code system + *

+ */ + public ComposeIncludeFilter setProperty( String theCode) { + myProperty = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for op (= | is-a | is-not-a | regex | in | not in). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The kind of operation to perform as a part of the filter criteria + *

+ */ + public BoundCodeDt getOp() { + if (myOp == null) { + myOp = new BoundCodeDt(FilterOperatorEnum.VALUESET_BINDER); + } + return myOp; + } + + /** + * Sets the value(s) for op (= | is-a | is-not-a | regex | in | not in) + * + *

+ * Definition: + * The kind of operation to perform as a part of the filter criteria + *

+ */ + public ComposeIncludeFilter setOp(BoundCodeDt theValue) { + myOp = theValue; + return this; + } + + /** + * Sets the value(s) for op (= | is-a | is-not-a | regex | in | not in) + * + *

+ * Definition: + * The kind of operation to perform as a part of the filter criteria + *

+ */ + public ComposeIncludeFilter setOp(FilterOperatorEnum theValue) { + getOp().setValueAsEnum(theValue); + return this; + } + + + /** + * Gets the value(s) for value (Code from the system, or regex criteria). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * The match value may be either a code defined by the system, or a string value which is used a regex match on the literal string of the property value + *

+ */ + public CodeDt getValue() { + if (myValue == null) { + myValue = new CodeDt(); + } + return myValue; + } + + /** + * Sets the value(s) for value (Code from the system, or regex criteria) + * + *

+ * Definition: + * The match value may be either a code defined by the system, or a string value which is used a regex match on the literal string of the property value + *

+ */ + public ComposeIncludeFilter setValue(CodeDt theValue) { + myValue = theValue; + return this; + } + + /** + * Sets the value for value (Code from the system, or regex criteria) + * + *

+ * Definition: + * The match value may be either a code defined by the system, or a string value which is used a regex match on the literal string of the property value + *

+ */ + public ComposeIncludeFilter setValue( String theCode) { + myValue = new CodeDt(theCode); + return this; + } + + + + } + + + + + /** + * Block class for child element: ValueSet.expansion (When value set is an expansion) + * + *

+ * Definition: + * + *

+ */ + @Block() + public static class Expansion extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="identifier", type=IdentifierDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="Uniquely identifies this expansion", + formalDefinition="An identifier that uniquely identifies this expansion of the valueset. Systems may re-use the same identifier as long as the expansion and the definition remain the same, but are not required to do so" + ) + private IdentifierDt myIdentifier; + + @Child(name="timestamp", type=InstantDt.class, order=1, min=1, max=1) + @Description( + shortDefinition="Time valueset expansion happened", + formalDefinition="" + ) + private InstantDt myTimestamp; + + @Child(name="contains", order=2, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Codes in the value set", + formalDefinition="" + ) + private java.util.List myContains; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myIdentifier, myTimestamp, myContains); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myIdentifier, myTimestamp, myContains); + } + + /** + * Gets the value(s) for identifier (Uniquely identifies this expansion). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * An identifier that uniquely identifies this expansion of the valueset. Systems may re-use the same identifier as long as the expansion and the definition remain the same, but are not required to do so + *

+ */ + public IdentifierDt getIdentifier() { + if (myIdentifier == null) { + myIdentifier = new IdentifierDt(); + } + return myIdentifier; + } + + /** + * Sets the value(s) for identifier (Uniquely identifies this expansion) + * + *

+ * Definition: + * An identifier that uniquely identifies this expansion of the valueset. Systems may re-use the same identifier as long as the expansion and the definition remain the same, but are not required to do so + *

+ */ + public Expansion setIdentifier(IdentifierDt theValue) { + myIdentifier = theValue; + return this; + } + + /** + * Sets the value for identifier (Uniquely identifies this expansion) + * + *

+ * Definition: + * An identifier that uniquely identifies this expansion of the valueset. Systems may re-use the same identifier as long as the expansion and the definition remain the same, but are not required to do so + *

+ */ + public Expansion setIdentifier( IdentifierUseEnum theUse, String theSystem, String theValue, String theLabel) { + myIdentifier = new IdentifierDt(theUse, theSystem, theValue, theLabel); + return this; + } + + /** + * Sets the value for identifier (Uniquely identifies this expansion) + * + *

+ * Definition: + * An identifier that uniquely identifies this expansion of the valueset. Systems may re-use the same identifier as long as the expansion and the definition remain the same, but are not required to do so + *

+ */ + public Expansion setIdentifier( String theSystem, String theValue) { + myIdentifier = new IdentifierDt(theSystem, theValue); + return this; + } + + + /** + * Gets the value(s) for timestamp (Time valueset expansion happened). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public InstantDt getTimestamp() { + if (myTimestamp == null) { + myTimestamp = new InstantDt(); + } + return myTimestamp; + } + + /** + * Sets the value(s) for timestamp (Time valueset expansion happened) + * + *

+ * Definition: + * + *

+ */ + public Expansion setTimestamp(InstantDt theValue) { + myTimestamp = theValue; + return this; + } + + /** + * Sets the value for timestamp (Time valueset expansion happened) + * + *

+ * Definition: + * + *

+ */ + public Expansion setTimestamp( Date theDate, TemporalPrecisionEnum thePrecision) { + myTimestamp = new InstantDt(theDate, thePrecision); + return this; + } + + /** + * Sets the value for timestamp (Time valueset expansion happened) + * + *

+ * Definition: + * + *

+ */ + public Expansion setTimestampWithMillisPrecision( Date theDate) { + myTimestamp = new InstantDt(theDate); + return this; + } + + + /** + * Gets the value(s) for contains (Codes in the value set). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public java.util.List getContains() { + if (myContains == null) { + myContains = new java.util.ArrayList(); + } + return myContains; + } + + /** + * Sets the value(s) for contains (Codes in the value set) + * + *

+ * Definition: + * + *

+ */ + public Expansion setContains(java.util.List theValue) { + myContains = theValue; + return this; + } + + /** + * Adds and returns a new value for contains (Codes in the value set) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains addContains() { + ExpansionContains newType = new ExpansionContains(); + getContains().add(newType); + return newType; + } + + /** + * Gets the first repetition for contains (Codes in the value set), + * creating it if it does not already exist. + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains getContainsFirstRep() { + if (getContains().isEmpty()) { + return addContains(); + } + return getContains().get(0); + } + + + } + + /** + * Block class for child element: ValueSet.expansion.contains (Codes in the value set) + * + *

+ * Definition: + * + *

+ */ + @Block() + public static class ExpansionContains extends BaseIdentifiableElement implements IResourceBlock { + + @Child(name="system", type=UriDt.class, order=0, min=0, max=1) + @Description( + shortDefinition="System value for the code", + formalDefinition="" + ) + private UriDt mySystem; + + @Child(name="code", type=CodeDt.class, order=1, min=0, max=1) + @Description( + shortDefinition="Code - if blank, this is not a choosable code", + formalDefinition="" + ) + private CodeDt myCode; + + @Child(name="display", type=StringDt.class, order=2, min=0, max=1) + @Description( + shortDefinition="User display for the concept", + formalDefinition="" + ) + private StringDt myDisplay; + + @Child(name="contains", type=ExpansionContains.class, order=3, min=0, max=Child.MAX_UNLIMITED) + @Description( + shortDefinition="Codes contained in this concept", + formalDefinition="" + ) + private java.util.List myContains; + + + @Override + public boolean isEmpty() { + return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( mySystem, myCode, myDisplay, myContains); + } + + @Override + public List getAllPopulatedChildElementsOfType(Class theType) { + return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, mySystem, myCode, myDisplay, myContains); + } + + /** + * Gets the value(s) for system (System value for the code). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public UriDt getSystem() { + if (mySystem == null) { + mySystem = new UriDt(); + } + return mySystem; + } + + /** + * Sets the value(s) for system (System value for the code) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains setSystem(UriDt theValue) { + mySystem = theValue; + return this; + } + + /** + * Sets the value for system (System value for the code) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains setSystem( String theUri) { + mySystem = new UriDt(theUri); + return this; + } + + + /** + * Gets the value(s) for code (Code - if blank, this is not a choosable code). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public CodeDt getCode() { + if (myCode == null) { + myCode = new CodeDt(); + } + return myCode; + } + + /** + * Sets the value(s) for code (Code - if blank, this is not a choosable code) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains setCode(CodeDt theValue) { + myCode = theValue; + return this; + } + + /** + * Sets the value for code (Code - if blank, this is not a choosable code) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains setCode( String theCode) { + myCode = new CodeDt(theCode); + return this; + } + + + /** + * Gets the value(s) for display (User display for the concept). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public StringDt getDisplay() { + if (myDisplay == null) { + myDisplay = new StringDt(); + } + return myDisplay; + } + + /** + * Sets the value(s) for display (User display for the concept) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains setDisplay(StringDt theValue) { + myDisplay = theValue; + return this; + } + + /** + * Sets the value for display (User display for the concept) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains setDisplay( String theString) { + myDisplay = new StringDt(theString); + return this; + } + + + /** + * Gets the value(s) for contains (Codes contained in this concept). + * creating it if it does + * not exist. Will not return null. + * + *

+ * Definition: + * + *

+ */ + public java.util.List getContains() { + if (myContains == null) { + myContains = new java.util.ArrayList(); + } + return myContains; + } + + /** + * Sets the value(s) for contains (Codes contained in this concept) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains setContains(java.util.List theValue) { + myContains = theValue; + return this; + } + + /** + * Adds and returns a new value for contains (Codes contained in this concept) + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains addContains() { + ExpansionContains newType = new ExpansionContains(); + getContains().add(newType); + return newType; + } + + /** + * Gets the first repetition for contains (Codes contained in this concept), + * creating it if it does not already exist. + * + *

+ * Definition: + * + *

+ */ + public ExpansionContains getContainsFirstRep() { + if (getContains().isEmpty()) { + return addContains(); + } + return getContains().get(0); + } + + + } + + + + + +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/primitive/BoundCodeDt.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/primitive/BoundCodeDt.java new file mode 100644 index 00000000000..6704540264d --- /dev/null +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/model/primitive/BoundCodeDt.java @@ -0,0 +1,55 @@ +package ca.uhn.fhir.model.primitive; + +/* + * #%L + * HAPI FHIR - Core Library + * %% + * Copyright (C) 2014 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. + * #L% + */ + +import ca.uhn.fhir.model.api.IValueSetEnumBinder; +import ca.uhn.fhir.model.api.annotation.DatatypeDef; + +@DatatypeDef(name = "code", isSpecialization = true) +public class BoundCodeDt> extends CodeDt { + + private IValueSetEnumBinder myBinder; + + public BoundCodeDt(IValueSetEnumBinder theBinder) { + myBinder = theBinder; + } + + public BoundCodeDt(IValueSetEnumBinder theBinder, T theValue) { + myBinder = theBinder; + setValueAsEnum(theValue); + } + + public void setValueAsEnum(T theValue) { + if (theValue==null) { + setValue(null); + } else { + setValue(myBinder.toCodeString(theValue)); + } + } + + public T getValueAsEnum() { + T retVal = myBinder.fromCodeString(getValue()); + if (retVal == null) { + // TODO: throw special exception type? + } + return retVal; + } +} diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java index 68e3c9a8d50..a1d3547b9d8 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderClientMojo.java @@ -49,6 +49,12 @@ public class TinderClientMojo extends AbstractMojo { @Parameter(required = true, defaultValue = "false") private boolean generateSearchForAllParams; + @Parameter(alias = "version", required = true, defaultValue="dstu") + private String version = "dstu"; + + @Parameter(required = true, defaultValue = "${project.build.directory}/..") + private String baseDir; + private List myResources = new ArrayList(); private String myPackageBase; private File myDirectoryBase; @@ -76,7 +82,7 @@ public class TinderClientMojo extends AbstractMojo { FhirContext ctx = new FhirContext(Conformance.class); IBasicClient client = ctx.newRestfulClient(IBasicClient.class, serverBaseHref); - Conformance conformance = client.getServerConformanceStatement(); + Conformance conformance = (Conformance)client.getServerConformanceStatement(); if (conformance.getRest().size() != 1) { throw new MojoFailureException("Found " + conformance.getRest().size() + " rest definitions in Conformance resource. Need exactly 1."); @@ -87,7 +93,7 @@ public class TinderClientMojo extends AbstractMojo { throw new MojoFailureException("Conformance mode is not server, found: " + rest.getMode().getValue()); } - ProfileParser pp = new ProfileParser(); + ProfileParser pp = new ProfileParser(version,baseDir ); int index = 0; for (RestResource nextResource : rest.getResource()) { if (StringUtils.isBlank(nextResource.getProfile().getReference().getValue())) { diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java index d3bb9c82dd0..2a32ce79f08 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderJpaRestServerMojo.java @@ -42,6 +42,9 @@ public class TinderJpaRestServerMojo extends AbstractMojo { @Parameter(required = true) private List baseResourceNames; + @Parameter(required = true, defaultValue = "${project.build.directory}/..") + private String baseDir; + @Component private MavenProject myProject; @@ -51,7 +54,7 @@ public class TinderJpaRestServerMojo extends AbstractMojo { File directoryBase = new File(targetDirectory, packageBase.replace(".", File.separatorChar + "")); directoryBase.mkdirs(); - ResourceGeneratorUsingSpreadsheet gen = new ResourceGeneratorUsingSpreadsheet(); + ResourceGeneratorUsingSpreadsheet gen = new ResourceGeneratorUsingSpreadsheet("dstu", baseDir); gen.setBaseResourceNames(baseResourceNames); try { diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java index 05400986b75..156d9aa2bcc 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/TinderStructuresMojo.java @@ -37,6 +37,9 @@ public class TinderStructuresMojo extends AbstractMojo { @Parameter(alias = "package", required = true) private String packageName; + @Parameter(alias = "version", required = true, defaultValue="dstu") + private String version = "dstu"; + @Parameter(required = false) private List resourceProfileFiles; @@ -49,6 +52,9 @@ public class TinderStructuresMojo extends AbstractMojo { @Parameter(required = true, defaultValue = "${project.build.directory}/generated-resources/tinder") private String targetResourceDirectory; + @Parameter(required = true, defaultValue = "${project.build.directory}/..") + private String baseDir; + @Override public void execute() throws MojoExecutionException, MojoFailureException { if (StringUtils.isBlank(packageName)) { @@ -70,7 +76,7 @@ public class TinderStructuresMojo extends AbstractMojo { directoryBase.mkdirs(); ourLog.info(" * Output Source Directory: " + directoryBase.getAbsolutePath()); - ValueSetGenerator vsp = new ValueSetGenerator(); + ValueSetGenerator vsp = new ValueSetGenerator(version); vsp.setResourceValueSetFiles(resourceValueSetFiles); try { vsp.parse(); @@ -81,7 +87,7 @@ public class TinderStructuresMojo extends AbstractMojo { ourLog.info("Loading Datatypes..."); Map datatypeLocalImports = new HashMap(); - DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet(); + DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet(version, baseDir); if (buildDatatypes) { try { dtp.parse(); @@ -94,7 +100,7 @@ public class TinderStructuresMojo extends AbstractMojo { datatypeLocalImports = dtp.getLocalImports(); } - ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet(); + ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet(version, baseDir); if (baseResourceNames != null && baseResourceNames.size() > 0) { ourLog.info("Loading Resources..."); try { @@ -115,7 +121,7 @@ public class TinderStructuresMojo extends AbstractMojo { rp.writeAll(resSubDirectoryBase, resDirectoryBase, packageName); } - ProfileParser pp = new ProfileParser(); + ProfileParser pp = new ProfileParser(version, baseDir); if (resourceProfileFiles != null) { ourLog.info("Loading profiles..."); for (ProfileFileDefinition next : resourceProfileFiles) { @@ -198,35 +204,44 @@ public class TinderStructuresMojo extends AbstractMojo { public static void main(String[] args) throws Exception { + // ProfileParser pp = new ProfileParser(); // pp.parseSingleProfile(new File("../hapi-tinder-test/src/test/resources/profile/patient.xml"), "http://foo"); - ValueSetGenerator vsp = new ValueSetGenerator(); + ValueSetGenerator vsp = new ValueSetGenerator("dev"); // vsp.setResourceValueSetFiles(theResourceValueSetFiles);Directory("src/main/resources/vs/"); vsp.parse(); - DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet(); + DatatypeGeneratorUsingSpreadsheet dtp = new DatatypeGeneratorUsingSpreadsheet("dev", "."); dtp.parse(); + dtp.markResourcesForImports(); dtp.bindValueSets(vsp); + Map datatypeLocalImports = dtp.getLocalImports(); - String dtOutputDir = "target/generated-sources/ca/uhn/fhir/model/dstu/composite"; - dtp.writeAll(new File(dtOutputDir), null, "ca.uhn.fhir.model.dstu"); + String dtOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/composite"; - ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet(); - rp.setBaseResourceNames(Arrays.asList("securityevent")); + ResourceGeneratorUsingSpreadsheet rp = new ResourceGeneratorUsingSpreadsheet("dev", "."); + rp.setBaseResourceNames(Arrays.asList("referralrequest", "patient","practitioner","encounter", + "organization","location","relatedperson","appointment","slot","order","availability","device", "valueset")); rp.parse(); rp.bindValueSets(vsp); + rp.markResourcesForImports(); // rp.bindValueSets(vsp); - String rpOutputDir = "target/generated-sources/ca/uhn/fhir/model/dstu/resource"; - String rpSOutputDir = "target/generated-resources/ca/uhn/fhir/model/dstu"; - + String rpOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/resource"; + String rpSOutputDir = "target/generated-resources/tinder/ca/uhn/fhir/model/dev"; + + dtp.combineContentMaps(rp); rp.combineContentMaps(dtp); - rp.writeAll(new File(rpOutputDir), new File(rpSOutputDir), "ca.uhn.fhir.model.dstu"); + rp.getLocalImports().putAll(datatypeLocalImports); + datatypeLocalImports.putAll(rp.getLocalImports()); - String vsOutputDir = "target/generated-sources/ca/uhn/fhir/model/dstu/valueset"; - vsp.writeMarkedValueSets(new File(vsOutputDir), "ca.uhn.fhir.model.dstu"); + dtp.writeAll(new File(dtOutputDir), null, "ca.uhn.fhir.model.dev"); + rp.writeAll(new File(rpOutputDir), new File(rpSOutputDir), "ca.uhn.fhir.model.dev"); + + String vsOutputDir = "target/generated-sources/tinder/ca/uhn/fhir/model/dev/valueset"; + vsp.writeMarkedValueSets(new File(vsOutputDir), "ca.uhn.fhir.model.dev"); } public static class ProfileFileDefinition { diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java index 03fe1905848..79b30d312c3 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/ValueSetGenerator.java @@ -43,6 +43,11 @@ public class ValueSetGenerator { private Map myValueSets = new HashMap(); private int myValueSetCount; private int myConceptCount; + private String myVersion; + + public ValueSetGenerator(String theVersion) { + myVersion =theVersion; + } public String getClassForValueSetIdAndMarkAsNeeded(String theId) { ValueSetTm vs = myValueSets.get(theId); @@ -62,7 +67,7 @@ public class ValueSetGenerator { IParser newXmlParser = new FhirContext(ValueSet.class).newXmlParser(); ourLog.info("Parsing built-in ValueSets"); - String vs = IOUtils.toString(ValueSetGenerator.class.getResourceAsStream("/vs/all-valuesets-bundle.xml")); + String vs = IOUtils.toString(ValueSetGenerator.class.getResourceAsStream("/vs/" + myVersion + "/all-valuesets-bundle.xml")); Bundle bundle = newXmlParser.parseBundle(vs); for (BundleEntry next : bundle.getEntries()) { ValueSet nextVs = (ValueSet) next.getResource(); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java index 650ffb9b4f1..29cd2fe24a1 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/BaseElement.java @@ -48,10 +48,10 @@ public abstract class BaseElement { myChildren = new ArrayList(); } myChildren.add(theElem); - -// if (theElem.getDeclaringClassNameComplete()==null) { - theElem.setDeclaringClassNameComplete(getDeclaringClassNameCompleteForChildren()); -// } + + // if (theElem.getDeclaringClassNameComplete()==null) { + theElem.setDeclaringClassNameComplete(getDeclaringClassNameCompleteForChildren()); + // } } public String getBinding() { @@ -63,11 +63,11 @@ public abstract class BaseElement { } public String getCardMax() { - return defaultString(myCardMax,"1"); + return defaultString(myCardMax, "1"); } public String getCardMin() { - return defaultString(myCardMin,"0"); + return defaultString(myCardMin, "0"); } public Map getChildElementNameToSlicing() { @@ -90,7 +90,7 @@ public abstract class BaseElement { } private String toStringConstant(String theDefinition) { - if (theDefinition==null) { + if (theDefinition == null) { return ""; } StringBuffer b = new StringBuffer(); @@ -188,7 +188,7 @@ public abstract class BaseElement { public void setElementName(String theName) { myElementName = theName; } - + public void setElementNameAndDeriveParentElementName(String theName) { int lastDot = theName.lastIndexOf('.'); if (lastDot == -1) { @@ -220,16 +220,21 @@ public abstract class BaseElement { public void clearTypes() { getType().clear(); } - + public void setTypeFromString(String theType) { if (theType == null) { myType = null; return; } String typeString = theType; + typeString = typeString.replace("Reference (", "Reference("); + if (typeString.toLowerCase().startsWith("resource(")) { typeString = typeString.substring("Resource(".length(), typeString.length() - 1); myResourceRef = true; + } else if (typeString.toLowerCase().startsWith("reference(")) { + typeString = typeString.substring("Reference(".length(), typeString.length() - 1); + myResourceRef = true; } else if (typeString.startsWith("@")) { typeString = typeString.substring(1); typeString = ResourceBlock.convertFhirPathNameToClassName(typeString); @@ -238,22 +243,34 @@ public abstract class BaseElement { } if (StringUtils.isNotBlank(typeString)) { + + int idx = typeString.indexOf("Reference("); + if (idx != -1) { + int endIdx = typeString.indexOf(")"); + typeString = typeString.substring(0,idx) + typeString.substring(idx, endIdx).replace("|", ",") + typeString.substring(endIdx); + } + String[] types = typeString.replace("=", "").split("\\|"); for (String nextType : types) { nextType = nextType.trim(); - if (nextType.endsWith(")")){ - nextType = nextType.substring(0, nextType.length()-1); + if (nextType.endsWith(")")) { + nextType = nextType.substring(0, nextType.length() - 1); } if (nextType.toLowerCase().startsWith("resource(")) { nextType = nextType.substring("Resource(".length(), nextType.length()); nextType = nextType.substring(0, 1).toUpperCase() + nextType.substring(1); + } else if (nextType.toLowerCase().startsWith("reference(")) { + nextType = nextType.substring("Reference(".length(), nextType.length()); + nextType = nextType.substring(0, 1).toUpperCase() + nextType.substring(1); } else { nextType = nextType.substring(0, 1).toUpperCase() + nextType.substring(1); nextType = nextType + getTypeSuffix(); } - if (isNotBlank(nextType)) { - getType().add(nextType); + for (String next : nextType.split(",")) { + if (isNotBlank(next.trim())) { + getType().add(next.trim()); + } } } } @@ -276,7 +293,6 @@ public abstract class BaseElement { return false; // TODO: implemment } - public boolean isHasExtensionUrl() { return StringUtils.isNotBlank(myExtensionUrl); } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Child.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Child.java index 723944e6143..7166d7c6878 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Child.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/Child.java @@ -1,11 +1,14 @@ package ca.uhn.fhir.tinder.model; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.lang3.StringUtils; +import ca.uhn.fhir.model.api.BasePrimitive; import ca.uhn.fhir.model.api.IDatatype; import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; @@ -38,11 +41,10 @@ public abstract class Child extends BaseElement { return getCardMax(); } } - @Override public String toString() { - return getClass().getSimpleName()+"[" + getName() + "]"; + return getClass().getSimpleName() + "[" + getName() + "]"; } /** @@ -62,9 +64,9 @@ public abstract class Child extends BaseElement { if ("Class".equals(elementName)) { elementName = "ClassElement"; } -// if ("Language".equals(elementName)) { -// elementName = "LanguageElement"; -// } + // if ("Language".equals(elementName)) { + // elementName = "LanguageElement"; + // } return elementName; } @@ -75,7 +77,7 @@ public abstract class Child extends BaseElement { } else if (this.getType().size() == 1 || this instanceof ResourceBlock) { if (isBoundCode()) { retVal = "Bound" + getSingleType() + "<" + getBindingClass() + ">"; - }else { + } else { retVal = getSingleType(); } } else { @@ -96,7 +98,7 @@ public abstract class Child extends BaseElement { public String getReferenceTypeForConstructor() { return getReferenceType().replaceAll("^java.util.List<", "java.util.ArrayList<"); } - + public List getReferenceTypesForMultiple() { ArrayList retVal = new ArrayList(); for (String next : getType()) { @@ -104,11 +106,11 @@ public abstract class Child extends BaseElement { next = "IResource"; } retVal.add(next); -// retVal.add(next + getTypeSuffix()); + // retVal.add(next + getTypeSuffix()); } return retVal; } - + public List getSimpleSetters() { if (isBoundCode()) { return Collections.emptyList(); @@ -120,11 +122,11 @@ public abstract class Child extends BaseElement { String retVal; String elemName = this.getType().get(0); elemName = elemName.substring(0, 1).toUpperCase() + elemName.substring(1); -// if (this instanceof ResourceBlock) { - retVal = (elemName); -// } else { -// retVal = (elemName + getTypeSuffix()); -// } + // if (this instanceof ResourceBlock) { + retVal = (elemName); + // } else { + // retVal = (elemName + getTypeSuffix()); + // } return retVal; } @@ -144,6 +146,36 @@ public abstract class Child extends BaseElement { return false; } + public boolean isPrimitive() { + + if (IDatatype.class.getSimpleName().equals(getReferenceType())) { + return false; + } + + try { + String name = "ca.uhn.fhir.model.primitive." + getSingleType(); + Class.forName(name); + return true; + } catch (ClassNotFoundException e) { + return false; + } + } + + public String getPrimitiveType() throws ClassNotFoundException { + String name = "ca.uhn.fhir.model.primitive." + getSingleType(); + Class clazz = Class.forName(name); + while (!clazz.getSuperclass().equals(BasePrimitive.class)) { + clazz = clazz.getSuperclass(); + if (clazz.equals(Object.class)) { + throw new Error("Parent of " + name + " is not BasePrimitive"); + } + } + + ParameterizedType type = (ParameterizedType) clazz.getGenericSuperclass(); + Class rawType = (Class) type.getActualTypeArguments()[0]; + return rawType.getSimpleName(); + } + public boolean isBoundCode() { String singleType = getSingleType(); if ("CodeDt".equals(singleType) || "CodeableConceptDt".equals(singleType)) { @@ -162,5 +194,4 @@ public abstract class Child extends BaseElement { return true; } - } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java index 11220dce24a..5989bb3694a 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/model/SearchParameter.java @@ -77,7 +77,11 @@ public class SearchParameter { } public void setName(String theName) { - myName = theName; + if (theName != null && Character.isUpperCase(theName.charAt(0))) { + myName = theName.substring(theName.indexOf('.')+1); + }else { + myName = theName; + } } public void setPath(String thePath) { diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java index e0ff32e29a0..bb3cb19ee4c 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureParser.java @@ -32,6 +32,7 @@ import ca.uhn.fhir.model.api.ExtensionDt; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.model.api.annotation.SimpleSetter; import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt; +import ca.uhn.fhir.model.dstu.resource.Binary; import ca.uhn.fhir.tinder.TinderStructuresMojo; import ca.uhn.fhir.tinder.ValueSetGenerator; import ca.uhn.fhir.tinder.model.BaseElement; @@ -47,40 +48,41 @@ import ca.uhn.fhir.tinder.model.SimpleSetter.Parameter; public abstract class BaseStructureParser { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseStructureParser.class); + private String myBaseDir; private ArrayList myExtensions; private TreeSet myImports = new TreeSet(); - private Map myLocallyDefinedClassNames = new HashMap(); - private List myResources = new ArrayList(); private boolean myImportsResolved; - private TreeMap myNameToResourceClass = new TreeMap(); + private Map myLocallyDefinedClassNames = new HashMap(); private TreeMap myNameToDatatypeClass = new TreeMap(); + private TreeMap myNameToResourceClass = new TreeMap(); + private String myPackageBase; + private List myResources = new ArrayList(); + private String myVersion; - public TreeMap getNameToDatatypeClass() { - return myNameToDatatypeClass; + public BaseStructureParser(String theVersion, String theBaseDir) { + myVersion = theVersion; + myBaseDir = theBaseDir; } - public void combineContentMaps(BaseStructureParser theStructureParser) { - myNameToResourceClass.putAll(theStructureParser.myNameToResourceClass); - myNameToDatatypeClass.putAll(theStructureParser.myNameToDatatypeClass); - theStructureParser.myNameToResourceClass.putAll(myNameToResourceClass); - theStructureParser.myNameToDatatypeClass.putAll(myNameToDatatypeClass); + public String getVersion() { + return myVersion; } - + + private void addImport(String bindingClass) { + myImports.add(bindingClass); + } + public void addResource(BaseRootType theResource) { myResources.add(theResource); } - public Map getLocalImports() { - return myLocallyDefinedClassNames; - } - private void bindValueSets(BaseElement theResource, ValueSetGenerator theVsp) { if (isNotBlank(theResource.getBinding())) { String bindingClass = theVsp.getClassForValueSetIdAndMarkAsNeeded(theResource.getBinding()); if (bindingClass != null) { ourLog.info("Adding binding ValueSet class: {}", bindingClass); theResource.setBindingClass(bindingClass); - myImports.add(bindingClass); + addImport(bindingClass); myLocallyDefinedClassNames.put(bindingClass, "valueset"); } else { ourLog.info("No binding found for: {}", theResource.getBinding()); @@ -98,7 +100,15 @@ public abstract class BaseStructureParser { } } - private ca.uhn.fhir.model.api.annotation.SimpleSetter.Parameter findAnnotation(Class theBase, Annotation[] theAnnotations, Class theClass) { + public void combineContentMaps(BaseStructureParser theStructureParser) { + myNameToResourceClass.putAll(theStructureParser.myNameToResourceClass); + myNameToDatatypeClass.putAll(theStructureParser.myNameToDatatypeClass); + theStructureParser.myNameToResourceClass.putAll(myNameToResourceClass); + theStructureParser.myNameToDatatypeClass.putAll(myNameToDatatypeClass); + } + + private ca.uhn.fhir.model.api.annotation.SimpleSetter.Parameter findAnnotation(Class theBase, Annotation[] theAnnotations, + Class theClass) { for (Annotation next : theAnnotations) { if (theClass.equals(next.annotationType())) { return (ca.uhn.fhir.model.api.annotation.SimpleSetter.Parameter) next; @@ -107,8 +117,51 @@ public abstract class BaseStructureParser { throw new IllegalArgumentException(theBase.getCanonicalName() + " has @" + SimpleSetter.class.getCanonicalName() + " constructor with no/invalid parameter annotation"); } + /** + * Example: Encounter has an internal block class named "Location", but it also has a reference to the Location resource type, so we need to use the fully qualified name for that resource + * reference + */ + private void fixResourceReferenceClassNames(BaseElement theNext, String thePackageBase) { + for (BaseElement next : theNext.getChildren()) { + fixResourceReferenceClassNames(next, thePackageBase); + } + + if (theNext.isResourceRef()) { + for (int i = 0; i < theNext.getType().size(); i++) { + String nextTypeName = theNext.getType().get(i); + if ("Any".equals(nextTypeName)) { + continue; + } + // if ("Location".equals(nextTypeName)) { + // ourLog.info("***** Checking for Location"); + // ourLog.info("***** Imports are: {}", new + // TreeSet(myImports)); + // } + boolean found = false; + for (String nextImport : myImports) { + if (nextImport.endsWith(".resource." + nextTypeName)) { + // ourLog.info("***** Found match " + nextImport); + theNext.getType().set(i, nextImport); + found = true; + } + } + if (!found) { + theNext.getType().set(i, thePackageBase + ".resource." + nextTypeName); + } + } + } + } + protected abstract String getFilenameSuffix(); + public Map getLocalImports() { + return myLocallyDefinedClassNames; + } + + public TreeMap getNameToDatatypeClass() { + return myNameToDatatypeClass; + } + public List getResources() { return myResources; } @@ -119,6 +172,105 @@ public abstract class BaseStructureParser { return true; } + public void markResourcesForImports() { + for (BaseRootType next : myResources) { + if (next instanceof Resource) { + myLocallyDefinedClassNames.put(next.getName(), "resource"); + } else if (next instanceof Composite) { + myLocallyDefinedClassNames.put(next.getName() + "Dt", "composite"); + } else { + throw new IllegalStateException(next.getClass() + ""); + } + } + } + + private void scanForCorrections(BaseRootType theNext) { + if (theNext.getElementName().equals("ResourceReference")) { + for (BaseElement next : theNext.getChildren()) { + if (next.getElementName().equals("reference")) { + next.clearTypes(); + next.setTypeFromString("id"); + scanForSimpleSetters((Child) next); + } + } + } + } + + private String scanForImportNamesAndReturnFqn(String theNextType) throws MojoFailureException { + if ("Any".equals(theNextType)) { + return (IResource.class.getCanonicalName()); + } + if ("ExtensionDt".equals(theNextType)) { + return (ExtensionDt.class.getCanonicalName()); + } + if ("ResourceReferenceDt".equals(theNextType)) { + return ResourceReferenceDt.class.getCanonicalName(); + } + if ("Binary".equals(theNextType)) { + return Binary.class.getCanonicalName(); + } + // QuantityCompararatorEnum + // QuantityComparatorEnum + + if (myLocallyDefinedClassNames.containsKey(theNextType)) { + return (theNextType); + } else { + try { + String type = myPackageBase + ".composite." + theNextType; + Class.forName(type); + return (type); + } catch (ClassNotFoundException e) { + try { + String type = "ca.uhn.fhir.model."+myVersion+ ".composite." + theNextType; + Class.forName(type); + return (type); + } catch (ClassNotFoundException e5) { + try { + String type = "ca.uhn.fhir.model."+myVersion+".resource." + theNextType; + Class.forName(type); + return (type); + } catch (ClassNotFoundException e1) { + try { + String type = "ca.uhn.fhir.model.primitive." + theNextType; + Class.forName(type); + return (type); + } catch (ClassNotFoundException e2) { + try { + String type = myPackageBase + ".valueset." + theNextType; + Class.forName(type); + return (type); + } catch (ClassNotFoundException e3) { + try { + String type = "ca.uhn.fhir.model.api." + theNextType; + Class.forName(type); + return (type); + } catch (ClassNotFoundException e4) { + try { + String type = "ca.uhn.fhir.model."+myVersion+".valueset." + theNextType; + Class.forName(type); + return (type); + } catch (ClassNotFoundException e6) { + String fileName = myBaseDir + "/src/main/java/" + myPackageBase.replace('.', '/') + "/composite/" + theNextType + ".java"; + File file = new File(fileName); + if (file.exists()) { + return myPackageBase + ".composite." + theNextType; + } + fileName = myBaseDir + "/src/main/java/ca/uhn/fhir/model/primitive/" + theNextType + ".java"; + file = new File(fileName); + if (file.exists()) { + return "ca.uhn.fhir.model.primitive." + theNextType; + } + throw new MojoFailureException("Unknown type: " + theNextType + " - Have locally defined names: " + new TreeSet(myLocallyDefinedClassNames.keySet())); + } + } + } + } + } + } + } + } + } + private void scanForImportsNames(BaseElement theNext) throws MojoFailureException { for (BaseElement next : theNext.getChildren()) { ourLog.debug("Element Name: {}", next.getName()); @@ -138,52 +290,7 @@ public abstract class BaseStructureParser { } private void scanForImportsNames(String theNextType) throws MojoFailureException { - myImports.add(scanForImportNamesAndReturnFqn(theNextType)); - } - - private String scanForImportNamesAndReturnFqn(String theNextType) throws MojoFailureException { - if ("Any".equals(theNextType)) { - return (IResource.class.getCanonicalName()); - } - if ("ExtensionDt".equals(theNextType)) { - return (ExtensionDt.class.getCanonicalName()); - } - - if (myLocallyDefinedClassNames.containsKey(theNextType)) { - return (theNextType); - } else { - try { - String type = "ca.uhn.fhir.model.dstu.composite." + theNextType; - Class.forName(type); - return (type); - } catch (ClassNotFoundException e) { - try { - String type = "ca.uhn.fhir.model.dstu.resource." + theNextType; - Class.forName(type); - return (type); - } catch (ClassNotFoundException e1) { - try { - String type = "ca.uhn.fhir.model.primitive." + theNextType; - Class.forName(type); - return (type); - } catch (ClassNotFoundException e2) { - try { - String type = "ca.uhn.fhir.model.dstu.valueset." + theNextType; - Class.forName(type); - return (type); - } catch (ClassNotFoundException e3) { - try { - String type = "ca.uhn.fhir.model.api." + theNextType; - Class.forName(type); - return (type); - } catch (ClassNotFoundException e4) { - throw new MojoFailureException("Unknown type: " + theNextType + " - Have locally defined names: " + new TreeSet(myLocallyDefinedClassNames.keySet())); - } - } - } - } - } - } + addImport(scanForImportNamesAndReturnFqn(theNextType)); } protected void scanForSimpleSetters(Child theElem) { @@ -192,9 +299,13 @@ public abstract class BaseStructureParser { try { childDt = Class.forName("ca.uhn.fhir.model.primitive." + theElem.getReferenceTypesForMultiple().get(0)); } catch (ClassNotFoundException e) { - try { - childDt = Class.forName("ca.uhn.fhir.model.dstu.composite." + theElem.getReferenceTypesForMultiple().get(0)); - } catch (ClassNotFoundException e2) { + if (myVersion.equals("dstu")) { + try { + childDt = Class.forName("ca.uhn.fhir.model.dstu.composite." + theElem.getReferenceTypesForMultiple().get(0)); + } catch (ClassNotFoundException e2) { + return; + } + } else { return; } } @@ -221,7 +332,7 @@ public abstract class BaseStructureParser { p.setDatatype(paramTypes[i].getCanonicalName()); } else { if (paramTypes[i].getCanonicalName().startsWith("ca.uhn.fhir")) { - myImports.add(paramTypes[i].getSimpleName()); + addImport(paramTypes[i].getSimpleName()); } p.setDatatype(paramTypes[i].getSimpleName()); } @@ -262,6 +373,13 @@ public abstract class BaseStructureParser { myExtensions = theExts; } + private String translateClassName(String theName) { + if ("List".equals(theName)) { + return "ListResource"; + } + return theName; + } + private void write(BaseRootType theResource, File theFile, String thePackageBase) throws IOException, MojoFailureException { FileWriter w = new FileWriter(theFile, false); @@ -287,6 +405,7 @@ public abstract class BaseStructureParser { ctx.put("hash", "#"); ctx.put("imports", imports); ctx.put("profile", theResource.getProfile()); + ctx.put("version", myVersion); ctx.put("id", StringUtils.defaultString(theResource.getId())); if (theResource.getDeclaringClassNameComplete() != null) { ctx.put("className", theResource.getDeclaringClassNameComplete()); @@ -317,19 +436,9 @@ public abstract class BaseStructureParser { w.close(); } - public void markResourcesForImports() { - for (BaseRootType next : myResources) { - if (next instanceof Resource) { - myLocallyDefinedClassNames.put(next.getName(), "resource"); - } else if (next instanceof Composite) { - myLocallyDefinedClassNames.put(next.getName() + "Dt", "composite"); - } else { - throw new IllegalStateException(next.getClass() + ""); - } - } - } - public void writeAll(File theOutputDirectory, File theResourceOutputDirectory, String thePackageBase) throws MojoFailureException { + myPackageBase = thePackageBase; + if (!theOutputDirectory.exists()) { theOutputDirectory.mkdirs(); } @@ -389,6 +498,7 @@ public abstract class BaseStructureParser { VelocityContext ctx = new VelocityContext(); ctx.put("nameToResourceClass", myNameToResourceClass); ctx.put("nameToDatatypeClass", myNameToDatatypeClass); + ctx.put("version", myVersion); VelocityEngine v = new VelocityEngine(); v.setProperty("resource.loader", "cp"); @@ -406,60 +516,6 @@ public abstract class BaseStructureParser { } } - private void scanForCorrections(BaseRootType theNext) { - if (theNext.getElementName().equals("ResourceReference")) { - for (BaseElement next : theNext.getChildren()) { - if (next.getElementName().equals("reference")) { - next.clearTypes(); - next.setTypeFromString("id"); - scanForSimpleSetters((Child) next); - } - } - } - } - - private String translateClassName(String theName) { - if ("List".equals(theName)) { - return "ListResource"; - } - return theName; - } - - /** - * Example: Encounter has an internal block class named "Location", but it also has a reference to the Location - * resource type, so we need to use the fully qualified name for that resource reference - */ - private void fixResourceReferenceClassNames(BaseElement theNext, String thePackageBase) { - for (BaseElement next : theNext.getChildren()) { - fixResourceReferenceClassNames(next, thePackageBase); - } - - if (theNext.isResourceRef()) { - for (int i = 0; i < theNext.getType().size(); i++) { - String nextTypeName = theNext.getType().get(i); - if ("Any".equals(nextTypeName)) { - continue; - } - // if ("Location".equals(nextTypeName)) { - // ourLog.info("***** Checking for Location"); - // ourLog.info("***** Imports are: {}", new - // TreeSet(myImports)); - // } - boolean found = false; - for (String nextImport : myImports) { - if (nextImport.endsWith(".resource." + nextTypeName)) { - // ourLog.info("***** Found match " + nextImport); - theNext.getType().set(i, nextImport); - found = true; - } - } - if (!found) { - theNext.getType().set(i, thePackageBase + ".resource." + nextTypeName); - } - } - } - } - static String cellValue(Node theRowXml, int theCellIndex) { NodeList cells = ((Element) theRowXml).getElementsByTagName("Cell"); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java index c9ce31e768a..ec72e28df8b 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/BaseStructureSpreadsheetParser.java @@ -1,6 +1,6 @@ package ca.uhn.fhir.tinder.parser; -import static org.apache.commons.lang3.StringUtils.*; +import static org.apache.commons.lang3.StringUtils.isBlank; import java.io.InputStream; import java.util.ArrayList; @@ -31,6 +31,11 @@ import ca.uhn.fhir.tinder.model.SimpleChild; import ca.uhn.fhir.tinder.util.XMLUtils; public abstract class BaseStructureSpreadsheetParser extends BaseStructureParser { + + public BaseStructureSpreadsheetParser(String theVersion, String theBaseDir) { + super(theVersion, theBaseDir); + } + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseStructureSpreadsheetParser.class); private int myColBinding; private int myColCard; diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java index 11f9f272c39..f06e4f87e91 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/DatatypeGeneratorUsingSpreadsheet.java @@ -20,9 +20,16 @@ import com.google.common.reflect.ClassPath.ClassInfo; public class DatatypeGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetParser { + private String myVersion; + + public DatatypeGeneratorUsingSpreadsheet(String theVersion, String theBaseDir) { + super(theVersion, theBaseDir); + myVersion = theVersion; + } + @Override protected String getTemplate() { - return "/vm/dt_composite.vm"; + return "dstu".equals(myVersion) ? "/vm/dt_composite_dstu.vm" : "/vm/dt_composite.vm"; } @Override @@ -71,22 +78,30 @@ public class DatatypeGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP protected List getInputStreamNames() { ArrayList retVal = new ArrayList(); - retVal.add(("/dt/address.xml")); - retVal.add(("/dt/coding.xml")); - retVal.add(("/dt/humanname.xml")); - retVal.add(("/dt/period.xml")); - retVal.add(("/dt/ratio.xml")); - retVal.add(("/dt/schedule.xml")); - retVal.add(("/dt/attachment.xml")); - retVal.add(("/dt/contact.xml")); - retVal.add(("/dt/identifier.xml")); - retVal.add(("/dt/quantity.xml")); - retVal.add(("/dt/resourcereference.xml")); - retVal.add(("/dt/codeableconcept.xml")); -// retVal.add(("/dt/extension.xml")); -// retVal.add(("/dt/narrative.xml")); - retVal.add(("/dt/range.xml")); - retVal.add(("/dt/sampleddata.xml")); + retVal.add(("/dt/" + myVersion + "/address.xml")); + retVal.add(("/dt/" + myVersion + "/attachment.xml")); + retVal.add(("/dt/" + myVersion + "/codeableconcept.xml")); + retVal.add(("/dt/" + myVersion + "/coding.xml")); + retVal.add(("/dt/" + myVersion + "/humanname.xml")); + retVal.add(("/dt/" + myVersion + "/identifier.xml")); + retVal.add(("/dt/" + myVersion + "/period.xml")); + retVal.add(("/dt/" + myVersion + "/ratio.xml")); + retVal.add(("/dt/" + myVersion + "/quantity.xml")); + retVal.add(("/dt/" + myVersion + "/range.xml")); + retVal.add(("/dt/" + myVersion + "/sampleddata.xml")); + + if ("dstu".equals(myVersion)) { + retVal.add(("/dt/" + myVersion + "/contact.xml")); +// retVal.add(("/dt/" + myVersion + "/resourcereference.xml")); + retVal.add(("/dt/" + myVersion + "/schedule.xml")); + } + + if (!myVersion.equals("dstu")) { + retVal.add(("/dt/" + myVersion + "/reference.xml")); + retVal.add(("/dt/" + myVersion + "/attachment.xml")); + retVal.add(("/dt/" + myVersion + "/contactpoint.xml")); + retVal.add(("/dt/" + myVersion + "/timing.xml")); + } return retVal; } diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ProfileParser.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ProfileParser.java index b990d7b6010..82895011177 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ProfileParser.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ProfileParser.java @@ -38,6 +38,10 @@ import ca.uhn.fhir.tinder.model.Slicing; public class ProfileParser extends BaseStructureParser { + public ProfileParser(String theVersion, String theBaseDir) { + super(theVersion, theBaseDir); + } + private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ProfileParser.class); private ExtensionDefn findExtension(Profile theProfile, String theCode) { @@ -56,7 +60,7 @@ public class ProfileParser extends BaseStructureParser { @Override protected String getTemplate() { - return "/vm/resource.vm"; + return "dstu".equals(getVersion()) ? "/vm/resource_dstu.vm" : "/vm/resource.vm"; } public void parseSingleProfile(File theProfile, String theHttpUrl) throws MojoFailureException { @@ -304,7 +308,7 @@ public class ProfileParser extends BaseStructureParser { public static void main(String[] args) throws Exception { IParser parser = new FhirContext(Profile.class).newXmlParser(); - ProfileParser pp = new ProfileParser(); + ProfileParser pp = new ProfileParser("dev","."); String str = IOUtils.toString(new FileReader("../hapi-tinder-test/src/test/resources/profile/organization.xml")); Profile prof = parser.parseResource(Profile.class, str); diff --git a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java index f97f624b83b..38371f2bc67 100644 --- a/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java +++ b/hapi-tinder-plugin/src/main/java/ca/uhn/fhir/tinder/parser/ResourceGeneratorUsingSpreadsheet.java @@ -1,6 +1,5 @@ package ca.uhn.fhir.tinder.parser; -import java.io.File; import java.io.InputStream; import java.util.ArrayList; import java.util.Collection; @@ -11,14 +10,18 @@ import org.apache.maven.plugin.MojoFailureException; import ca.uhn.fhir.tinder.model.BaseRootType; import ca.uhn.fhir.tinder.model.Resource; - - public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetParser { private String myFilenameSuffix = ""; private List myInputStreamNames; private ArrayList myInputStreams; - private String myTemplate="/vm/resource.vm"; - + private String myTemplate = null; + private String myVersion; + + public ResourceGeneratorUsingSpreadsheet(String theVersion, String theBaseDir) { + super(theVersion, theBaseDir); + myVersion = theVersion; + } + public List getInputStreamNames() { return myInputStreamNames; } @@ -26,12 +29,13 @@ public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP public void setBaseResourceNames(List theBaseResourceNames) throws MojoFailureException { myInputStreamNames = theBaseResourceNames; myInputStreams = new ArrayList(); - + for (String next : theBaseResourceNames) { - InputStream nextRes = getClass().getResourceAsStream("/res/" + next + "-spreadsheet.xml"); + String resName = "/res/" + myVersion + "/" + next + "-spreadsheet.xml"; + InputStream nextRes = getClass().getResourceAsStream(resName); myInputStreams.add(nextRes); if (nextRes == null) { - throw new MojoFailureException("Unknown base resource name: " + next); + throw new MojoFailureException("Unknown base resource name: " + resName); } } } @@ -49,7 +53,6 @@ public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP return new Resource(); } - @Override protected String getFilenameSuffix() { return myFilenameSuffix; @@ -62,7 +65,13 @@ public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP @Override protected String getTemplate() { - return myTemplate; + if (myTemplate != null) { + return myTemplate; + } else if ("dstu".equals(myVersion)) { + return "/vm/resource_dstu.vm"; + } else { + return "/vm/resource.vm"; + } } @Override @@ -70,110 +79,4 @@ public class ResourceGeneratorUsingSpreadsheet extends BaseStructureSpreadsheetP return theFileName.endsWith("spreadsheet.xml"); } - public static void main(String[] args) throws Exception { - ResourceGeneratorUsingSpreadsheet p = new ResourceGeneratorUsingSpreadsheet(); - ArrayList names = new ArrayList(); - names.add("conceptmap"); - names.add("list"); - names.add("person"); - p.setBaseResourceNames(names); - p.parse(); - p.markResourcesForImports(); - p.writeAll(new File("target/gen/ca/uhn/fhir/model/dstu/resource"), null,"ca.uhn.fhir.model.dstu"); -// -// // TODO: this needs to be properly populated -// p.getAllDatatypes().add("String"); -// p.getAllDatatypes().add("Date"); -// p.getAllDatatypes().add("DateTime"); -// -//// p.setDirectory("src/test/resources/res"); -//// p.setResourceName("patient"); -//// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/ResourceWithExtensionsA.java"); -//// ArrayList exts = new ArrayList(); -//// Extension ext1 = new Extension("foo1", "http://foo/1", "string"); -//// exts.add(ext1); -//// Extension ext2 = new Extension("bar1", "http://bar/1", new Extension("bar11", "http://bar/1/1", "date"), new Extension("bar12", "http://bar/1/2", "date")); -//// exts.add(ext2); -//// p.setExtensions(exts); -//// p.parse(); -// -//// String basePath="../hapi-fhir-base/src/main/java"; -// String basePath="target/generated/valuesets"; -// -// p.setResourceName("medication"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Medication.java"); -// p.parse(); -// -// p.setDirectory("src/test/resources/res"); -// p.setResourceName("substance"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Substance.java"); -// p.parse(); -// -// -// p.setDirectory("src/test/resources/res"); -// p.setResourceName("valueset"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/ValueSetTm.java"); -// p.parse(); -// -// p.setDirectory("src/test/resources/res"); -// p.setResourceName("observation"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Observation.java"); -// p.parse(); -// -// p.setResourceName("profile"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Profile.java"); -// p.parse(); -// -// p.setResourceName("device"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Device.java"); -// p.parse(); -// -// p.setResourceName("group"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Group.java"); -// p.parse(); -// -// p.setResourceName("location"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Location.java"); -// p.parse(); -// -// p.setResourceName("organization"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Organization.java"); -// p.parse(); -// -// p.setResourceName("patient"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Patient.java"); -// p.parse(); -// -// p.setResourceName("specimen"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Specimen.java"); -// p.parse(); -// -// p.setResourceName("practitioner"); -// p.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/resource/Practitioner.java"); -// p.parse(); -// -// DatatypeSpreadsheetParser d = new DatatypeSpreadsheetParser(); -// d.setDirectory("src/test/resources/dt"); -// d.setDatatypeName("humanname"); -// d.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/composite/HumanNameDt.java"); -// d.parse(); -// -// d.setDatatypeName("contact"); -// d.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/composite/ContactDt.java"); -// d.parse(); -// -// d.setDatatypeName("address"); -// d.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/composite/AddressDt.java"); -// d.parse(); -// -// d.setDatatypeName("narrative"); -// d.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/composite/NarrativeDt.java"); -// d.parse(); -// -// d.setDatatypeName("quantity"); -// d.setOutputFile(basePath + "/ca/uhn/fhir/model/dstu/composite/QuantityDt.java"); -// d.parse(); - - } - } \ No newline at end of file diff --git a/hapi-tinder-plugin/src/main/resources/dt/dev/activitydefinition.xml b/hapi-tinder-plugin/src/main/resources/dt/dev/activitydefinition.xml new file mode 100644 index 00000000000..b81f6be91f2 --- /dev/null +++ b/hapi-tinder-plugin/src/main/resources/dt/dev/activitydefinition.xml @@ -0,0 +1,677 @@ + + + + + Grahame + Lloyd McKenzie + 2012-03-19T11:22:15Z + 2013-04-22T02:38:01Z + 14.00 + + + + + + 8445 + 23250 + 3360 + 3510 + False + False + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Element + Card. + Inv. + Is Modifier + UML + Type + Binding + Short Name + Definition + Aliases + Requirements + Comments + RIM Mapping + v2 Mapping + To Do + Committee Notes + + + ActivityDefinition + + + + + SharedDefinition + Information about a type of activity that can be performed + Used as part of care plans, protocols and other resources that describe + Act + + + ActivityDefinition.category + 0..1 + + + + code + ActivityDefinitionCategory + diet | drug | encounter | observation + + High-level categorization of the type of activity. + + May determine what types of extensions are permitted + + .classCode + + + + + + + Should this be an HL7-defined code? Do we need more (e.g. accomodation) + + + ActivityDefinition.code + 0..1 + + + + CodeableConcept + ActivityDefinitionType + Detail type of activity + Detailed description of the type of activity. E.g. What lab test, what procedure, what kind of encounter. + + Allows matching performed to planned as well as validation against protocols + Tends to be less relevant for activities involving particular products. + .code + + + + + + + + + + ActivityDefinition.timing[x] + 0..1 + + + + CodeableConcept | Schedule + ActivityTiming + When activity is to occur + The period, timing or frequency upon which the described activity is to occur. + + Allows prompting for activities and detection of missed planned activities. + + .effectiveTime + + Add constraint prohibiting event (once it won't raise an error on the name timingSchedule) + + + + + + + + ActivityDefinition.location + 0..1 + + + + Reference(Location) + + Where it should happen + Identifies the facility where the activity will occur. E.g. home, hospital, specific clinic, etc. + facility + Helps in planning of activity + May reference a specific clinical location or may just identify a type of location. + + + + + + + + + + + ActivityDefinition.performer + 0..* + + + + Reference(Practitioner|Organization|RelatedPerson|Patient) + + Who's responsible? + Identifies who's expected to be involved in the activity. + + Helps in planning of activity + + + + + + + + + + + + ActivityDefinition.product + 0..1 + + + + Reference(Medication|Substance) + + What's administered/supplied + Identifies the food, drug or other product being consumed or supplied in the activity. + + + + + + + + + + + + + + ActivityDefinition.quantity + 0..1 + + + + Quantity + + How much is administered/consumed/supplied + Identifies the quantity expected to be consumed at once (per dose, per meal, etc.) + dose + + + + + + + + + + + + + ActivityDefinition.details + 0..1 + + + + string + + Extra info on activity occurrence + This provides a textual description of constraints on the activity occurrence, including relation to other activities. It may also include objectives, pre-conditions and end-conditions. Finally, it may convey specifics about the activity such as body site, method, route, etc. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + +
+