From 86bd9a28fe3c9ce5dea8f0f4a5bf3218c885ad25 Mon Sep 17 00:00:00 2001 From: James Agnew Date: Sun, 1 Dec 2019 21:21:19 -0500 Subject: [PATCH] Fix to valueset expansion logic (#1613) * Fox to valueset expansion logic * Work on docs * Docs tweaks * Docs tweaks * Fix test * Remove unused class * Add changelog --- .../main/java/ca/uhn/fhir/util/DateUtils.java | 16 +- .../ca/uhn/fhir/validation/FhirValidator.java | 4 +- hapi-fhir-docs/pom.xml | 6 + .../ca/uhn/hapi/fhir/docs/BundleFetcher.java | 78 +-- .../fhir/docs/ClientTransactionExamples.java | 6 +- .../uhn/hapi/fhir/docs/FhirTesterConfig.java | 62 ++ .../hapi/fhir/docs/GenericClientExample.java | 6 +- .../uhn/hapi/fhir/docs/ValidatorExamples.java | 66 +- .../ca/uhn/hapi/fhir/docs/android/client.md | 2 +- .../ca/uhn/hapi/fhir/docs/appendix/faq.md | 10 +- .../ca/uhn/hapi/fhir/docs/appendix/logging.md | 4 +- .../fhir/docs/client/annotation_client.md | 56 ++ .../fhir/docs/client/client_configuration.md | 83 +++ .../ca/uhn/hapi/fhir/docs/client/examples.md | 106 ++++ .../hapi/fhir/docs/client/generic_client.md | 326 ++++++++++ .../uhn/hapi/fhir/docs/client/get_started.md | 5 + .../uhn/hapi/fhir/docs/client/introduction.md | 13 + .../fhir/docs/contributing/hacking_guide.md | 4 +- .../ca/uhn/hapi/fhir/docs/files.properties | 33 +- .../images/hapi-fhir-logging-complete.svg | 1 + .../fhir/docs/images/hapi-fhir-logging.svg | 1 + .../fhir/docs/images/hapi_usage_patterns.svg | 594 ++++++++++++++++++ .../restful-server-interceptors-exception.svg | 3 + .../images/restful-server-interceptors.svg | 3 + .../built_in_client_interceptors.md | 3 + .../built_in_server_interceptors.md | 3 + .../docs/interceptors/client_interceptors.md | 3 + .../docs/interceptors/server_interceptors.md | 1 + .../{appendix => introduction}/changelog.md | 0 .../introduction/downloading_and_importing.md | 2 +- .../fhir/docs/introduction/introduction.md | 10 +- .../hapi/fhir/docs/introduction/modules.md | 20 +- .../hapi/fhir/docs/introduction/versions.md | 284 +++++---- .../docs/model/profiles_and_extensions.md | 2 +- .../ca/uhn/hapi/fhir/docs/model/references.md | 168 +++++ .../security/authorization_interceptor.md | 6 +- .../fhir/docs/security/consent_interceptor.md | 4 +- .../docs/security/narrowing_interceptor.md | 2 +- .../hapi/fhir/docs/server_jpa/architecture.md | 2 +- .../hapi/fhir/docs/server_jpa/introduction.md | 4 +- .../fhir/docs/server_plain/introduction.md | 14 +- .../uhn/hapi/fhir/docs/server_plain/jax_rs.md | 57 ++ .../fhir/docs/server_plain/multitenency.md | 2 +- .../uhn/hapi/fhir/docs/server_plain/paging.md | 6 +- .../docs/server_plain/resource_providers.md | 22 +- .../fhir/docs/server_plain/rest_operations.md | 66 +- .../rest_operations_operations.md | 20 +- .../server_plain/rest_operations_search.md | 45 +- .../fhir/docs/server_plain/server_types.md | 2 +- .../docs/server_plain/web_testpage_overlay.md | 112 ++++ .../uhn/hapi/fhir/docs/tools/hapi_fhir_cli.md | 4 +- .../hapi/fhir/docs/validation/introduction.md | 14 + .../docs/validation/parser_error_handler.md | 28 + .../fhir/docs/validation/profile_validator.md | 103 +++ .../fhir/docs/validation/schema_validator.md | 28 + .../java/ca/uhn/fhir/jpa/dao/DaoConfig.java | 3 +- .../jpa/entity/TermValueSetConceptView.java | 43 +- .../jpa/term/ValueSetExpansionR4Test.java | 22 + ...eSystem-iar-chymh-cb-calculated-cap-10.xml | 31 + ...alueSet-iar-chymh-cb-calculated-cap-10.xml | 34 + .../fhir/jpa/migrate/taskdef/BaseTask.java | 21 +- .../tasks/HapiFhirJpaMigrationTasks.java | 19 +- .../fhir/jpa/migrate/tasks/api/Builder.java | 9 +- .../jpa/migrate/taskdef/ModifyColumnTest.java | 41 ++ hapi-fhir-structures-hl7org-dstu2/pom.xml | 20 + .../SnapshotGeneratingValidationSupport.java | 2 +- src/changes/changes.xml | 4 + src/site/xdoc/doc_resource_references.xml | 514 +++++++-------- src/site/xdoc/doc_rest_client.xml | 2 + src/site/xdoc/doc_rest_client_annotation.xml | 314 ++++----- src/site/xdoc/doc_rest_client_examples.xml | 274 ++++---- .../xdoc/doc_rest_client_http_config.xml.vm | 382 +++++------ src/site/xdoc/doc_rest_etag.xml | 53 -- src/site/xdoc/doc_rest_operations.xml | 2 +- src/site/xdoc/doc_rest_server_jaxrs.xml | 180 +++--- src/site/xdoc/doc_rest_server_security.xml | 2 +- src/site/xdoc/doc_server_tester.xml.vm | 408 ++++++------ src/site/xdoc/doc_tinder.xml.vm | 198 +++--- src/site/xdoc/doc_validation.xml | 2 + 79 files changed, 3554 insertions(+), 1551 deletions(-) create mode 100644 hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/FhirTesterConfig.java create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/annotation_client.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/client_configuration.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/examples.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/get_started.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/introduction.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging-complete.svg create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging.svg create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi_usage_patterns.svg create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors-exception.svg create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors.svg create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_client_interceptors.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/client_interceptors.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/server_interceptors.md rename hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/{appendix => introduction}/changelog.md (100%) create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/references.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/jax_rs.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/web_testpage_overlay.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/introduction.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/parser_error_handler.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/profile_validator.md create mode 100644 hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/schema_validator.md create mode 100644 hapi-fhir-jpaserver-base/src/test/resources/r4/CodeSystem-iar-chymh-cb-calculated-cap-10.xml create mode 100644 hapi-fhir-jpaserver-base/src/test/resources/r4/ValueSet-iar-chymh-cb-calculated-cap-10.xml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/DateUtils.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/DateUtils.java index 2a466c1a788..0e2c5577e6a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/DateUtils.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/DateUtils.java @@ -41,20 +41,30 @@ import java.util.*; */ public final class DateUtils { + /** + * GMT TimeZone + */ public static final TimeZone GMT = TimeZone.getTimeZone("GMT"); + /** * Date format pattern used to parse HTTP date headers in RFC 1123 format. */ - private static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; + @SuppressWarnings("WeakerAccess") + public static final String PATTERN_RFC1123 = "EEE, dd MMM yyyy HH:mm:ss zzz"; + /** * Date format pattern used to parse HTTP date headers in RFC 1036 format. */ - private static final String PATTERN_RFC1036 = "EEE, dd-MMM-yy HH:mm:ss zzz"; + @SuppressWarnings("WeakerAccess") + public static final String PATTERN_RFC1036 = "EEE, dd-MMM-yy HH:mm:ss zzz"; + /** * Date format pattern used to parse HTTP date headers in ANSI C * {@code asctime()} format. */ - private static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy"; + @SuppressWarnings("WeakerAccess") + public static final String PATTERN_ASCTIME = "EEE MMM d HH:mm:ss yyyy"; + private static final String[] DEFAULT_PATTERNS = new String[]{ PATTERN_RFC1123, PATTERN_RFC1036, diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java index d2710a1c0e9..00e7aa7b2bd 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/validation/FhirValidator.java @@ -109,14 +109,16 @@ public class FhirValidator { * * @param theValidator * The validator module. Must not be null. + * @return Returns a reference to this for easy method chaining. */ - public synchronized void registerValidatorModule(IValidatorModule theValidator) { + public synchronized FhirValidator registerValidatorModule(IValidatorModule theValidator) { Validate.notNull(theValidator, "theValidator must not be null"); ArrayList newValidators = new ArrayList(myValidators.size() + 1); newValidators.addAll(myValidators); newValidators.add(theValidator); myValidators = newValidators; + return this; } /** diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index dd7780e2efd..05b8bc61c91 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -93,6 +93,12 @@ javax.servlet-api provided + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + 4.2.0-SNAPSHOT + classes + diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/BundleFetcher.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/BundleFetcher.java index 017b0ba42f5..df063e1991f 100644 --- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/BundleFetcher.java +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/BundleFetcher.java @@ -22,65 +22,51 @@ package ca.uhn.hapi.fhir.docs; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.util.BundleUtil; import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.RelatedPerson; +import org.hl7.fhir.r4.model.Patient; -import java.util.HashSet; -import java.util.Set; +import java.util.ArrayList; +import java.util.List; /** * @author Bill de Beaubien on 1/13/2016. */ public class BundleFetcher { - public static void fetchRestOfBundle(IGenericClient theClient, Bundle theBundle) { - // we need to keep track of which resources are already in the bundle so that if other resources (e.g. Practitioner) are _included, - // we don't end up with multiple copies - Set resourcesAlreadyAdded = new HashSet(); - addInitialUrlsToSet(theBundle, resourcesAlreadyAdded); - Bundle partialBundle = theBundle; - for (;;) { - if (partialBundle.getLink(IBaseBundle.LINK_NEXT) != null) { - partialBundle = theClient.loadPage().next(partialBundle).execute(); - addAnyResourcesNotAlreadyPresentToBundle(theBundle, partialBundle, resourcesAlreadyAdded); - } else { - break; - } - } - // the self and next links for the aggregated bundle aren't really valid anymore, so remove them - theBundle.getLink().clear(); - } - private static void addInitialUrlsToSet(Bundle theBundle, Set theResourcesAlreadyAdded) { - for (Bundle.BundleEntryComponent entry : theBundle.getEntry()) { - theResourcesAlreadyAdded.add(entry.getFullUrl()); - } - } + public static void main(String[] args) { + // START SNIPPET: loadAll + // Create a context and a client + FhirContext ctx = FhirContext.forR4(); + String serverBase = "http://hapi.fhr.org/baseR4"; + IGenericClient client = ctx.newRestfulGenericClient(serverBase); - private static void addAnyResourcesNotAlreadyPresentToBundle(Bundle theAggregatedBundle, Bundle thePartialBundle, Set theResourcesAlreadyAdded) { - for (Bundle.BundleEntryComponent entry : thePartialBundle.getEntry()) { - if (!theResourcesAlreadyAdded.contains(entry.getFullUrl())) { - theResourcesAlreadyAdded.add(entry.getFullUrl()); - theAggregatedBundle.getEntry().add(entry); - } - } - } + // We'll populate this list + List patients = new ArrayList<>(); - public static void main(String[] args) { - FhirContext ctx = FhirContext.forR4(); - String serverBase = "http://fhirtest.uhn.ca/baseR4"; - IGenericClient client = ctx.newRestfulGenericClient(serverBase); - // use RelatedPerson because there aren't that many on the server - Bundle bundle = client.search().forResource(RelatedPerson.class).returnBundle(Bundle.class).execute(); - BundleFetcher.fetchRestOfBundle(client, bundle); - if (bundle.getTotal() != bundle.getEntry().size()) { - System.out.println("Counts didn't match! Expected " + bundle.getTotal() + " but bundle only had " + bundle.getEntry().size() + " entries!"); - } + // We'll do a search for all Patients and extract the first page + Bundle bundle = client + .search() + .forResource(Patient.class) + .where(Patient.NAME.matches().value("smith")) + .returnBundle(Bundle.class) + .execute(); + patients.addAll(BundleUtil.toListOfResources(ctx, bundle)); -// IParser parser = ctx.newXmlParser().setPrettyPrint(true); -// System.out.println(parser.encodeResourceToString(bundle)); + // Load the subsequent pages + while (bundle.getLink(IBaseBundle.LINK_NEXT) != null) { + bundle = client + .loadPage() + .next(bundle) + .execute(); + patients.addAll(BundleUtil.toListOfResources(ctx, bundle)); + } - } + System.out.println("Loaded " + patients.size() + " patients!"); + // END SNIPPET: loadAll + } } diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ClientTransactionExamples.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ClientTransactionExamples.java index b8ee113ff6e..4013ede2208 100644 --- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ClientTransactionExamples.java +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ClientTransactionExamples.java @@ -95,14 +95,14 @@ public class ClientTransactionExamples { // Log the request FhirContext ctx = FhirContext.forR4(); - System.out.println(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle)); + System.out.println(ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle)); // Create a client and post the transaction to the server - IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseR4"); + IGenericClient client = ctx.newRestfulGenericClient("http://hapi.fhir.org/baseR4"); Bundle resp = client.transaction().withBundle(bundle).execute(); // Log the response - System.out.println(ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(resp)); + System.out.println(ctx.newJsonParser().setPrettyPrint(true).encodeResourceToString(resp)); //END SNIPPET: conditional } diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/FhirTesterConfig.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/FhirTesterConfig.java new file mode 100644 index 00000000000..1681064f6ba --- /dev/null +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/FhirTesterConfig.java @@ -0,0 +1,62 @@ +package ca.uhn.hapi.fhir.docs; + +import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.to.FhirTesterMvcConfig; +import ca.uhn.fhir.to.TesterConfig; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Import; + +// START SNIPPET: file +/** + * This spring config file configures the web testing module. It serves two + * purposes: + * 1. It imports FhirTesterMvcConfig, which is the spring config for the + * tester itself + * 2. It tells the tester which server(s) to talk to, via the testerConfig() + * method below + */ +@Configuration +@Import(FhirTesterMvcConfig.class) +public class FhirTesterConfig { + + /** + * This bean tells the testing webpage which servers it should configure itself + * to communicate with. In this example we configure it to talk to the local + * server, as well as one public server. If you are creating a project to + * deploy somewhere else, you might choose to only put your own server's + * address here. + * + * Note the use of the ${serverBase} variable below. This will be replaced with + * the base URL as reported by the server itself. Often for a simple Tomcat + * (or other container) installation, this will end up being something + * like "http://localhost:8080/hapi-fhir-jpaserver-example". If you are + * deploying your server to a place with a fully qualified domain name, + * you might want to use that instead of using the variable. + */ + @Bean + public TesterConfig testerConfig() { + TesterConfig retVal = new TesterConfig(); + retVal + .addServer() + .withId("home") + .withFhirVersion(FhirVersionEnum.DSTU2) + .withBaseUrl("${serverBase}/fhir") + .withName("Local Tester") + .addServer() + .withId("hapi") + .withFhirVersion(FhirVersionEnum.DSTU2) + .withBaseUrl("http://fhirtest.uhn.ca/baseDstu2") + .withName("Public HAPI Test Server"); + + /* + * Use the method below to supply a client "factory" which can be used + * if your server requires authentication + */ + // retVal.setClientFactory(clientFactory); + + return retVal; + } + +} +// END SNIPPET: file diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java index b9bc8af2375..5ba4692de84 100644 --- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/GenericClientExample.java @@ -427,9 +427,8 @@ public class GenericClientExample { public static void history() { IGenericClient client = FhirContext.forDstu2().newRestfulGenericClient(""); { - Bundle response; // START SNIPPET: historyDstu2 - response = client + Bundle response = client .history() .onServer() .returnBundle(Bundle.class) @@ -437,9 +436,8 @@ public class GenericClientExample { // END SNIPPET: historyDstu2 } { - Bundle response; // START SNIPPET: historyFeatures - response = client + Bundle response = client .history() .onServer() .returnBundle(Bundle.class) diff --git a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ValidatorExamples.java b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ValidatorExamples.java index 36ca7c53b8d..cbeabb15084 100644 --- a/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ValidatorExamples.java +++ b/hapi-fhir-docs/src/main/java/ca/uhn/hapi/fhir/docs/ValidatorExamples.java @@ -33,6 +33,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport; import org.hl7.fhir.r4.hapi.ctx.IValidationSupport; import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator; +import org.hl7.fhir.r4.hapi.validation.PrePopulatedValidationSupport; import org.hl7.fhir.r4.hapi.validation.ValidationSupportChain; import org.hl7.fhir.r4.model.*; import org.hl7.fhir.r4.terminologies.ValueSetExpander; @@ -42,22 +43,20 @@ import java.io.File; import java.io.FileReader; import java.util.List; -@SuppressWarnings("serial") +@SuppressWarnings({"serial", "unused"}) public class ValidatorExamples { public void validationIntro() { // START SNIPPET: validationIntro - FhirContext ctx = FhirContext.forDstu3(); + FhirContext ctx = FhirContext.forR4(); // Ask the context for a validator FhirValidator validator = ctx.newValidator(); - // Create some modules and register them - IValidatorModule module1 = new SchemaBaseValidator(ctx); - validator.registerValidatorModule(module1); - IValidatorModule module2 = new SchematronBaseValidator(ctx); - validator.registerValidatorModule(module2); - + // Create a validator modules and register it + IValidatorModule module = new FhirInstanceValidator(); + validator.registerValidatorModule(module); + // Pass a resource in to be validated. The resource can // be an IBaseResource instance, or can be a raw String // containing a serialized resource as text. @@ -82,7 +81,7 @@ public class ValidatorExamples { // Create a context, set the error handler and instruct // the server to use it - FhirContext ctx = FhirContext.forDstu3(); + FhirContext ctx = FhirContext.forR4(); ctx.setParserErrorHandler(new StrictErrorHandler()); setFhirContext(ctx); } @@ -93,19 +92,19 @@ public class ValidatorExamples { @SuppressWarnings("unused") public void enableValidation() { // START SNIPPET: clientValidation - FhirContext ctx = FhirContext.forDstu3(); + FhirContext ctx = FhirContext.forR4(); ctx.setParserErrorHandler(new StrictErrorHandler()); // This client will have strict parser validation enabled - IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseDstu3"); + IGenericClient client = ctx.newRestfulGenericClient("http://hapi.fhir.org/baseR4"); // END SNIPPET: clientValidation } public void parserValidation() { // START SNIPPET: parserValidation - FhirContext ctx = FhirContext.forDstu3(); + FhirContext ctx = FhirContext.forR4(); // Create a parser and configure it to use the strict error handler IParser parser = ctx.newXmlParser(); @@ -122,7 +121,7 @@ public class ValidatorExamples { public void validateResource() { // START SNIPPET: basicValidation // As always, you need a context - FhirContext ctx = FhirContext.forDstu3(); + FhirContext ctx = FhirContext.forR4(); // Create and populate a new patient object Patient p = new Patient(); @@ -176,7 +175,7 @@ public class ValidatorExamples { private static void instanceValidator() throws Exception { // START SNIPPET: instanceValidator - FhirContext ctx = FhirContext.forDstu3(); + FhirContext ctx = FhirContext.forR4(); // Create a FhirInstanceValidator and register it to a validator FhirValidator validator = ctx.newValidator(); @@ -226,7 +225,7 @@ public class ValidatorExamples { private static void instanceValidatorCustom() throws Exception { // START SNIPPET: instanceValidatorCustom - FhirContext ctx = FhirContext.forDstu3(); + FhirContext ctx = FhirContext.forR4(); // Create a FhirInstanceValidator and register it to a validator FhirValidator validator = ctx.newValidator(); @@ -315,6 +314,43 @@ public class ValidatorExamples { // END SNIPPET: instanceValidatorCustom } + + + public void validateSupplyProfiles() { + + StructureDefinition someStructureDefnition = null; + ValueSet someValueSet = null; + String input = null; + + // START SNIPPET: validateSupplyProfiles + FhirContext ctx = FhirContext.forR4(); + + // Create a PrePopulatedValidationSupport and load it with our custom structures + PrePopulatedValidationSupport prePopulatedSupport = new PrePopulatedValidationSupport(); + + // In this example we're loading two things, but in a real scenario we might + // load many StructureDefinitions, ValueSets, CodeSystems, etc. + prePopulatedSupport.addStructureDefinition(someStructureDefnition); + prePopulatedSupport.addValueSet(someValueSet); + + // We'll still use DefaultProfileValidationSupport since derived profiles generally + // rely on built-in profiles also being available + DefaultProfileValidationSupport defaultSupport = new DefaultProfileValidationSupport(); + + // We'll create a chain that includes both the pre-populated and default. We put + // the pre-populated (custom) support module first so that it takes precedence + ValidationSupportChain supportChain = new ValidationSupportChain(); + supportChain.addValidationSupport(prePopulatedSupport); + supportChain.addValidationSupport(defaultSupport); + + // Create a validator using the FhirInstanceValidator module. We can use this + // validator to perform validation + FhirInstanceValidator validatorModule = new FhirInstanceValidator(supportChain); + FhirValidator validator = ctx.newValidator().registerValidatorModule(validatorModule); + ValidationResult result = validator.validateWithResult(input); + // END SNIPPET: validateSupplyProfiles + + } @SuppressWarnings("unused") private static void validateFiles() throws Exception { diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/android/client.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/android/client.md index 6fdc8e52079..a4d37820283 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/android/client.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/android/client.md @@ -34,7 +34,7 @@ To see a sample Gradle file for a working Android project using HAPI FHIR, see t # Performance -On mobile devices, performance problems are particularly noticeable. This is made worse by the fact that some economy Android devices have much slower performance than modern desktop computers. See the [Client Configuration Performance](/docs/client/rest_client_http_config.html#performance) page for some tips on how to improve client performance. +On mobile devices, performance problems are particularly noticeable. This is made worse by the fact that some economy Android devices have much slower performance than modern desktop computers. See the [Client Configuration Performance](/docs/client/client_configuration.html#performance) page for some tips on how to improve client performance. # Examples diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/faq.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/faq.md index c641e45c6e5..d81b20dc555 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/faq.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/faq.md @@ -30,7 +30,13 @@ There are a few options available to work around this fact: # Contributing -### My build is failing with the following error: *[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.19.1:test (default-test) on project hapi-fhir-jpaserver-base: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.19.1:test failed: The forked VM terminated without properly saying goodbye. VM crash or System.exit called?* +### My build is failing with the following error: *The forked VM terminated without properly saying goodbye. VM crash or System.exit called?* + +The complete error message typically resembles: + +``` +Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.19.1:test (default-test) on project hapi-fhir-jpaserver-base: Execution default-test of goal org.apache.maven.plugins:maven-surefire-plugin:2.19.1:test failed: The forked VM terminated without properly saying goodbye. VM crash or System.exit called? +``` This typically means that your build is running out of memory. HAPI's unit tests execute by default in multiple threads (the thread count is determined by the number of CPU cores available) so in an environment with lots of cores but not enough RAM, you may run out. If you are getting this error, try executing the build with the following arguments: @@ -38,4 +44,4 @@ This typically means that your build is running out of memory. HAPI's unit tests mvn -P ALLMODULES,NOPARALLEL install ``` -See [Hacking HAPI FHIR](/hacking.html) for more information on the build process. +See [Hacking HAPI FHIR](/docs/contributing/hacking_guide.html) for more information on the build process. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/logging.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/logging.md index b7dc1bc5768..f807bc67a6c 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/logging.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/logging.md @@ -58,9 +58,9 @@ Note that some popular libraries (e.g. Spring Framework) also use commons-loggin # Client Payload Logging -To enable detailed logging of client requests and responses (what URL is being requested, what headers and payload are being received, etc.), an interceptor may be added to the client which logs each transaction. See [Logging Requests and Responses](./doc_rest_client_interceptor.html#req_resp_logging) for more information. +To enable detailed logging of client requests and responses (what URL is being requested, what headers and payload are being received, etc.), an interceptor may be added to the client which logs each transaction. See [Logging Requests and Responses](/docs/interceptors/built_in_client_interceptors.html#req_resp_logging) for more information. # Server Request Logging -To enable detailed logging of server requests and responses, an interceptor may be added to the server which logs each transaction. See [Logging Server Requests](./doc_rest_server_interceptor.html#Logging) for more information. +To enable detailed logging of server requests and responses, an interceptor may be added to the server which logs each transaction. See [Logging Server Requests](/docs/interceptors/built_in_server_interceptors.html#logging_server_requests) for more information. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/annotation_client.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/annotation_client.md new file mode 100644 index 00000000000..d28aea66dd6 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/annotation_client.md @@ -0,0 +1,56 @@ +# Annotation Client + +HAPI also provides a second style of client, called the *annotation-driven* client. If you are using the +[Generic (Fluent) Client](./generic_client.html) do not necessarily need to read this page. + +The design of the annotation-driven client is intended to be similar to that of JAX-WS, so users of that specification should be comfortable with this one. It uses a user-defined interface containing special annotated methods which HAPI binds to calls against a server. + +The annotation-driven client is particularly useful if you have a server that exposes a set of specific operations (search parameter combinations, named queries, etc.) and you want to let developers have a stongly/statically typed interface to that server. + +There is no difference in terms of capability between the two styles of client. There is simply a difference in programming style and complexity. It is probably safe to say that the generic client is easier to use and leads to more readable code, at the expense of not giving any visibility into the specific capabilities of the server you are interacting with. + +## Defining A Restful Client Interface + +The first step in creating an annotation-driven client is to define a restful client interface. + +A restful client interface class must extend the [IRestfulClient](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/client/api/IRestfulClient.html) interface, and will contain one or more methods which have been annotated with special annotations indicating which REST operation +that method supports. + +Below is a simple example of a resource provider which supports the [read](http://hl7.org/implement/standards/fhir/http.html#read) operation (i.e. retrieve a single resource by ID) as well as the [search](http://hl7.org/implement/standards/fhir/http.html#search) operation (i.e. find any resources matching a given criteria) for a specific search criteria. + +You may notice that this interface looks a lot like the Resource Provider which is defined for use by the RESTful server. In fact, it supports all of the same annotations and is essentially identical, other than the fact that for a client you must use an interface but for a server you must use a concrete class with method implementations. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/IRestfulClient.java|provider}} +``` + +You will probably want to add more methods to your client interface. + +See the [REST Operations](/docs/server_plain/rest_operations.html) page in the server documentation section to see examples of how these methods should look. + +## Instantiating the Client + +Once your client interface is created, all that is left is to create a FhirContext and instantiate the client and you are ready to start using it. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExampleRestfulClient.java|client}} +``` + +# Configuring Encoding (JSON/XML) + +Restful client interfaces that you create will also extend the interface [IRestfulClient](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/client/api/IRestfulClient.html), which comes with some helpful methods for configuring the way that the client will interact with the server. + +The following snippet shows how to configure the cliet to explicitly request JSON or XML responses, and how to request "pretty printed" responses on servers that support this (HAPI based servers currently). + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ClientExamples.java|clientConfig}} +``` + +## A Complete Example + +The following is a complete example showing a RESTful client using HAPI FHIR. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/CompleteExampleClient.java|client}} +``` + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/client_configuration.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/client_configuration.md new file mode 100644 index 00000000000..f674a1d8cd7 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/client_configuration.md @@ -0,0 +1,83 @@ +# Client Configuration + +This page outlines ways that the client can be configured for specific behaviour. + + + +# Performance + +## Server Conformance Check + +By default, the client will query the server before the very first operation to download the server's conformance/metadata statement and verify that the server is appropriate for the given client. This check is only done once per server endpoint for a given FhirContext. + +This check is useful to prevent bugs or unexpected behaviour when talking to servers. It may introduce unneccesary overhead however in circumstances where the client and server are known to be compatible. The following example shows how to disable this check. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|dontValidate}} +``` + +## Deferred Model Scanning + +By default, HAPI will scan each model type it encounters as soon as it encounters it. This scan includes a check for all fields within the type, and makes use of reflection to do this. + +While this process is not particularly significant on reasonably performant machines (one benchmark showed that this takes roughly 0.6 seconds to scan all types on one developer workstation), on some devices (e.g. Android phones where every millisecond counts) it may be desirable to defer this scan. + +When the scan is deferred, objects will only be scanned when they are actually accessed, meaning that only types that are actually used in an application get scanned. + +The following example shows how to defer model scanning: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|deferModelScanning}} +``` + +# Configuring the HTTP Client + +REST clients (both Generic and Annotation-Driven) use [Apache HTTP Client](http://hc.apache.org/httpcomponents-client-ga/) as a provider by default (except on Android, where [OkHttp](http://square.github.io/okhttp/) is the default). + +The Apache HTTP Client is very powerful and extremely flexible, but can be confusing at first to configure, because of the low-level approach that the library uses. + +In many cases, the default configuration should suffice. HAPI FHIR also encapsulates some of the more common configuration settings you might want to use (socket timesouts, proxy settings, etc.) so that these can be configured through HAPI's API without needing to understand the underlying HTTP Client library. + +This configuration is provided by accessing the [IRestfulClientFactory](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/client/api/IRestfulClientFactory.html) class from the FhirContext. + +Note that individual requests and responses can be tweaked using [Client Interceptors](/docs/interceptors/client_interceptors.html). This approach is generally useful for configuration involving tweaking the HTTP request/response, such as adding authorization headers or logging. + +## Setting Socket Timeouts + +The following example shows how to configure low level socket timeouts for client operations. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ClientExamples.java|timeouts}} +``` + +## Configuring an HTTP Proxy + +The following example shows how to configure the use of an HTTP proxy in the client. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ClientExamples.java|proxy}} +``` + +## Using OkHttp instead of Apache HttpClient + +As of HAPI FHIR 2.0, an alternate client implementation is available. This client replaces the low-level Apache HttpClient implementation with the Square [OkHttp](http://square.github.io/okhttp/) library. + +Changing HTTP implementations should be mostly ransparent (it has no effect on the actual FHIR semantics which are transmitted over the wire) but might be useful if you have an application that uses OkHttp in other parts of the application and has specific configuration for that library. + +Note that as of HAPI FHIR 2.1, OkHttp is the default provider on Android, and will be used without any configuration being required. This is done because HttpClient is deprecated on Android and has caused problems in the past. + +To use OkHttp, first add the library as a dependency to your project POM: + +```xml + + ca.uhn.hapi.fhir + hapi-fhir-client-okhttp + ${hapi_stable_version} + +``` + +Then, set the client factory to use OkHttp. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ClientExamples.java|okhttp}} +``` diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/examples.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/examples.md new file mode 100644 index 00000000000..41b8a37fe79 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/examples.md @@ -0,0 +1,106 @@ +# Client Examples + +This page contains examples of how to use the client to perform complete tasks. If you have an example you could contribute, we'd love to hear from you! + +# Transaction With Placeholder IDs + +The following example shows how to post a transaction with two resources, where one resource contains a reference to the other. A temporary ID (a UUID) is used as an ID to refer to, and this ID will be replaced by the server by a permanent ID. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ClientTransactionExamples.java|conditional}} +``` + +This code creates the following transaction bundle: + + + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +The server responds with the following response. Note that the ID of the already existing patient is returned, and the ID of the newly created Observation is too. + +```xml + + + + + + + + + + + + + + + + + + + + + + + +``` + +# Fetch all Pages of a Bundle + +This following example shows how to load all pages of a bundle by fetching each page one-after-the-other and then joining the resuts. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/BundleFetcher.java|loadAll}} +``` diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md new file mode 100644 index 00000000000..055f2aaf636 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/generic_client.md @@ -0,0 +1,326 @@ +# Generic (Fluent) Client + +Creating a generic client simply requires you to create an instance of `FhirContext` and use that to instantiate a client. + +The following example shows how to create a client, and a few operations which can be performed. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|simple}} +``` + +

+ Performance Tip: Note that FhirContext is an expensive object to create, so you should try to keep an instance around for the lifetime of your application. It is thread-safe so it can be passed as needed. Client instances, on the other hand, are very inexpensive to create so you can create a new one for each request if needed (although there is no requirement to do so, clients are reusable and thread-safe as well). +

+ +# Fluent Calls + +The generic client supports queries using a fluent interface which is originally inspired by the excellent [.NET FHIR API](http://firely-team.github.io/fhir-net-api/client-search.html). + +The fluent interface allows you to construct powerful queries by chaining method calls together, leading to highly readable code. It also allows you to take advantage of intellisense/code completion in your favourite IDE. + +Note that most fluent operations end with an `execute()` statement which actually performs the invocation. You may also invoke several configuration operations just prior to the execute() statement, such as `encodedJson()` or `encodedXml()`. + +# Search + +Searching is a very powerful part of the FHIR API specification itself, and HAPI FHIR aims to proide a complete implementation of the FHIR API search specification via the generic client API. + +## Search - By Type + +Searching for resources is probably the most common initial scenario for client applications, so we'll start the demonstration there. The FHIR search operation generally uses a URL with a set of predefined search parameters, and returns a Bundle containing zero-or-more resources which matched the given search criteria. + +Search is a very powerful mechanism, with advanced features such as paging, including linked resources, etc. See the FHIR [search specification](http://hl7.org/fhir/search.html) for more information. + +The following example shows how to query using the generic client: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|search}} +``` + +## Search - Multi-valued Parameters (ANY/OR) + +To search for a set of possible values where *ANY* should be matched, you can provide multiple values to a parameter, as shown in the example below. + +This leads to a URL resembling `http://base/Patient?family=Smith,Smyth`. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchOr}} +``` + +## Search - Multi-valued Parameters (ALL/AND) + +To search for a set of possible values where *ALL* should be matched, you can provide multiple instances of a parameter, as shown in the example below. + +This leads to a URL resembling `http://base/Patient?address=Toronto&address=Ontario&address=Canada`. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchAnd}} +``` + +## Search - Paging + +If the server supports paging results, the client has a page method which can be used to load subsequent pages. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchPaging}} +``` + +## Search - Composite Parameters + +If a composite parameter is being searched on, the parameter takes a "left" and "right" operand, each of which is a parameter from the resource being seached. The following example shows the syntax. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchComposite}} +``` + +## Search - By plain URL + +You can also perform a search using a String URL, instead of using the fluent method calls to build the URL. This can be useful if you have a URL you retrieved from somewhere else that you want to use as a search. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchUrl}} +``` + +## Search - Other Query Options + +The fluent search also has methods for sorting, limiting, specifying JSON encoding, _include, _revinclude, _lastUpdated, _tag, etc. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchAdv}} +``` + +## Search - Using HTTP POST + +The FHIR specification allows the use of an HTTP POST to transmit a search to a server instead of using +an HTTP GET. With this style of search, the search parameters are included in the request body instead +of the request URL, which can be useful if you need to transmit a search with a large number of parameters. + +The [`usingStyle(SearchStyleEnum)`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/gclient/IQuery.html#usingStyle(ca.uhn.fhir.rest.api.SearchStyleEnum)) method controls which style to use. By default, GET style is used unless the client detects that the request would result in a very long URL (over 8000 chars) in which case the client automatically switches to POST. + +If you wish to force the use of HTTP POST, you can do that as well. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchPost}} +``` + +## Search - Compartments + +To search a [resource compartment](http://www.hl7.org/implement/standards/fhir/extras.html#compartment), simply use the [`withIdAndCompartment()`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/gclient/IQuery.html#withIdAndCompartment(java.lang.String,java.lang.String)) method in your search. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchCompartment}} +``` + +## Search - Subsetting (_summary and _elements) + +Sometimes you may want to only ask the server to include some parts of returned resources (instead of the whole resource). Typically this is for performance or optimization reasons, but there may also be privacy reasons for doing this. + +To request that the server return only "summary" elements (those elements defined in the specification with the "Σ" flag), you can use the [`summaryMode(SummaryEnum)`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/gclient/IClientExecutable.html#summaryMode(ca.uhn.fhir.rest.api.SummaryEnum)) qualifier: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchSubsetSummary}} +``` + +To request that the server return only elements from a custom list provided by the client, you can use the [`elementsSubset(String...)`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/gclient/IClientExecutable.html#elementsSubset(java.lang.String...)) qualifier: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|searchSubsetElements}} +``` + +# Create - Type + +The following example shows how to perform a create operation using the generic client: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|create}} +``` + +## Conditional Creates + +FHIR also specifies a type of update called "conditional create", where a set of search parameters are provided and a new resource is only created if no existing resource matches those parameters. See the FHIR specification for more information on conditional creation. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|createConditional}} +``` + +# Read/VRead - Instance + +Given a resource name and ID, it is simple to retrieve the latest version of that resource (a 'read'). + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|read}} +``` + +By adding a version string, it is also possible to retrieve a specific version (a 'vread'). + + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|vread}} +``` + +It is also possible to retrieve a resource given its absolute URL (this will override the base URL set on the client). + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|readabsolute}} +``` + +**See Also:** See the description of [Read/VRead ETags](#read_etags) below for information on specifying a matching version in the client request. + +# Delete - Instance + +The following example shows how to perform a delete operation using the generic client: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|delete}} +``` + +## Conditional Deletes + +Conditional deletions are also possible, which is a form where instead of deleting a resource using its logical ID, you specify a set of search criteria and a single resource is deleted if it matches that criteria. Note that this is not a mechanism for bulk deletion; see the FHIR specification for information on conditional deletes and how they are used. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|deleteConditional}} +``` + +# Update - Instance + +Updating a resource is similar to creating one, except that an ID must be supplied since you are updating a previously existing resource instance. + +The following example shows how to perform an update operation using the generic client: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|update}} +``` + +## Conditional Updates + +FHIR also specifies a type of update called "conditional updates", where insetad of using the logical ID of a resource to update, a set of search parameters is provided. If a single resource matches that set of parameters, that resource is updated. See the FHIR specification for information on how conditional updates work. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|updateConditional}} +``` + +**See Also:** See the description of [Update ETags](#update_etags) below for information on specifying a matching version in the client request. + +# History - Server/Type/Instance + +To retrieve the version history of all resources, or all resources of a given type, or of a specific instance of a resource, you call the [`history()`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/client/api/IGenericClient.html#history()) method. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|historyDstu2}} +``` + +You can also optionally request that only resource versions later than a given date, and/or only up to a given count (number) of resource versions be returned. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|historyFeatures}} +``` + +# Transaction - Server + +The following example shows how to execute a transaction using the generic client: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|transaction}} +``` + +# Capability Statement (metadata) - Server + +To retrieve the server's capability statement, simply call the [`capabilities()`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/client/api/IGenericClient.html#capabilities()) method as shown below. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|conformance}} +``` + +# Extended Operations + +FHIR also supports a set of *extended operatioons*, which are operatons beyond the basic CRUD operations defined in the specificiation. These operations are an RPC style of invocation, with a set of named input parameters passed to the server and a set of named output parameters returned back. + +To invoke an operation using the client, you simply need to create the input [Parameters](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Parameters.html) resource, then pass that to the [`operation()`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/client/api/IGenericClient.html#operation()) fluent method. + +The example below shows a simple operation call. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|operation}} +``` + +Note that if the operation does not require any input parameters, you may also invoke the operation using the following form. Note that the `withNoParameters` form still requires you to provide the type of the Parameters resource so that it can return the correct type in the response. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|operationNoIn}} +``` + +## Using the HTTP GET Form + +By default, the client will invoke operations using the HTTP POST form. The FHIR specification also allows requests to use the HTTP GET verb if the operation does not affect state and has no composite/resource parameters. Use the following form to invoke operation with HTTP GET. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|operationHttpGet}} +``` + +## Built-In Operations - Validate + +The `$validate` operation asks the server to test a given resource to see if it would be acceptable as a create/update on that server. The client has built-in support for this operation. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|validate}} +``` + +# Built-In Operations - Process-Message + +The `$process-message` operation asks the server to accept a FHIR message bundle for processing. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ClientExamples.java|processMessage}} +``` + +# Additional Properties + +This section contains ways of customizing the request sent by the client. + +## Cache-Control + +The `Cache-Control` header can be used by the client in a request to signal to the server (or any cache in front of it) that the client wants specific behaviour from the cache, or wants the cache to not act on the request altogether. Naturally, not all servers will honour this header. + +To add a cache control directive in a request: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ClientExamples.java|cacheControl}} +``` + +
+ +# ETags + +ETag features are added simply by adding fluent method calls to the client method chain, as shown in the following examples. + + + +## Read / VRead ETags + +To notify the server that it should return an `HTTP 304 Not Modified` if the content has not changed, add an [`ifVersionMatches()`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/gclient/IReadExecutable.html#ifVersionMatches(java.lang.String)) invocation. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|etagread}} +``` + +This method will add the following header to the request: + +```http +If-None-Match: "W/001" +``` + + + +## Update ETags + +To implement version aware updates, specify a version in the request. This will notify the server that it should only update the resource on the server if the version matches the given version. This is useful to prevent two clients from attempting to modify the resource at the same time, and having one client's updates overwrite the other's. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/GenericClientExample.java|etagupdate}} +``` + +The following header will be added to the request as a part of this interaction: + +```http +If-Match: "W/001" +``` diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/get_started.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/get_started.md new file mode 100644 index 00000000000..801c261e428 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/get_started.md @@ -0,0 +1,5 @@ +# Getting Started with the Client + +A starter project containing all nedded dependencies and some starter code for the HAPI FHIR client is available here: + +* [hapi-fhirstarters-client-skeleton](https://github.com/FirelyTeam/fhirstarters/tree/master/java/hapi-fhirstarters-client-skeleton/) diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/introduction.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/introduction.md new file mode 100644 index 00000000000..dfe36527a08 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/client/introduction.md @@ -0,0 +1,13 @@ +# Client Introduction + +HAPI FHIR provides a built-in mechanism for connecting to FHIR REST servers. + +The HAPI RESTful client is designed to be easy to set up and to allow strong compile-time type checking wherever possible. + +There are two types of REST clients provided by HAPI: + +* The [Generic (Fluent) client](./generic_client.html) is designed to be very flexible, yet easy to use. It allows you to build up FHIR REST invocations using a fluent API that is consistent and powerful. If you are getting started with HAPI FHIR and aren't sure which client to use, this is the client to start with. + +* The [Annotation Client](./annotation_client.html) client relies on static binding to specific operations to give better compile-time checking against servers with a specific set of capabilities +exposed. This second model takes more effort to use, but can be useful if the person defining the specific methods to invoke is not the same person who is using those methods. + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/contributing/hacking_guide.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/contributing/hacking_guide.md index d518df2aa9a..8ebba6885ba 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/contributing/hacking_guide.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/contributing/hacking_guide.md @@ -79,13 +79,13 @@ If the build fails to execute successfully, try the following: Import the HAPI projects as Maven Modules by selecting **File -> Import...** from the File menu. Then select **Existing Module Projects** as shown below. - + **Select the Projects** Next, browse to the directory where you checked out the HAPI FHIR sources. You might want to select only the projects you are interested in editing, in order to keep Eclipse's memory use down. You can always come back and import more later. - + ## Troubleshooting diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties index 88400506380..91380f6e15d 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/files.properties @@ -1,6 +1,7 @@ section.introduction.title=Welcome to HAPI FHIR page.introduction.table_of_contents=Table of Contents +page.introduction.changelog=Changelog page.introduction.introduction=Introduction page.introduction.versions=FHIR and HAPI FHIR Versions page.introduction.modules=HAPI FHIR Modules @@ -8,11 +9,20 @@ page.introduction.downloading_and_importing=Downloading and Importing section.model.title=Working With The FHIR Model page.model.working_with_resources=Working With Resources +page.model.references=Resource References page.model.profiles_and_extensions=Profiles and Extensions page.model.converter=Version Converters page.model.custom_structures=Custom Structures page.model.narrative_generation=Narrative Generation +section.client.title=Client +page.client.introduction=Introduction +page.client.generic_client=Generic (Fluent) Client +page.client.annotation_client=Annotation Client +page.client.client_configuration=Client Configuration +page.client.get_started=Get Started +page.client.examples=Client Examples + section.server_plain.title=Plain Server page.server_plain.server_types=REST Server Types page.server_plain.introduction=Plain Server Introduction @@ -20,19 +30,25 @@ page.server_plain.get_started=Getting Started with Plain Server page.server_plain.resource_providers=Resource Providers and Plan Providers page.server_plain.rest_operations=REST Operations: Overview page.server_plain.rest_operations_search=REST Operations: Search -page.server_plain.rest_operations_operations=REST Operations: Operations Framework +page.server_plain.rest_operations_operations=REST Operations: Extended Operations page.server_plain.paging=Paging Search Results page.server_plain.cors=CORS +page.server_plain.web_testpage_overlay=Web Testpage Overlay page.server_plain.multitenency=Multitenency +page.server_plain.jax_rs=JAX-RS Support section.server_jpa.title=JPA Server -section.server_jpa.introduction=Introduction -section.server_jpa.get_started=Get Started -section.server_jpa.architecture=Architecture -section.server_jpa.upgrading=Upgrade Guide +page.server_jpa.introduction=Introduction +page.server_jpa.get_started=Get Started +page.server_jpa.architecture=Architecture +page.server_jpa.upgrading=Upgrade Guide section.interceptors.title=Interceptors page.interceptors.interceptors=Interceptors Overview +page.interceptors.client_interceptors=Client Interceptors +page.interceptors.built_in_client_interceptors=Built-In Client Interceptors +page.interceptors.server_interceptors=Server Interceptors +page.interceptors.built_in_server_interceptors=Built-In Server Interceptors section.security.title=Security page.security.introduction=Introduction @@ -41,7 +57,11 @@ page.security.consent_interceptor=Consent Interceptor page.security.narrowing_interceptor=Narrowing Interceptor section.validation.title=Validation -section.validation.examples=Validation Examples +page.validation.introduction=Introduction +page.validation.parser_error_handler=Parser Error Handler +page.validation.profile_validator=Profile Validator +page.validation.schema_validator=Schema/Schematron Validator +page.validation.examples=Validation Examples section.android.title=Android page.android.client=Android Client @@ -54,5 +74,4 @@ page.contributing.hacking_guide=Hacking Guide section.appendix.title=Appendix page.appendix.logging=Logging -page.appendix.changelog=Changelog page.appendix.faq=FAQ diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging-complete.svg b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging-complete.svg new file mode 100644 index 00000000000..ae06998393d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging-complete.svg @@ -0,0 +1 @@ +hapi-fhir
slf4j-api
[Not supported by viewer]
commons-httpclient
jcl-over-slf4j
[Not supported by viewer]
Underlying LoggingFramework(logback, log4j, etc.)
\ No newline at end of file diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging.svg b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging.svg new file mode 100644 index 00000000000..ff4bc79aa79 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi-fhir-logging.svg @@ -0,0 +1 @@ +hapi-fhir
slf4j-api
[Not supported by viewer]
logback-classic
[Not supported by viewer]
slf4j-log4j
[Not supported by viewer]
log4j
[Not supported by viewer]
slf4j-jdk14
[Not supported by viewer]
JDK Logging
(built in to Java)
[Not supported by viewer]
disk
[Not supported by viewer]
disk
[Not supported by viewer]
disk
[Not supported by viewer]
Chosen by
searching
classpath
[Not supported by viewer]
\ No newline at end of file diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi_usage_patterns.svg b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi_usage_patterns.svg new file mode 100644 index 00000000000..730b07d8e95 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/hapi_usage_patterns.svg @@ -0,0 +1,594 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ External FHIR Clients +
+
+ [Not supported by viewer] +
+
+ + + +
+ Your +
+
Application
+
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI FHIR +
+ Client +
+
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI +
+ Model +
+ Objects +
+ [Not supported by viewer] +
+
+ + + + +
+ External +
+ FHIR +
+ Server +
+
+ [Not supported by viewer] +
+
+ + + +
HTTP
+ [Not supported by viewer] +
+
+ + + + +
+ Use the HAPI FHIR client in an application to fetch from or store + resources to an external server. +
+ Learn Mode +
+ [Not supported by viewer] +
+
+ + + +
+ Your +
+
Application
+
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI +
+ Model +
+ Objects +
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI FHIR +
+ Server +
+ [Not supported by viewer] +
+
+ + + +
HTTP
+ [Not supported by viewer] +
+
+ + + + +
+ Use the HAPI FHIR server in an application to allow external + applications to access or modify your application's data. +
+ Learn More +
+
+ [Not supported by viewer] +
+
+ + + +
+ HAPI JPA Database Server +
+
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI FHIR Server +
+
+ [Not supported by viewer] +
+
+ + + + + +
+ JPA Persistence Module +
+
+ [Not supported by viewer] +
+
+ + + +
+ Your +
+
Application
+
+ [Not supported by viewer] +
+
+ + + +
HTTP
+ [Not supported by viewer] +
+
+ + + + +
+ Use the HAPI JPA/Database Server to deploy a fully functional FHIR + server you can develop applications against. +
+ Learn More +
+ [Not supported by viewer] +
+
+ + + +
+ Your +
+
Application
+
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI +
+ Model +
+ Objects +
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI FHIR +
+ Parser (Xml/Json) +
+
+ [Not supported by viewer] +
+
+ + + +

+ [Not supported by viewer] +
+
+ + + +
+ Raw FHIR Resources +
+
+ [Not supported by viewer] +
+
+ + + + + + + +
+ HAPI FHIR +
+ Parser (Xml/Json) +
+
+ [Not supported by viewer] +
+
+ + + + + +
+ HAPI +
+ Model +
+ Objects +
+ [Not supported by viewer] +
+
+ + + +

+ [Not supported by viewer] +
+
+ + + + +
+ Use the HAPI FHIR parser and encoder to convert between FHIR and + your application's data model. +
+ Learn More +
+ [Not supported by viewer] +
+
+ + + + +
+
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors-exception.svg b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors-exception.svg new file mode 100644 index 00000000000..b6e67f3c7df --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors-exception.svg @@ -0,0 +1,3 @@ + + +RESTfulServerInterceptorResource/PlainProviderMethodIncoming Request
Request is handled
[Not supported by viewer]
handleExceptionreturn true;Responsethrow exceptionpreProcessExceptionreturn null;
\ No newline at end of file diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors.svg b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors.svg new file mode 100644 index 00000000000..0f874ea368a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/images/restful-server-interceptors.svg @@ -0,0 +1,3 @@ + + +RESTfulServerInterceptorResource/PlainProviderMethodHTTP RequestincomingRequestPreProcessedreturn true;
Request is classified
[Not supported by viewer]
incomingRequestPostProcessedreturn true;
Request is handled
[Not supported by viewer]
outgoingResponsereturn true;HTTP ResponseincomingRequestPreHandledreturn;
Request is parsed
[Not supported by viewer]
\ No newline at end of file diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_client_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_client_interceptors.md new file mode 100644 index 00000000000..870e2d3a23f --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_client_interceptors.md @@ -0,0 +1,3 @@ +# Built-In Client Interceptors + + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md new file mode 100644 index 00000000000..58d25589f15 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/built_in_server_interceptors.md @@ -0,0 +1,3 @@ +# Built-In Server Interceptors + + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/client_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/client_interceptors.md new file mode 100644 index 00000000000..8ee02214311 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/client_interceptors.md @@ -0,0 +1,3 @@ +# Client Interceptors + + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/server_interceptors.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/server_interceptors.md new file mode 100644 index 00000000000..1d011e23a64 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/interceptors/server_interceptors.md @@ -0,0 +1 @@ +# Server Interceptors diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/changelog.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/changelog.md similarity index 100% rename from hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/appendix/changelog.md rename to hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/changelog.md diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/downloading_and_importing.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/downloading_and_importing.md index 359361ad9d7..5dcb5adb94f 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/downloading_and_importing.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/downloading_and_importing.md @@ -122,7 +122,7 @@ System.setProperty("javax.xml.stream.XMLEventFactory", "com.ctc.wstx.stax.WstxEv ## PH-Schematron -If you are using the [Schematron Validation](/docs/validation/schema.html) module, you will also need to include the Ph-Schematron library on your classpath. (Note that prior to HAPI FHIR 3.4.0 we used Phloc-Schamtron instead, but that library has been discontinued). +If you are using the [Schematron Validation](/docs/validation/schema_validator.html) module, you will also need to include the Ph-Schematron library on your classpath. (Note that prior to HAPI FHIR 3.4.0 we used Phloc-Schamtron instead, but that library has been discontinued). If you are using Maven, this library is not added by default (it is marked as an optional dependency) since not all applications need Schematron support. As a result you will need to manually add the following dependencies to your project pom.xml: diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/introduction.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/introduction.md index d26405c3e43..2f278a9b18a 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/introduction.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/introduction.md @@ -9,19 +9,17 @@ HAPI FHIR is based on the same principle, but applied to the Java implementation # Getting Started -To get started with HAPI FHIR, first download a copy and add it to your project. See the [Download Page](./download.html) for instructions. +To get started with HAPI FHIR, first download a copy and add it to your project. See [Downloading and Importing](./downloading_and_importing.html) for instructions. ## A Note on FHIR Versions Before discussing HAPI itself, a quick word about FHIR versions. FHIR is not yet a finalized "1.0" standard. It is currently in the DSTU phase, which means that it is changing in subtle and non-subtle ways between releases. Before trying to use FHIR, you will need to determine which version of FHIR you want to support in your application. Typically this would be the latest version, but if you are looking to interact with an application which already exists, you will probably want to implement the same version implemented by that application. -See the [note on DSTU2 support](doc_dstu2.html) for more information on supporting multiple versions of FHIR. - ## Introducing the FHIR Context -HAPI defines model classes for every resource type and datatype defined by the FHIR specification. For example, here is the [Patient](../apidocs/hapi-fhir-structures-r4/ca/uhn/fhir/model/r4/resource/Patient.html) resource specification. If you browse the JavaDoc you will see getters and setters for the various properties that make up a Patient resource. +HAPI defines model classes for every resource type and datatype defined by the FHIR specification. For example, here is the [Patient](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Patient.html) resource specification. If you browse the JavaDoc you will see getters and setters for the various properties that make up a Patient resource. -We will come back to how to interact with these objects in a moment, but first we need to create a [FhirContext](../apidocs/hapi-fhir-base/ca/uhn/fhir/context/FhirContext.html). FhirContext is the starting point to using HAPI, and acts as a factory for most other parts of the API as well as a runtime cache of information that HAPI needs to operate. Users of the JAXB API may find this class to be similar in purpose to the [JAXBContext](http://docs.oracle.com/javaee/5/api/javax/xml/bind/JAXBContext.html) class from that API. +We will come back to how to interact with these objects in a moment, but first we need to create a [FhirContext](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/FhirContext.html). FhirContext is the starting point to using HAPI, and acts as a factory for most other parts of the API as well as a runtime cache of information that HAPI needs to operate. Users of the JAXB API may find this class to be similar in purpose to the [JAXBContext](http://docs.oracle.com/javaee/5/api/javax/xml/bind/JAXBContext.html) class from that API. Creating a FhirContext is as simple as instantiating one. A FhirContext instance is specific to a given version of the FHIR specification, so it is recommended that you use one of the factory methods indicating the FHIR version you wish to support in your application, as shown in the following snippet: @@ -31,7 +29,7 @@ Creating a FhirContext is as simple as instantiating one. A FhirContext instance ## Parsing a resource from a String -This [Parser instance](../apidocs/hapi-fhir-base/ca/uhn/fhir/parser/IParser.html) can then be used to parse messages. Note that you may use the context to create as many parsers are you want. +This [Parser instance](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/parser/IParser.html) can then be used to parse messages. Note that you may use the context to create as many parsers are you want. **Performance tip:** The FhirContext is an expensive object to create, so you should try to create it once and keep it around during the life of your application. Parsers, on the other hand, are very lightweight and do not need to be reused. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/modules.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/modules.md index 97cb9a60198..7b139c50ed9 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/modules.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/modules.md @@ -12,7 +12,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-base - JavaDoc + JavaDoc This is the core HAPI FHIR library and is always required in order to use @@ -35,7 +35,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-structures-dstu2 - JavaDoc + JavaDoc This module contains FHIR DSTU2 model classes. @@ -44,7 +44,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-structures-hl7org-dstu2 - JavaDoc + JavaDoc This module contains alternate FHIR DSTU2 model classes. The HAPI FHIR and FHIR "Java Reference @@ -58,7 +58,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-structures-dstu3 - JavaDoc + JavaDoc This module contains FHIR DSTU3 model classes. @@ -67,7 +67,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-structures-r4 - JavaDoc + JavaDoc This module contains FHIR R4 model classes. @@ -76,7 +76,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-structures-r5 - JavaDoc + JavaDoc This module contains FHIR R5 model classes. @@ -85,7 +85,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-converter - JavaDoc + JavaDoc This module contains converters for converting between FHIR versions. @@ -99,7 +99,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-client - JavaDoc + JavaDoc This module contains the core FHIR client framework, including an @@ -192,7 +192,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-server - JavaDoc + JavaDoc This module contains the HAPI FHIR Server framework, which can be used to @@ -202,7 +202,7 @@ The following table shows the modules that make up the HAPI FHIR library. hapi-fhir-jpaserver-base - JavaDoc + JavaDoc This module contains the HAPI FHIR "JPA Server", which is a complete diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/versions.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/versions.md index bf95cfe4580..da2e4a43368 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/versions.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/introduction/versions.md @@ -1,11 +1,17 @@ # FHIR and HAPI FHIR Versions + + The following table shows the various versions of the HAPI FHIR library, and the versions of the FHIR standard that they support. Note that support for stable releases of FHIR are shown in GREEN and support for draft pre-release versions of FHIR are shown in YELLOW. Note also that after the release of the FHIR DSTU2 specification, the FHIR standard itself stopped using the DSTUx naming scheme, in favour or naming new releases STUx or simply Rx. Because HAPI FHIR already had draft support for what was then called DSTU3 at this time, we did not update our naming conventions until R4 in order to avoid breaking existing users' code. From the perspective of a user of HAPI FHIR, consider the terms DSTU3 / STU3 / R3 to be interchangeable. - +
@@ -22,232 +28,232 @@ Note also that after the release of the FHIR DSTU2 specification, the FHIR - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + + - - - - - - + + + + + +
HAPI Version
HAPI FHIR 1.1 JDK60.0.820.5.0-58430.0.820.5.0-5843
HAPI FHIR 1.2 JDK60.0.820.5.0-58430.0.820.5.0-5843
HAPI FHIR 1.3 JDK60.0.821.0.20.0.821.0.2
HAPI FHIR 1.4 JDK60.0.821.0.21.3.0-76020.0.821.0.21.3.0-7602
HAPI FHIR 1.5 JDK60.0.821.0.21.4.0-81380.0.821.0.21.4.0-8138
HAPI FHIR 1.6 JDK60.0.821.0.21.4.0-86360.0.821.0.21.4.0-8636
HAPI FHIR 2.0 JDK60.0.821.0.21.6.0-96630.0.821.0.21.6.0-9663
HAPI FHIR 2.1 JDK60.0.821.0.21.7.0-101290.0.821.0.21.7.0-10129
HAPI FHIR 2.2 JDK60.0.821.0.21.4.01.8.0-105280.0.821.0.21.4.01.8.0-10528
HAPI FHIR 2.3 JDK60.0.821.0.21.4.01.9.0-115010.0.821.0.21.4.01.9.0-11501
HAPI FHIR 2.4 JDK60.0.821.0.21.4.03.0.10.0.821.0.21.4.03.0.1
HAPI FHIR 2.5 JDK60.0.821.0.21.4.03.0.10.0.821.0.21.4.03.0.1
HAPI FHIR 3.0.0 JDK71.0.21.4.03.0.13.1.0-123701.0.21.4.03.0.13.1.0-12370
HAPI FHIR 3.1.0 JDK71.0.21.4.03.0.13.1.0-123701.0.21.4.03.0.13.1.0-12370
HAPI FHIR 3.2.0 JDK71.0.21.4.03.0.13.2.0-129171.0.21.4.03.0.13.2.0-12917
HAPI FHIR 3.3.0 JDK71.0.21.4.03.0.13.2.0-132711.0.21.4.03.0.13.2.0-13271
HAPI FHIR 3.4.0 JDK81.0.21.4.03.0.13.4.0-137321.0.21.4.03.0.13.4.0-13732
HAPI FHIR 3.5.0 JDK81.0.21.4.03.0.13.4.0-137321.0.21.4.03.0.13.4.0-13732
HAPI FHIR 3.6.0 JDK81.0.21.4.03.0.13.6.0-1202b2eed0f1.0.21.4.03.0.13.6.0-1202b2eed0f
HAPI FHIR 3.7.0 JDK81.0.21.4.03.0.14.0.01.0.21.4.03.0.14.0.0
HAPI FHIR 3.8.0 JDK81.0.21.4.03.0.14.0.01.0.21.4.03.0.14.0.0
HAPI FHIR 4.0.0 JDK81.0.21.4.03.0.14.0.04.1.0-e0e3caf9ba1.0.21.4.03.0.14.0.04.1.0-e0e3caf9ba
HAPI FHIR 4.1.0 JDK81.0.21.4.03.0.24.0.14.1.0-1a7623d8661.0.21.4.03.0.24.0.14.1.0-1a7623d866
diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/profiles_and_extensions.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/profiles_and_extensions.md index a8fc56e1faf..ddb426d4ff2 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/profiles_and_extensions.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/profiles_and_extensions.md @@ -5,7 +5,7 @@ This page describes how to extend and constrain the FHIR data model for your own # Extensions

-Note on FHIR Versions: Because of the differences in the way the structures work between DSTU2 and DSTU3, we have provided two versions of many of the examples on this page. See the download page for more information on FHIR versions. +Note on FHIR Versions: Because of the differences in the way the structures work between DSTU2 and DSTU3, we have provided two versions of many of the examples on this page. See the FHIR Versions page for more information on FHIR version support in HAPI FHIR.

Extensions are a key part of the FHIR specification, providing a standardized way of placing additional data in a resource. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/references.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/references.md new file mode 100644 index 00000000000..bebd8e5f40c --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/model/references.md @@ -0,0 +1,168 @@ +# Resource References + +Resource references are a key part of the HAPI FHIR model, since almost any resource will have references to other resources within it. + +The [Reference](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Reference.html) type is the datatype for references. This datatype has a number of properties which help make working with FHIR simple. + +The `getReference()` method returns a String that contains the identity of the resource being referenced. This is the item which is most commonly populated when interacting with FHIR. For example, consider the following Patient resource, which contains a reference to an Organization resource: + +```json +{ + "resourceType": "Patient", + "identifier": [{ + "system": "http://example.com/identifiers", + "value": "12345" + }], + "managingOrganization": { + "reference": "Organization/123" + } +} +``` + +Given a Patient resource obtained by invoking a client operation, a call to `String reference = patient.getManagingOrganization().getReference();` returns a String containing `Organization/112`. + +Reference also has a place for storing actual resource instances (i.e. an actual [IBaseResource](/hapi-fhir/apidocs/hapi-fhir-base/org/hl7/fhir/instance/model/api/IBaseResource.html) instance), and this can be very useful as shown below. + +# References in Client Code + +In client code, if a resource reference refers to a resource which was received as a part of the same response, getResource() will be populated with the actual resource. This can happen because either the resource was received as a contained resource, or the resource was received as a separate resource in a bundle. + +# References in Server Code + +In server code, you will often want to return a resource which contains a link to another resource. Generally these "linked" resources are not actually included in the response, but rather a link to the resource is included and the client may request that resource directly (by ID) if it is needed. + +The following example shows a Patient resource being created which will have a link to its managing organization when encoded from a server: + +```java +Patient patient = new Patient(); +patient.setId("Patient/1333"); +patient.addIdentifier("urn:mrns", "253345"); +patient.getManagingOrganization().setReference("Organization/124362"); +``` + +## Handling Includes (_include) in a Bundle + +Your server code may also wish to add additional resource to a bundle being returned (e.g. because of an _include directive in the client's request). + +To do this, you can implement your server method to simply return List and then simply add your extra resources to the list. Another technique however, is to populate the reference as shown in the example below, but ensure that the referenced resource has an ID set. + +In the following example, the Organization resource has an ID set, so it will not be contained but will rather appear as a distinct entry in any returned bundles. Both resources are added to a bundle, which will then have two entries: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/IncludesExamples.java|addIncludes}} +``` + +This will give the following output: + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +```` + +## Contained Resources + +On the other hand, if the linked resource does not have an ID set, the linked resource will be included in the returned bundle as a "contained" resource. In this case, HAPI itself will define a local reference ID (e.g. `#1`). + +```java +// 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 = ourCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(patient); +System.out.println(encoded); +``` + +This will give the following output: + +```xml + + + + + + + + + + + + + + +``` + +Note that you may also "contain" resources manually in your own code if you prefer. The following example show how to do this: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ResourceRefs.java|manualContained}} +``` + +# Versioned References + +By default, HAPI will strip resource versions from references between resources. For example, if you set a reference to `Patient.managingOrganization` to the value `Patient/123/_history/2`, HAPI will encode this reference as `Patient/123`. + +This is because in most circumstances, references between resources should be versionless (e.g. the reference just points to the latest version, whatever version that might be). + +There are valid circumstances however for wanting versioned references. If you need HAPI to emit versionned references, you have a few options: + +You can force the parser to never strip versions: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/Parser.java|disableStripVersions}} +``` + +You can also disable this behaviour entirely on the context (so that it will apply to all parsers): + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/Parser.java|disableStripVersionsCtx}} +``` + +You can also configure HAPI to not strip versions only on certain fields. This is desirable if you want versionless references in most places but need them in some places: + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/Parser.java|disableStripVersionsField}} +``` diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/authorization_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/authorization_interceptor.md index 866116879c0..44d742577f8 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/authorization_interceptor.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/authorization_interceptor.md @@ -1,6 +1,6 @@ # Authorization Interceptor -HAPI FHIR 1.5 introduced a new interceptor: [AuthorizationInterceptor](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationInterceptor.html). +HAPI FHIR 1.5 introduced a new interceptor: [AuthorizationInterceptor](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationInterceptor.html). This interceptor can help with the complicated task of determining whether a user has the appropriate permission to perform a given task on a FHIR server. This is done by declaring a set of rules that can selectively allow (whitelist) and/or selectively block (blacklist) requests. @@ -28,7 +28,7 @@ Note that there are performance implications to this mechanism, since an unautho See the following diagram for an example of how this works. -Write Authorization +Write Authorization ## Authorizing Write Operations @@ -36,7 +36,7 @@ Write operations (create, update, etc.) are typically authorized by the intercep See the following diagram for an example of how this works. -Write Authorization +Write Authorization diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/consent_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/consent_interceptor.md index 7005f919e68..bf1d7411590 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/consent_interceptor.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/consent_interceptor.md @@ -1,6 +1,6 @@ # Consent Interceptor -HAPI FHIR 4.0.0 introduced a new interceptor, the [ConsentInterceptor](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/consent/ConsentInterceptor.html). +HAPI FHIR 4.0.0 introduced a new interceptor, the [ConsentInterceptor](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/consent/ConsentInterceptor.html). The consent interceptor may be used to examine client requests to apply consent directives and create audit trail events. Like the AuthorizationInterceptor above, this interceptor is not a complete working solution, but instead is a framework designed to make it easier to implement local policies. @@ -16,7 +16,7 @@ The consent interceptor has several primary purposes: * The consent service suppresses search the total being returned in Bundle.total for search results. -The ConsentInterceptor requires a user-supplied instance of the [IConsentService](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/consent/IConsentService.html) interface. The following shows a simple example of an IConsentService implementation: +The ConsentInterceptor requires a user-supplied instance of the [IConsentService](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/consent/IConsentService.html) interface. The following shows a simple example of an IConsentService implementation: ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/ConsentInterceptors.java|service}} diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/narrowing_interceptor.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/narrowing_interceptor.md index 79a7943964a..aca44b425fe 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/narrowing_interceptor.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/security/narrowing_interceptor.md @@ -1,6 +1,6 @@ # Search Narrowing Interceptor -HAPI FHIR 3.7.0 introduced a new interceptor, the [SearchNarrowingInterceptor](/apidocs/hapi-fhr-server/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptor.html). +HAPI FHIR 3.7.0 introduced a new interceptor, the [SearchNarrowingInterceptor](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/interceptor/auth/SearchNarrowingInterceptor.html). This interceptor is designed to be used in conjunction with AuthorizationInterceptor. It uses a similar strategy where a dynamic list is built up for each request, but the purpose of this interceptor is to modify client searches that are received (after HAPI FHIR received the HTTP request, but before the search is actually performed) to restrict the search to only search for specific resources or compartments that the user has access to. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/architecture.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/architecture.md index 3dce7d6f953..cb53fef461c 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/architecture.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/architecture.md @@ -4,7 +4,7 @@ The HAPI JPA Server has the following components: -* **Resource Providers:** A RESTful server [Resource Provider](/hapi-fhir/docs/server/restful_server.html#resource_providers) is provided for each resource type in a given release of FHIR. Each resource provider implements a [@Search](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Search.html) method implementing the complete set of search parameters defined in the FHIR specification for the given resource type. +* **Resource Providers:** A RESTful server [Resource Provider](/hapi-fhir/docs/server_plain/resource_providers.html) is provided for each resource type in a given release of FHIR. Each resource provider implements a [@Search](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Search.html) method implementing the complete set of search parameters defined in the FHIR specification for the given resource type. The resource providers also extend a superclass which implements all of the other FHIR methods, such as Read, Create, Delete, etc. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/introduction.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/introduction.md index 4f6201b0222..e9c474c7a4b 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/introduction.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_jpa/introduction.md @@ -1,6 +1,6 @@ # JPA Server Introduction -The HAPI FHIR [RestfulServer](/hapi-fhir/docs/server/restful_server.html) module can be used to create a FHIR server endpoint against an arbitrary data source, which could be a database of your own design, an existing clinical system, a set of files, or anything else you come up with. +The HAPI FHIR [Plain Server](/hapi-fhir/docs/server_plain/introduction.html) module can be used to create a FHIR server endpoint against an arbitrary data source, which could be a database of your own design, an existing clinical system, a set of files, or anything else you come up with. HAPI also provides a persistence module which can be used to provide a complete RESTful server implementation, backed by a database of your choosing. This module uses the [JPA 2.0](http://en.wikipedia.org/wiki/Java_Persistence_API) API to store data in a database without depending on any specific database technology. @@ -69,7 +69,7 @@ web address. A common use for logical references is in references to conformance resources, such as ValueSets, StructureDefinitions, etc. For example, you might refer to the ValueSet `http://hl7.org/fhir/ValueSet/quantity-comparator` from your own resources. In this case, you are not necessarily telling the server that this is a real address that it should resolve, but rather that this is an identifier for a ValueSet where `ValueSet.url` has the given URI/URL. -HAPI can be configured to treat certain URI/URL patterns as logical by using the DaoConfig#setTreatReferencesAsLogical property (see [JavaDoc](/hapi-fhir/apidocs/hapi-fhir-jpaserver-base/ca/uhn/fhir/jpa/dao/DaoConfig.html#setTreatReferencesAsLogical-java.util.Set-)). +HAPI can be configured to treat certain URI/URL patterns as logical by using the DaoConfig#setTreatReferencesAsLogical property (see [JavaDoc](/hapi-fhir/apidocs/hapi-fhir-jpaserver-base/ca/uhn/fhir/jpa/dao/DaoConfig.html#setTreatReferencesAsLogical(java.util.Set))). For example: diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/introduction.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/introduction.md index 7edc5e2a9ec..fd84c9d39f6 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/introduction.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/introduction.md @@ -56,7 +56,7 @@ This strategy is shown in the following example: ## Other Strategies -See the [IServerAddressStrategy](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IServerAddressStrategy.html) JavaDoc (specifically the list of "All Known Implementing Classes") to see other strategies that are available. +See the [IServerAddressStrategy](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IServerAddressStrategy.html) JavaDoc (specifically the list of "All Known Implementing Classes") to see other strategies that are available. @@ -64,7 +64,7 @@ See the [IServerAddressStrategy](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/serv The HAPI FHIR RESTful Server will automatically generate a Server [CapabilityStatement](http://hl7.org/fhir/capabilitystatement.html) resource (or a Server [Conformance](https://www.hl7.org/fhir/DSTU2/conformance.html) resource for FHIR DSTU2). -This statement is automatically generated based on the various annotated methods which are provided to the server. This behaviour may be modified by creating a new class containing a method annotated with a [@Metadata annotation](./restful_operations.html#system_conformance) and then passing an instance of that class to the [setServerConformanceProvider(Object)](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/RestfulServer.html#setServerConformanceProvider(java.lang.Object)) method on your RestfulServer instance. +This statement is automatically generated based on the various annotated methods which are provided to the server. This behaviour may be modified by creating a new class containing a method annotated with a [@Metadata annotation](./rest_operations.html#system_capabilities) and then passing an instance of that class to the [setServerConformanceProvider(Object)](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/RestfulServer.html#setServerConformanceProvider(java.lang.Object)) method on your RestfulServer instance. ## Enhancing the Generated CapabilityStatement @@ -72,12 +72,12 @@ If you have a need to add your own content (special extensions, etc.) to your se The generator class is version-specific, so you will need to extend the class appropriate for the version of FHIR you are implementing: -* DSTU3: [ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider](/apidocs/hapi-fhir-structures-dstu2/ca/uhn/fhir/rest/server/provider/dstu2.ServerConformanceProvider.html) -* DSTU3: [org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider](/apidocs/hapi-fhir-structures-dstu3/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProvider.html) -* R4: [org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider](/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.html) -* R5: [org.hl7.fhir.r5.hapi.rest.server.ServerCapabilityStatementProvider](/apidocs/hapi-fhir-structures-r5/org/hl7/fhir/r5/hapi/rest/server/ServerCapabilityStatementProvider.html) +* DSTU3: [ca.uhn.fhir.rest.server.provider.dstu2.ServerConformanceProvider](/hapi-fhir/apidocs/hapi-fhir-structures-dstu2/ca/uhn/fhir/rest/server/provider/dstu2/ServerConformanceProvider.html) +* DSTU3: [org.hl7.fhir.dstu3.hapi.rest.server.ServerCapabilityStatementProvider](/hapi-fhir/apidocs/hapi-fhir-structures-dstu3/org/hl7/fhir/dstu3/hapi/rest/server/ServerCapabilityStatementProvider.html) +* R4: [org.hl7.fhir.r4.hapi.rest.server.ServerCapabilityStatementProvider](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.html) +* R5: [org.hl7.fhir.r5.hapi.rest.server.ServerCapabilityStatementProvider](/hapi-fhir/apidocs/hapi-fhir-structures-r5/org/hl7/fhir/r5/hapi/rest/server/ServerCapabilityStatementProvider.html) -In your own class extending this class, you can override the [`getServerConformance()`](/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.html#getServerConformance()) method to provide your own implementation. In this method, call `super.getServerConformance()` to obtain the built-in conformance statement and then add your own information to it. +In your own class extending this class, you can override the [`getServerConformance()`](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/rest/server/ServerCapabilityStatementProvider.html#getServerConformance(javax.servlet.http.HttpServletRequest,ca.uhn.fhir.rest.api.server.RequestDetails)) method to provide your own implementation. In this method, call `super.getServerConformance()` to obtain the built-in conformance statement and then add your own information to it. # Controlling Response Contents / Encoding / Formatting diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/jax_rs.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/jax_rs.md new file mode 100644 index 00000000000..a905b38c4fe --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/jax_rs.md @@ -0,0 +1,57 @@ +# JAX-RS Server + +The HAPI FHIR Plain Server ([RestfulServer](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/RestfulServer.html)) is implemented as a standard JEE Servlet, meaning that it can be deployed in any compliant JEE web container. + +For users who already have an existing JAX-RS infrastructure, and who would like to use that technology foor their FHIR stack as well, a module exists which implements the server using [JAX-RS technology](https://jax-rs-spec.java.net/nonav/2.0/apidocs/index.html). + +
+ The JAX-RS module is a community-supported module that was not developed by the core HAPI FHIR team. Before decid the HAPI FHIR JAX-RS module, please be aware that it does not have as complete of support for the full FHIR REST specification as the Plain Server. If you need a feature that is missing, please consiider adding it and making a pull request! +
+ +## Features + +The server currently supports: + +* Automatic [Capability Statement Generation](./introduction.html#capabilities) +* [@Read](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Read.html) +* [@RSearch](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Search.html) +* [@Create](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Create.html) +* [@Update](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Update.html) +* [@Delete](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Delete.html) +* [@Operation](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Operation.html) + +The primary intention for this project is to ensure that other web technologies (JAX-RS in this case) can be used together with the base-server functionality. +An example server can be found in the Git repo [here](https://github.com/jamesagnew/hapi-fhir/tree/master/hapi-fhir-jaxrsserver-example). + +# JAX-RS Implementation specifics + +The set-up of a JAX-RS server goes beyond the scope of this documentation. The implementation of the server follows the same pattern as the standard server. It is required to put the correct [annotation](./rest_operations.html) on the methods in the [Resource Providers](./resource_providers.html) in order to be able to call them. + +Implementing a JAX-RS Resource Provider requires some JAX-RS annotations. The [@Path](https://docs.oracle.com/javaee/6/api/javax/ws/rs/Path.html) annotation needs to define the resource path. The
@Produces annotation needs to declare the produced formats. The constructor needs to pass the class of the object explicitely in order to avoid problems with proxy classes in a Java EE environment. + +It is necessary to extend the abstract class [AbstractJaxRsResourceProvide](/hapi-fhir/apidocs/hapi-fhir-jaxrsserver-base/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.html). + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/JaxRsPatientRestProvider.java|jax-rs-provider-construction}} +``` + +## Extended Operations + +[Extended Operations](./rest_operations_operations.html) require the correct JAX-RS ( +[@Path](https://docs.oracle.com/javaee/6/api/javax/ws/rs/Path.html), [@GET](https://docs.oracle.com/javaee/6/api/javax/ws/rs/GET.html) or [@POST](https://docs.oracle.com/javaee/6/api/javax/ws/rs/POST.html) annotations. The body of the method needs to call the method [AbstractJaxRsResourceProvider#customOperation](/hapi-fhir/apidocs/hapi-fhir-jaxrsserver-base/ca/uhn/fhir/jaxrs/server/AbstractJaxRsResourceProvider.html#customOperation(java.lang.String,ca.uhn.fhir.rest.api.RequestTypeEnum,java.lang.String,java.lang.String,ca.uhn.fhir.rest.api.RestOperationTypeEnum) with the correct parameters. The server will then call the method with corresponding name. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/JaxRsPatientRestProvider.java|jax-rs-provider-operation}} +``` + +In order to create the conformance profile, a conformance provider class needs to be deployed which exports the provider's conformance statements. These providers need to be returned as the result of the method [AbstractJaxRsConformanceProvider#getProviders](/hapi-fhir/apidocs/hapi-fhir-jaxrsserver-base/ca/uhn/fhir/jaxrs/server/AbstractJaxRsConformanceProvider.html#getProviders()). This method is called once, during [PostConstruct](https://docs.oracle.com/javaee/6/api/javax/annotation/PostConstruct.html). + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/JaxRsConformanceProvider.java|jax-rs-conformance}} +``` + +# A Complete Example + +A complete example showing how to implement a JAX-RS RESTful server can be found in our Git repo here: + +* [hapi-fhir-jaxrsserver-example](https://github.com/jamesagnew/hapi-fhir/tree/master/hapi-fhir-jaxrsserver-example) diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/multitenency.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/multitenency.md index 957b3295737..58b03dbd896 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/multitenency.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/multitenency.md @@ -8,7 +8,7 @@ This means that additional logic will be performed during request parsing to det Using URL Base Multitenancy means that an additional element is added to the path of each resource between the server base URL and the resource name. For example, if your restful server is deployed to `http://acme.org:8080/baseDstu3` and a client wishes to access Patient 123 for Tenant "FOO", the resource ID (and URL to fetch that resource) would be `http://acme.org:8080/FOO/Patient/123`. -To enable this mode on your server, simply provide the [UrlBaseTenantIdentificationStrategy](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/tenant/UrlBaseTenantIdentificationStrategy.html) to the server as shown below: +To enable this mode on your server, simply provide the [UrlBaseTenantIdentificationStrategy](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/tenant/UrlBaseTenantIdentificationStrategy.html) to the server as shown below: ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/Multitenancy.java|enableUrlBaseTenantIdentificationStrategy}} diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/paging.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/paging.md index 078b042059e..3ab0de11cde 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/paging.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/paging.md @@ -8,7 +8,7 @@ There are two complementary parts to the HAPI FHIR server paging support: paging ## Paging Providers -To support paging, a server must have an [IPagingProvider](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IPagingProvider.html) implementation set. The paging provider is used to store resource return lists between incoming calls by clients. +To support paging, a server must have an [IPagingProvider](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IPagingProvider.html) implementation set. The paging provider is used to store resource return lists between incoming calls by clients. A paging provider provides two key methods: @@ -26,7 +26,7 @@ The following example shows a server implementation with paging support. # Bundle Providers -If a server supports a paging provider, a further optimization is to also use a bundle provider. A bundle provider simply takes the place of the `List` return type in your provider methods. In other words, instead of returning *List*, your search method will return [IBundleProvider](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IBundleProvider.html). +If a server supports a paging provider, a further optimization is to also use a bundle provider. A bundle provider simply takes the place of the `List` return type in your provider methods. In other words, instead of returning *List*, your search method will return [IBundleProvider](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/api/server/IBundleProvider.html). When using a bundle provider however, the server will only request small sublists of resources as they are actually being returned. This allows servers to optimize by not loading all resources into memory until they are actually needed. @@ -46,5 +46,5 @@ Another option is to use "named pages", meaning that each page is simply assigne In order to support named pages, the IPagingProvider must implement the `retrieveResultList(RequestDetails theRequestDetails, String theSearchId, String thePageId)` method. -Then, individual search/history methods may return a [BundleProviderWithNamedPages](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/BundleProviderWithNamedPages.html) or simply implement the `getPageId()` method on their own IBundleProvider implementation. +Then, individual search/history methods may return a [BundleProviderWithNamedPages](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/BundleProviderWithNamedPages.html) or simply implement the `getPageId()` method on their own IBundleProvider implementation. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/resource_providers.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/resource_providers.md index e1a82b82cd3..f72a13ca7f8 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/resource_providers.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/resource_providers.md @@ -10,7 +10,7 @@ There are two types of providers that can be registered against a HAPI FHIR Plai # Resource Providers -A Resource provider class must implement the [IResourceProvider](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IResourceProvider.html) interface, and will contain one or more methods which have been annotated with special annotations indicating which RESTful operation that method supports. Below is a simple example of a resource provider which supports the FHIR [read](http://hl7.org/fhir/http.html#read) operation (i.e. retrieve a single resource by ID) as well as the FHIR [search](http://hl7.org/fhir/http.html#search) operation (i.e. find any resources matching a given criteria) for a specific search criteria. +A Resource provider class must implement the [IResourceProvider](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IResourceProvider.html) interface, and will contain one or more methods which have been annotated with special annotations indicating which RESTful operation that method supports. Below is a simple example of a resource provider which supports the FHIR [read](http://hl7.org/fhir/http.html#read) operation (i.e. retrieve a single resource by ID) as well as the FHIR [search](http://hl7.org/fhir/http.html#search) operation (i.e. find any resources matching a given criteria) for a specific search criteria. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProvider.java|provider}} @@ -18,7 +18,7 @@ A Resource provider class must implement the [IResourceProvider](/apidocs/hapi-f ## Adding more Methods (Search, History, Create, etc.) -You will probably wish to add more methods to your resource provider. See [RESTful Operations](./restful_operatons.html) for lots more examples of how to add methods for various operations. +You will probably wish to add more methods to your resource provider. See [REST Operations](./rest_operations.html) for lots more examples of how to add methods for various operations. For now, we will move on to the next step though, which is creating the actual server to hold your resource providers and deploying that. Once you have this working, you might want to come back and start adding other operations. @@ -26,7 +26,7 @@ For now, we will move on to the next step though, which is creating the actual s Once your resource providers are created, your next step is to define a server class. -HAPI provides a class called [RestfulServer](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/RestfulServer.html), which is a specialized Java Servlet. To create a server, you simply create a class which extends RestfulServer as shown in the example below. +HAPI provides a class called [RestfulServer](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/RestfulServer.html), which is a specialized Java Servlet. To create a server, you simply create a class which extends RestfulServer as shown in the example below. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExampleRestfulServlet.java|servlet}} @@ -42,15 +42,15 @@ In addition to **Resource Providers**, which are resource-type specific, a secon Defining one provider per resource is a good strategy to keep code readable and maintainable, but it is also possible to put methods for multiple resource types in a provider class. -Providers which do not implement the [IResourceProvider](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IResourceProvider.html) (and therefore are not bound to one specific resource type) are known as **Plain Providers**. +Providers which do not implement the [IResourceProvider](/hapi-fhir/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/IResourceProvider.html) (and therefore are not bound to one specific resource type) are known as **Plain Providers**. -A plain provider may implement any [RESTful operation](./restful_operations.html), but will generally need to explicitly state what type of resource it applies to. If the method directly returns a resource or a collection of resources (as in an [instance read](./restful_operations.htmnl.html#instance_read) or [type search](./restful_operations.html#type_search) operation) the resource type will be inferred automatically. If the method returns a [Bundle Resource](http://hl7.org/fhir/bundle.html), it is necessary to explicitly specify the resource type in the method annotation. The following example shows this: +A plain provider may implement any [REST operation](./rest_operations.html), but will generally need to explicitly state what type of resource it applies to. If the method directly returns a resource or a collection of resources (as in an [instance read](./rest_operations.html#instance_read) or [type search](./rest_operations.html#type_search) operation) the resource type will be inferred automatically. If the method returns a [Bundle Resource](http://hl7.org/fhir/bundle.html), it is necessary to explicitly specify the resource type in the method annotation. The following example shows this: ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/ExampleProviders.java|plainProvider}} ``` -In addition, some methods are not resource specific. For example, the [system history](./restful_operations.html#system-history) operation returns historical versions of *all resource types* on a server, so it needs to be defined in a plain provider. +In addition, some methods are not resource specific. For example, the [system history](./rest_operations.html#history) operation returns historical versions of *all resource types* on a server, so it needs to be defined in a plain provider. Once you have defined your plain providers, they are passed to the server in a similar way to the resource providers. @@ -60,7 +60,7 @@ Once you have defined your plain providers, they are passed to the server in a s # Common Method Parameters -Different RESTful methods will have different requirements in terms of the method parameters they require, as described in the [RESTful Operations](./restful_operations.html) page. +Different RESTful methods will have different requirements in terms of the method parameters they require, as described in the [REST Operations](./rest_operations.html) page. In addition, there are several parameters you may add in order to meet specific needs of your application. @@ -90,11 +90,11 @@ In many cases, you will want to respond to client requests with a specific HTTP Sometimes this is simply a requirement of your specific application (e.g. you want to provide application specific HTTP status codes for certain types of errors), and other times this may be a requirement of the FHIR or HTTP specifications to respond in a specific way to certain conditions. -To customize the error that is returned by HAPI's server methods, you should throw an exception which extends HAPI's [BaseServerResponseException](/apidocs/hapi-fhir-server/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.html) class. Various exceptions which extend this class will generate a different HTTP status code. +To customize the error that is returned by HAPI's server methods, you should throw an exception which extends HAPI's [BaseServerResponseException](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/BaseServerResponseException.html) class. Various exceptions which extend this class will generate a different HTTP status code. -For example, the [ResourceNotFoundException](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.html) causes HAPI to return an `HTTP 404 Resource Not Found`. A complete list of available exceptions is available in the [exceptions package summary](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/package-summary.html). +For example, the [ResourceNotFoundException](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/ResourceNotFoundException.html) causes HAPI to return an `HTTP 404 Resource Not Found`. A complete list of available exceptions is available in the [exceptions package summary](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/package-summary.html). -If you wish to return an HTTP status code for which there is no pre-defined exception, you may throw the [UnclassifiedServerFailureException](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/UnclassifiedServerFailureException.html), which allows you to return any status code you wish. +If you wish to return an HTTP status code for which there is no pre-defined exception, you may throw the [UnclassifiedServerFailureException](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/UnclassifiedServerFailureException.html), which allows you to return any status code you wish. ## Returning an OperationOutcome for Errors @@ -106,7 +106,7 @@ By default, HAPI will automatically generate an OperationOutcome which contains # Server Lifecycle Methods -Resource providers may optionally want to be notified when the server they are registered with is being destroyed, so that they can perform cleanup. In this case, a method annotated with the [@Destroy](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Destroy.html) annotation can be added (this method should be public, return `void`, and take no parameters). +Resource providers may optionally want to be notified when the server they are registered with is being destroyed, so that they can perform cleanup. In this case, a method annotated with the [@Destroy](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Destroy.html) annotation can be added (this method should be public, return `void`, and take no parameters). This method will be invoked once by the RestfulServer when it is shutting down. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations.md index 4bd1d2e452d..92028f2dfcb 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations.md @@ -1,12 +1,12 @@ # REST Operations: Overview -This page shows the operations which can be implemented on HAPI [Plain Server](/docs/server_plain/introduction.html), as well as on the [Annotation Client](/docs/client/annotation.html). Most of the examples shown here show how to implement a server method, but to perform an equivalent call on an annotation client you simply put a method with the same signature in your client interface. +This page shows the operations which can be implemented on HAPI [Plain Server](/docs/server_plain/introduction.html), as well as on the [Annotation Client](/docs/client/annotation_client.html). Most of the examples shown here show how to implement a server method, but to perform an equivalent call on an annotation client you simply put a method with the same signature in your client interface. # Instance Level - Read -The [read](http://hl7.org/fhir/http.html#read) operation retrieves a resource by ID. It is annotated with the [@Read](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Read.html) annotation, and has at least a single parameter annotated with the [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation. +The [read](http://hl7.org/fhir/http.html#read) operation retrieves a resource by ID. It is annotated with the [@Read](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Read.html) annotation, and has at least a single parameter annotated with the [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|read}} @@ -28,7 +28,7 @@ The following snippet shows how to define a client interface to handle a read me # Instance Level - VRead -The **[vread](http://hl7.org/implement/standards/fhir/http.html#vread)** operation retrieves a specific version of a resource with a given ID. To support vread, simply add "version=true" to your [@Read](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Read.html) annotation. This means that the read method will support both "Read" and "VRead". The IdType instance passed into your method may or may not have the version populated depending on the client's request. +The **[vread](http://hl7.org/implement/standards/fhir/http.html#vread)** operation retrieves a specific version of a resource with a given ID. To support vread, simply add "version=true" to your [@Read](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Read.html) annotation. This means that the read method will support both "Read" and "VRead". The IdType instance passed into your method may or may not have the version populated depending on the client's request. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|vread}} @@ -46,11 +46,11 @@ http://fhir.example.com/Patient/111/_history/2 The **[update](http://hl7.org/implement/standards/fhir/http.html#update)** operation updates a specific resource instance (using its ID), and optionally accepts a version ID as well (which can be used to detect version conflicts). -Update methods must be annotated with the [@Update](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Update.html) annotation, and have a parameter annotated with the [@ResourceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) annotation. This parameter contains the resource instance to be created. See the [@ResourceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) for information on the types allowed for this parameter (resource types, String, byte[]). +Update methods must be annotated with the [@Update](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Update.html) annotation, and have a parameter annotated with the [@ResourceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) annotation. This parameter contains the resource instance to be created. See the [@ResourceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) for information on the types allowed for this parameter (resource types, String, byte[]). -In addition, the method may optionally have a parameter annotated with the [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, or they may obtain the ID of the resource being updated from the resource itself. Either way, this ID comes from the URL passed in. +In addition, the method may optionally have a parameter annotated with the [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, or they may obtain the ID of the resource being updated from the resource itself. Either way, this ID comes from the URL passed in. -Update methods must return an object of type [MethodOutcome](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html). This object contains the identity of the created resource. +Update methods must return an object of type [MethodOutcome](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html). This object contains the identity of the created resource. The following snippet shows how to define an update method on a server: @@ -72,7 +72,7 @@ The following snippet shows how the corresponding client interface would look: ## Conditional Updates -If you wish to support conditional updates, you can add a parameter tagged with a [@ConditionalOperationParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ConditionalOperationParam.html) annotation. If the request URL contains search parameters instead of a resource ID, then this parameter will be populated. +If you wish to support conditional updates, you can add a parameter tagged with a [@ConditionalUrlParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ConditionalUrlParam.html) annotation. If the request URL contains search parameters instead of a resource ID, then this parameter will be populated. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|updateConditional}} @@ -88,7 +88,7 @@ http://fhir.example.com/Patient?identifier=system%7C00001 ## Accessing The Raw Resource Payload -If you wish to have access to the raw resource payload as well as the parsed value for any reason, you may also add parameters which have been annotated with the [@ResourceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) of type `String` (to access the raw resource body) and/or `EncodingEnum` (to determine which encoding was used). +If you wish to have access to the raw resource payload as well as the parsed value for any reason, you may also add parameters which have been annotated with the [@ResourceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) of type `String` (to access the raw resource body) and/or `EncodingEnum` (to determine which encoding was used). The following example shows how to use these additional data elements. @@ -134,7 +134,7 @@ If a client performs a contention aware update, the ETag version will be placed # Instance Level - Delete -The [delete](http://hl7.org/implement/standards/fhir/http.html#delete) operation retrieves a specific version of a resource with a given ID. It takes a single ID parameter annotated with an [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, which supplies the ID of the resource to delete. +The [delete](http://hl7.org/implement/standards/fhir/http.html#delete) operation retrieves a specific version of a resource with a given ID. It takes a single ID parameter annotated with an [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, which supplies the ID of the resource to delete. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|delete}} @@ -143,7 +143,7 @@ The [delete](http://hl7.org/implement/standards/fhir/http.html#delete) operation Delete methods are allowed to return the following types: * **void**: This method may return `void`, in which case the server will return an empty response and the client will ignore any successful response from the server (failure responses will still throw an exception) -* **[MethodOutcome](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html)**: This method may return a `MethodOutcome`, which is a wrapper for the FHIR OperationOutcome resource, which may optionally be returned by the server according to the FHIR specification. +* **[MethodOutcome](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html)**: This method may return a `MethodOutcome`, which is a wrapper for the FHIR OperationOutcome resource, which may optionally be returned by the server according to the FHIR specification. Example URL to invoke this method (HTTP DELETE): @@ -181,9 +181,9 @@ The following snippet shows how to define a patch method on a server: The [create](http://hl7.org/implement/standards/fhir/http.html#create) operation saves a new resource to the server, allowing the server to give that resource an ID and version ID. -Create methods must be annotated with the [@Create](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Create.html) annotation, and have a single parameter annotated with the [@ResourceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) annotation. This parameter contains the resource instance to be created. See the [@ResourceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) for information on the types allowed for this parameter (resource types, String, byte[]). +Create methods must be annotated with the [@Create](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Create.html) annotation, and have a single parameter annotated with the [@ResourceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) annotation. This parameter contains the resource instance to be created. See the [@ResourceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) for information on the types allowed for this parameter (resource types, String, byte[]). -Create methods must return an object of type [MethodOutcome](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html). This object contains the identity of the created resource. +Create methods must return an object of type [MethodOutcome](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html). This object contains the identity of the created resource. The following snippet shows how to define a server create method: @@ -208,7 +208,7 @@ The following snippet shows how the corresponding client interface would look: The FHIR specification also allows "conditional creates". A conditional create has an additional header called `If-None-Exist` which the client will supply on the HTTP request. The client will populate this header with a search URL such as `Patient?identifier=foo`. See the FHIR specification for details on the semantics for correctly implementing conditional create. When a conditional create is detected (i.e. when the create request contains a populated `If-None-Exist` header), if a method parameter annotated with the -[@ConditionalOperationParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ConditionalOperationParam.html) is detected, it will be populated with the value of this header. +[@ConditionalUrlParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ConditionalUrlParam.html) is detected, it will be populated with the value of this header. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|createConditional}} @@ -247,28 +247,28 @@ Searching is a very powerful and potentially very complicated operation to imple The [validate](http://hl7.org/implement/standards/fhir/http.html#validate) operation tests whether a resource passes business validation, and would be acceptable for saving to a server (e.g. by a create or update method). -Validate methods must be annotated with the [@Validate](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Validate.html) annotation, and have a parameter annotated with the [@ResourceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) annotation. This parameter contains the resource instance to be created. +Validate methods must be annotated with the [@Validate](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Validate.html) annotation, and have a parameter annotated with the [@ResourceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) annotation. This parameter contains the resource instance to be created. -Validate methods may optionally also have a parameter of type IdType annotated with the [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation. This parameter contains the resource ID (see the [FHIR specification](http://hl7.org/implement/standards/fhir/http.html#validation) for details on how this is used). +Validate methods may optionally also have a parameter of type IdType annotated with the [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation. This parameter contains the resource ID (see the [FHIR specification](http://hl7.org/implement/standards/fhir/http.html#validation) for details on how this is used). -Validate methods must return normally if the resource validates successfully, or throw an [UnprocessableEntityException](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/UnprocessableEntityException.html) or [InvalidRequestException](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.html) if the validation fails. +Validate methods must return normally if the resource validates successfully, or throw an [UnprocessableEntityException](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/UnprocessableEntityException.html) or [InvalidRequestException](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/server/exceptions/InvalidRequestException.html) if the validation fails. Validate methods must return either: * **void** – The method should throw an exception for a validation failure, or return normally. -* An object of type [MethodOutcome](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html). The MethodOutcome may optionally be populated with an OperationOutcome resource, which will be returned to the client if it exists. +* An object of type [MethodOutcome](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/MethodOutcome.html). The MethodOutcome may optionally be populated with an OperationOutcome resource, which will be returned to the client if it exists. The following snippet shows how to define a server validate method: ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|validate}} ``` -In the example above, only the [@ResourceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) parameter is technically required, but you may also add the following parameters: +In the example above, only the [@ResourceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/ResourceParam.html) parameter is technically required, but you may also add the following parameters: -* **[@Validate.Mode](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Validate.html#Mode) ValidationModeEnum theMode** - This is the validation mode (see the FHIR specification for information on this) +* **[@Validate.Mode](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Validate.Mode.html) ValidationModeEnum theMode** - This is the validation mode (see the FHIR specification for information on this) -* **[@Validate.Profile](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Validate.html#Profile) String profile** - This is the profile to validate against (see the FHIR specification for more information on this) +* **[@Validate.Profile](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Validate.Profile.html) String profile** - This is the profile to validate against (see the FHIR specification for more information on this) Example URL to invoke this method (this would be invoked using an HTTP POST, with a Parameters resource in the POST body): @@ -284,7 +284,7 @@ FHIR defines that a FHIR Server must be able to export a Capability Statement (f The HAPI FHIR RESTful server will automatically export such a capability statement. See the [Server Capability Statement](./introduction.html#capabilities) documentation for more information. -If you wish to override this default behaviour by creating your own capability statement provider, you simply need to define a class with a method annotated using the [@Metadata](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Metadata.html) annotation. +If you wish to override this default behaviour by creating your own capability statement provider, you simply need to define a class with a method annotated using the [@Metadata](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Metadata.html) annotation. An example provider is shown below. @@ -292,13 +292,13 @@ An example provider is shown below. {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|metadataProvider}} ``` -To create a Client which can retrieve a Server's conformance statement is simple. First, define your Client Interface, using the [@Metadata](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Metadata.html) annotation: +To create a Client which can retrieve a Server's conformance statement is simple. First, define your Client Interface, using the [@Metadata](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Metadata.html) annotation: ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|metadataClient}} ``` -Then use the standard [REST Client](/docs/client/fooo) mechanism for instantiating a client: +You can then use the standard [Annotation Client](/docs/client/annotation_client.html) mechanism for instantiating a client: ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|metadataClientUsage}} @@ -316,11 +316,11 @@ HAPI provides a skeleton for implementing this action, although most of the effo {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|transaction}} ``` -Transaction methods require one parameter annotated with [@TransactionParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/TransactionParam.html), and that parameter may be of type [`List`](/apidocs/hapi-fhir-base/org/hl7/fhir/instance/model/api/IBaseResource.html) or [`Bundle`](/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Bundle.html)`. +Transaction methods require one parameter annotated with [@TransactionParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/TransactionParam.html), and that parameter may be of type [`List`](/hapi-fhir/apidocs/hapi-fhir-base/org/hl7/fhir/instance/model/api/IBaseResource.html) or [`Bundle`](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Bundle.html)`. In terms of actually implementing the method, unfortunately there is only so much help HAPI will give you. One might expect HAPI to automatically delegate the individual operations in the transaction to other methods on the server but at this point it does not do that. There is a lot that transaction needs to handle (making everything atomic, replacing placeholder IDs across multiple resources which may even be circular, handling operations in the right order) and so far we have not found a way for the framework to do this in a generic way. -What it comes down to is the fact that transaction is a tricky thing to implement. For what it's worth, you could look at the HAPI FHIR JPA Server [TransactionProcessor](/apidocs/hapi-fhir-jpaserver-base/ca/uhn/fhir/jpa/dao/TransactionProcessor.html) class for inspiration on how to build a transaction processor of your own (note that this class is tightly coupled with the rest of the JPA Server so it is unlikely that it can be used directly outside of that context). +What it comes down to is the fact that transaction is a tricky thing to implement. For what it's worth, you could look at the HAPI FHIR JPA Server [TransactionProcessor](/hapi-fhir/apidocs/hapi-fhir-jpaserver-base/ca/uhn/fhir/jpa/dao/TransactionProcessor.html) class for inspiration on how to build a transaction processor of your own (note that this class is tightly coupled with the rest of the JPA Server so it is unlikely that it can be used directly outside of that context). Example URL to invoke this method (note that the URL is the base URL for the server, and the request body is a Bundle resource): @@ -347,20 +347,20 @@ Not yet implemented - Get in touch if you would like to help! The [history](http://hl7.org/implement/standards/fhir/http.html#history) operation retrieves a historical collection of all versions of a single resource *(instance history)*, all resources of a given type *(type history)*, or all resources of any type on a server *(server history)*. -History methods are annotated with the [@History](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation, and will have additional requirements depending on the kind of history method intended: +History methods are annotated with the [@History](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation, and will have additional requirements depending on the kind of history method intended: -* For an **Instance History** method, the method must have a parameter annotated with the [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, indicating the ID of the resource for which to return history. The method must either be defined in a [resource provider](./resource_providers.html#resource-providers), or must have a `type()` value in the [@History](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation if it is defined in a [plain provider](./resource_providers.html#plain-providers). +* For an **Instance History** method, the method must have a parameter annotated with the [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, indicating the ID of the resource for which to return history. The method must either be defined in a [resource provider](./resource_providers.html#resource-providers), or must have a `type()` value in the [@History](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation if it is defined in a [plain provider](./resource_providers.html#plain-providers). -* For a **Type History** method, the method must not have any [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) parameter. The method must either be defined in a [resource provider](./resource_providers.html#resource-providers), or must have a `type()` value in the [@History](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation if it is defined in a [plain provider](./resource_providers.html#plain-providers). +* For a **Type History** method, the method must not have any [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) parameter. The method must either be defined in a [resource provider](./resource_providers.html#resource-providers), or must have a `type()` value in the [@History](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation if it is defined in a [plain provider](./resource_providers.html#plain-providers). -* For a **Server History** method, the method must not have any [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) parameter, and must not have a `type()` value specified in the [@History](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation. The method must be defined in a [plain provider](./resource_providers.html#plain-providers). +* For a **Server History** method, the method must not have any [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) parameter, and must not have a `type()` value specified in the [@History](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/History.html) annotation. The method must be defined in a [plain provider](./resource_providers.html#plain-providers). The following snippet shows how to define a history method on a server. Note that the following parameters are both optional, but may be useful in implementing the history operation: -* The [@Since](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Since.html) method argument implements the `_since` parameter and should be of type [DateTimeType](/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/DateTimeType.html). +* The [@Since](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Since.html) method argument implements the `_since` parameter and should be of type [DateTimeType](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/DateTimeType.html). -* The [@At](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/At.html) method argument implements the `_at` parameter and may be of type [DateRangeParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html) or [DateTimeType](/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/DateTimeType.html). +* The [@At](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/At.html) method argument implements the `_at` parameter and may be of type [DateRangeParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html) or [DateTimeType](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/DateTimeType.html). ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|history}} @@ -431,9 +431,9 @@ However, if you wish to add parameters to manually handle these fields, the foll FHIR defines a mechanism for logically grouping resources together called [compartments](http://www.hl7.org/implement/standards/fhir/extras.html#compartment). -To define a search by compartment, you simply need to add the `compartmentName()` attribute to the [@Search](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Search.html) annotation, and add an [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) parameter. +To define a search by compartment, you simply need to add the `compartmentName()` attribute to the [@Search](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Search.html) annotation, and add an [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) parameter. -The following example shows a search method in a resource provider which returns a compartment. Note that you may also add [@RequiredParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) and [@OptionalParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html) parameters to your compartment search method. +The following example shows a search method in a resource provider which returns a compartment. Note that you may also add [@RequiredParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) and [@OptionalParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html) parameters to your compartment search method. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|searchCompartment}} diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_operations.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_operations.md index 3238f8a8909..f0f7c2a7966 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_operations.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_operations.md @@ -1,10 +1,10 @@ -# REST Operations: Operations Framework +# REST Operations: Extended Operations The FHIR specification defines a special kind of operations that have an RPC-like functionality. These are called "Execute Operations", or simply "Operations" throughout the FHIR specification. A good introduction to this capability can be found on the [Operations Page](http://hl7.org/fhir/operations.html) of the FHIR Specification. -FHIR operations are a special type of RPC-style invocation you can perform against a FHIR server, type, or resource instance. These invocations are named using the convention `$name` (i.e. the name is prefixed with $) and will generally take a [Parameters](./apidocs-r4/org/hl7/fhir/r4/model/Parameters.html) resource as input and output. There are some cases where the input and/or output will be a different resource type however. +FHIR extended operations are a special type of RPC-style invocation you can perform against a FHIR server, type, or resource instance. These invocations are named using the convention `$name` (i.e. the name is prefixed with $) and will generally take a [Parameters](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Parameters.html) resource as input and output. There are some cases where the input and/or output will be a different resource type however. ## Providers @@ -12,7 +12,7 @@ To define an operation, a method should be placed in a [Resource Provider class] # Type-Level Operations -To implement a type-specific operation, the method should be annotated with the [@Operation](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Operation.html) tag, and should have an [@OperationParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OperationParam.html) tag for each named parameter that the input Parameters resource may be populated with. The following example shows how to implement the [`Patient/$everything`](http://hl7.org/fhir/operation-patient-everything.html) method, defined in the FHIR specification. +To implement a type-specific operation, the method should be annotated with the [@Operation](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Operation.html) tag, and should have an [@OperationParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OperationParam.html) tag for each named parameter that the input Parameters resource may be populated with. The following example shows how to implement the [`Patient/$everything`](http://hl7.org/fhir/operation-patient-everything.html) method, defined in the FHIR specification. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/ServerOperations.java|patientTypeOperation}} @@ -26,7 +26,7 @@ http://fhir.example.com/Patient/$everything # Instance-Level Operations -To create an instance-specific operation (an operation which takes the ID of a specific resource instance as a part of its request URL), you can add a parameter annotated with the [@IdParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, of type [IdType](/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/IdType.html). The following example shows how to implement the `Patient/[id]/$everything` operation. +To create an instance-specific operation (an operation which takes the ID of a specific resource instance as a part of its request URL), you can add a parameter annotated with the [@IdParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IdParam.html) annotation, of type [IdType](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/IdType.html). The following example shows how to implement the `Patient/[id]/$everything` operation. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/ServerOperations.java|patientInstanceOperation}} @@ -65,12 +65,12 @@ To use a search parameter type, any of the search parameter types listed in [Res Example URL to invoke this operation (HTTP request body is Parameters resource): ```url -http://fhir.example.com/$find-matches?date=2011-01-02&code=http://system|value +http://fhir.example.com/$find-matches?date=2011-01-02&code=http://system%7Cvalue ``` -It is also fine to use collection types for search parameter types if you want to be able to accept multiple values. For example, a [`List`](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenParam.html) could be used if you want to allow multiple repetitions of a given token parameter (this is analogous to the "AND" semantics in a search). +It is also fine to use collection types for search parameter types if you want to be able to accept multiple values. For example, a [`List`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenParam.html) could be used if you want to allow multiple repetitions of a given token parameter (this is analogous to the "AND" semantics in a search). -A [`TokenOrListParam`](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenOrListParam.html) could be used if you want to allow multiple values within a single repetition, separated by comma (this is analogous to "OR" semantics in a search). +A [`TokenOrListParam`](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenOrListParam.html) could be used if you want to allow multiple values within a single repetition, separated by comma (this is analogous to "OR" semantics in a search). For example: @@ -80,7 +80,7 @@ For example: # Returning Multiple OUT Parameters -In all of the Operation examples above, the return type specified for the operation is a single Resource instance. This is a common pattern in FHIR defined operations. However, it is also possible for an extended operation to be defined with multiple and/or repeating OUT parameters. In this case, you can return a [Parameters](/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Parameters.html) resource directly. +In all of the Operation examples above, the return type specified for the operation is a single Resource instance. This is a common pattern in FHIR defined operations. However, it is also possible for an extended operation to be defined with multiple and/or repeating OUT parameters. In this case, you can return a [Parameters](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Parameters.html) resource directly. # Accepting HTTP GET @@ -91,13 +91,13 @@ The FHIR specification allows for operations to be invoked using an HTTP GET ins * The operation is marked as "affectsState = false". Note that early releases of the FHIR specification referred to an operation that did not affect state as "idempotent = true". It was subsequently determined that *idempotency* was the wrong term for the concept being expressed, but the term does persist in some HAPI FHIR documentation and code. If you are implementing an operation which should allow HTTP GET, you should mark your operation with -`idempotent=true` in the [@Operation](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Operation.html). The default value for this flag is `false`, meaning that operations will not support HTTP GET by default. +`idempotent=true` in the [@Operation](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Operation.html). The default value for this flag is `false`, meaning that operations will not support HTTP GET by default. Note that the HTTP GET form is only supported if the operation has only primitive parameters (no complex parameters or resource parameters). If a client makes a request containing a complex parameter, the server will respond with an HTTP 405 Method Not Supported. # Manually handing Request/Response -For some operations you may wish to bypass the HAPI FHIR standard request parsing and/or response generation. In this case you may use the `manualRequest = true` and/or `manualResponse = true` attributes on the [@Operation](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Operation.html) annotation. +For some operations you may wish to bypass the HAPI FHIR standard request parsing and/or response generation. In this case you may use the `manualRequest = true` and/or `manualResponse = true` attributes on the [@Operation](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Operation.html) annotation. The following example shows an operation that parses the request and generates a response (by echoing back the request). diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_search.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_search.md index 598cf65ea42..64299f669e9 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_search.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/rest_operations_search.md @@ -18,11 +18,11 @@ http://fhir.example.com/Patient # Search Parameters: String Introduction -To allow a search using given search parameters, add one or more parameters to your search method and tag these parameters as either [@RequiredParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) or [@OptionalParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html). +To allow a search using given search parameters, add one or more parameters to your search method and tag these parameters as either [@RequiredParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) or [@OptionalParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html). This annotation takes a "name" parameter which specifies the parameter's name (as it will appear in the search URL). FHIR defines standardized parameter names for each resource, and these are available as constants on the individual HAPI resource classes. -Parameters which take a string as their format should use the [StringParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringParam.html) type. They may also use normal java `String`, although it is not possible to use modifiers such as the `:exact` modifier in that case. +Parameters which take a string as their format should use the [StringParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringParam.html) type. They may also use normal java `String`, although it is not possible to use modifiers such as the `:exact` modifier in that case. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|searchStringParam}} @@ -54,7 +54,7 @@ The FHIR specification provides a syntax for specifying dates+times (but for sim Dates may be optionally prefixed with a qualifier. For example, the string `=ge2011-01-02` means any date on or after 2011-01-02. -To accept a qualified date parameter, use the [DateParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateParam.html) parameter type. +To accept a qualified date parameter, use the [DateParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateParam.html) parameter type. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|dates}} @@ -80,7 +80,7 @@ A common scenario in searches is to allow searching for resources with values (i FHIR allows for multiple parameters with the same key, and interprets these as being an ***AND*** set. So, for example, a range of `&date=gt2011-01-01&date=lt2011-02-01` can be interpreted as any date within January 2011. -The following snippet shows how to accept such a range, and combines it with a specific identifier, which is a common scenario. (i.e. Give me a list of observations for a specific patient within a given date range). This is accomplished using a single parameter of type [DateRangeParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html). +The following snippet shows how to accept such a range, and combines it with a specific identifier, which is a common scenario. (i.e. Give me a list of observations for a specific patient within a given date range). This is accomplished using a single parameter of type [DateRangeParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html). ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|dateRange}} @@ -108,7 +108,7 @@ An example of this might be the following URL, which refers to any Observation r http://fhir.example.com/Observation?subject.identifier=7000135&date=gt2011-01-01 ``` -When such a request is made of a server (or to make such a request from a client), the `getLowerBound()` or `getUpperBound()` property of the [DateRangeParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html) object will be set to `null`. +When such a request is made of a server (or to make such a request from a client), the `getLowerBound()` or `getUpperBound()` property of the [DateRangeParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html) object will be set to `null`. # Search Parameters: Quantity @@ -130,12 +130,23 @@ http://fhir.example.com/Observation?value-quantity=lt123.2||mg|http://unitsofmea Many search parameters refer to resource references. For instance, the Patient parameter "provider" refers to the resource marked as the managing organization for patients. -Reference parameters use the [ReferenceParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/ReferenceParam.html) type. Reference parameters are, in their most basic form, just a pointer to another resource. For example, you might want to query for DiagnosticReport resources where the subject (the Patient resource that the report is about) is Patient/123. The following example shows a simple resource reference parameter in use. +Reference parameters use the [ReferenceParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/ReferenceParam.html) type. Reference parameters are, in their most basic form, just a pointer to another resource. For example, you might want to query for DiagnosticReport resources where the subject (the Patient resource that the report is about) is Patient/123. The following example shows a simple resource reference parameter in use. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|referenceSimple}} ``` + + +# Search Parameters: Filter + +To implement the FHIR [_filter](http://hl7.org/fhir/search_filter.html) search style, you may create a parameter of type `StringParam` (or one of the and/or derivatives), as shown below. + +```java +@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_FILTER) +StringAndListParam theFtFilter +``` + # Chained Resource References References may also support a "chained" value. This is a search parameter name on the target resource. For example, you might want to search for DiagnosticReport resources by subject, but use the subject's last name instead of their resource ID. In this example, you are chaining "family" (the last name) to "subject" (the patient). @@ -198,11 +209,11 @@ http://fhir.example.com/Observation?name-value-date=PROCTIME$2001-02-02 # Combining Multiple Parameters -Search methods may take multiple parameters, and these parameters may (or may not) be optional. To add a second required parameter, annotate the parameter with [@RequiredParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html). To add an optional parameter (which will be passed in as `null` if no value is supplied), annotate the method with [@OptionalParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html). +Search methods may take multiple parameters, and these parameters may (or may not) be optional. To add a second required parameter, annotate the parameter with [@RequiredParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html). To add an optional parameter (which will be passed in as `null` if no value is supplied), annotate the method with [@OptionalParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html). -You may annotate a method with any combination of as many [@RequiredParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) and as many [@OptionalParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html) parameters as you want. It is valid to have only [@RequiredParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) parameters, or only [@OptionalParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html) parameters, or any combination of the two. +You may annotate a method with any combination of as many [@RequiredParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) and as many [@OptionalParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html) parameters as you want. It is valid to have only [@RequiredParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/RequiredParam.html) parameters, or only [@OptionalParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html) parameters, or any combination of the two. -If you wish to create a server that can accept any combination of a large number of parameters, (this is how the various reference servers behave, as well as the [Public HAPI Test Server](http://hapi.fhir.org)). The easiest way to accomplish this is to simply create one method with all allowable parameters, each annotated as [@OptionalParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html). +If you wish to create a server that can accept any combination of a large number of parameters, (this is how the various reference servers behave, as well as the [Public HAPI Test Server](http://hapi.fhir.org)). The easiest way to accomplish this is to simply create one method with all allowable parameters, each annotated as [@OptionalParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/OptionalParam.html). On the other hand, if you have specific combinations of parameters you wish to support (a common scenario if you are building FHIR on top of existing data sources and only have certain indexes you can use) you could create multiple search methods, each with specific required and optional parameters matching the database indexes. @@ -235,9 +246,9 @@ It is worth noting that according to the FHIR specification, you can have an AND ## OR Relationship Query Parameters -To accept a composite parameter, use a parameter type which implements the [IQueryParameterOr](/apidocs/hapi-fhir-base/ca/uhn/fhir/model/api/IQueryParameterOr.html) interface. +To accept a composite parameter, use a parameter type which implements the [IQueryParameterOr](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/model/api/IQueryParameterOr.html) interface. -Each parameter type ([StringParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringParam.html), [TokenParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenParam.html), etc.) has a corresponding parameter which accepts an ***OR*** list of parameters. These types are called "[type]OrListParam", for example: [StringOrListParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringOrListParam.html) and [TokenOrListParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenOrListParam.html). +Each parameter type ([StringParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringParam.html), [TokenParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenParam.html), etc.) has a corresponding parameter which accepts an ***OR*** list of parameters. These types are called "[type]OrListParam", for example: [StringOrListParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringOrListParam.html) and [TokenOrListParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/TokenOrListParam.html). The following example shows a search for Observation by name, where a list of names may be passed in (and the expectation is that the server will return Observations that match any of these names): @@ -253,7 +264,7 @@ http://fhir.example.com/Observation?name=urn:fakenames|123,urn:fakenames|456 ## AND Relationship Query Parameters -To accept a composite parameter, use a parameter type which implements the [IQueryParameterAnd](/apidocs/hapi-fhir-base/ca/uhn/fhir/model/api/IQueryParameterAnd.html) interface (which in turn encapsulates the corresponding IQueryParameterOr types). +To accept a composite parameter, use a parameter type which implements the [IQueryParameterAnd](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/model/api/IQueryParameterAnd.html) interface (which in turn encapsulates the corresponding IQueryParameterOr types). An example follows which shows a search for Patients by address, where multiple string lists may be supplied by the client. For example, the client might request that the address match `("Montreal" OR "Sherbrooke") AND ("Quebec" OR "QC")` using the following query: @@ -261,7 +272,7 @@ An example follows which shows a search for Patients by address, where multiple http://fhir.example.com/Patient?address=Montreal,Sherbrooke&address=Quebec,QC ``` -The following code shows how to receive this parameter using a [StringAndListParameter](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringAndListParam.html), which can handle an AND list of multiple OR lists of strings. +The following code shows how to receive this parameter using a [StringAndListParameter](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/StringAndListParam.html), which can handle an AND list of multiple OR lists of strings. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|searchMultipleAnd}} @@ -272,7 +283,7 @@ in very specific cases where a composite parameter has been specifically defined # AND Relationship Query Parameters for Dates -Dates are a special case, since it is a fairly common scenario to want to match a date range (which is really just an AND query on two qualified date parameters). See the section on [date ranges](#DATE_RANGES) for an example of a [DateRangeParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html). +Dates are a special case, since it is a fairly common scenario to want to match a date range (which is really just an AND query on two qualified date parameters). See the section on [date ranges](#DATE_RANGES) for an example of a [DateRangeParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/param/DateRangeParam.html). # Resource Includes (_include) @@ -298,7 +309,7 @@ It is also possible to use a String type for the include parameter, which is mor # Reverse Resource Includes (_revinclude) -To add support for reverse includes (via the `_revinclude` parameter), use the same format as with the `_include` parameter (shown above) but add `reverse=true` to the [@IncludeParam](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IncludeParam.html) annotation, as shown below. +To add support for reverse includes (via the `_revinclude` parameter), use the same format as with the `_include` parameter (shown above) but add `reverse=true` to the [@IncludeParam](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/IncludeParam.html) annotation, as shown below. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|revInclude}} @@ -326,7 +337,7 @@ FHIR supports [sorting](http://www.hl7.org/implement/standards/fhir/search.html# According to the specification, sorting is requested by the client using a search param as the sort key. For example, when searching Patient resources, a sort key of "given" requests the "given" search param as the sort key. That param maps to the values in the field "Patient.name.given". -Sort specifications can be passed into handler methods by adding a parameter of type [SortSpec](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/SortSpec.html), which has been annotated with the [@Sort](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Sort.html) annotation, as shown in the following example: +Sort specifications can be passed into handler methods by adding a parameter of type [SortSpec](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/api/SortSpec.html), which has been annotated with the [@Sort](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Sort.html) annotation, as shown in the following example: ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|sort}} @@ -340,7 +351,7 @@ http://fhir.example.com/Patient?_identifier=urn:foo|123&_sort=given # Adding Descriptions -It is also possible to annotate search methods and/or parameters with the [@Description](/apidocs/hapi-fhir-base/ca/uhn/fhir/rest/annotation/Description.html) annotation. This annotation allows you to add a description of the method and the individual parameters. These descriptions will be placed in the server's conformance statement, which can be helpful to anyone who is developing software against your server. +It is also possible to annotate search methods and/or parameters with the [@Description](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/model/api/annotation/Description.html) annotation. This annotation allows you to add a description of the method and the individual parameters. These descriptions will be placed in the server's conformance statement, which can be helpful to anyone who is developing software against your server. ```java {{snippet:classpath:/ca/uhn/hapi/fhir/docs/RestfulPatientResourceProviderMore.java|searchWithDocs}} diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/server_types.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/server_types.md index 5c1a3411639..049d75c579f 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/server_types.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/server_types.md @@ -38,4 +38,4 @@ To get started with the JPA Server, jump to [JPA Server Introduction](/docs/serv For users in an environment where existing services using JAX-RS have been created, it is often desirable to use JAX-RS for FHIR servers as well. HAPI FHIR provides a JAX-RS FHIR server implementation for this purpose. -To get started with the JAX-RS FHIR Server, jump to [JAX-RS FHIR Server Introduction](/docs/server_jaxrs/introduction.html). +To get started with the JAX-RS FHIR Server, jump to [JAX-RS FHIR Server Introduction](/docs/server_plain/jax_rs.html). diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/web_testpage_overlay.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/web_testpage_overlay.md new file mode 100644 index 00000000000..b66e3fac35d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/server_plain/web_testpage_overlay.md @@ -0,0 +1,112 @@ +# Web Testpage Overlay + +HAPI FHIR includes a web UI that can be used to test your server implementation. This UI is the same UI used on the [http://hapi.fhir.org](http://hapi.fhir.org) public HAPI FHIR test server. + +The Web Testpage Overlay is a [Maven WAR Overlay](http://maven.apache.org/plugins/maven-war-plugin/overlays.html) project, +meaning that you create your own WAR project (which you would likely be doing anyway +to create your server) and the overlay drops a number of files into your project. You can then selectively customize the system by replacing the built-in overlay files. + +# Adding the Overlay + +These instructions assume that you have an exsiting web project which uses Maven to build. The POM.xml should have a "packaging" type of "war". + +Adding the overlay to your project is relatively simple. First, add the "hapi-fhir-testpage-overlay" dependency to the dependencies section of your POM.xml file. + +```xml + + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + ${project.version} + war + provided + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + ${project.version} + classes + provided + + +``` + +Then, add the following WAR plugin to the plugins section of your POM.xml + +```xml + + + + + org.apache.maven.plugins + maven-war-plugin + + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + + + + + + +``` + +Then, create a Java source file called `FhirTesterConfig.java` and copy in the following contents: + + + + + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/FhirTesterConfig.java|file}} +``` + +Note that the URL in the file above must be customized to point to the FHIR endpoint your server will be deployed to. For example, if you are naming your project "myfhir-1.0.war" and your endpoint in the WAR is deployed to "/fhirbase/*" then you should put a URL similar to http://localhost:8080/myfhir-1.0/fhirbase + +Next, create the following directory in your project if it doesn't already exist: + +`src/main/webapp/WEB-INF
` + +In this directory you should open your `web.xml` file, or create it if it doesn't exist. This file is required in order to deploy to a servlet container and you should create it if it does not already exist. Place the following contents in that file, adjusting the package on the FhirTesterConfig to match the actual package in which you placed this file. + +```xml + + spring + org.springframework.web.servlet.DispatcherServlet + + contextClass + org.springframework.web.context.support.AnnotationConfigWebApplicationContext + + + contextConfigLocation + ca.uhn.example.config.FhirTesterConfig + + 2 + + + spring + /tester/* + +``` + +# Customizing the Overlay + +The most important customization required is to set the FHIR server base URL in the Java configuration file described above. + +Beyond this, the entire tester application is built from a number of [Thymeleaf](http://thymeleaf.org) template files, any of which can be replaced to create your own look and feel. All of the templates can be found in your built war (after running the Maven build), or in the target directory's staging area, in `WEB-INF/templates`. By placing a file with the same path/name in your `src/main/webapp/WEB-INF/templates` directory you can replace the built in template with your own file. + +# A Complete Example + +The [hapi-fhir-jpaserver-starter](https://github.com/hapifhir/hapi-fhir-jpaserver-starter) project contains a complete working example of the FHIR Tester as a part of its configuration. You may +wish to browse its source to see how this works. The example in that project includes an overlay file that overrides some of the basic branding in the base project as well. + +# Authentication + +The testing UI uses its own client to talk to your FHIR server. In other words, there are no special "hooks" which the tested uses to retrieve data from your server, it acts as an HTTP client just like any other client. + +This does mean that if your server has any authorization requirements, you will need to configure the tester UI to meet those requirements. For example, if your server has been configured to require a HTTP Basic Auth header (e.g. Authorization: Basic VVNFUjpQQVNT) you need to configure the tester UI to send those credentials across when it is acting as a FHIR client. + +This is done by providing your own implementation of the `ITestingUiClientFactory` interface. This interface takes in some details about the incoming request and produces a client. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/tools/hapi_fhir_cli.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/tools/hapi_fhir_cli.md index af55b2ca55b..c13c723a81c 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/tools/hapi_fhir_cli.md +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/tools/hapi_fhir_cli.md @@ -82,6 +82,6 @@ Note that the path and exact filename of the terminology files will likely need # Migrate Database -The `migrate-database` command may be used to Migrate a database schema when upgrading a HAPI FHIR JPA project from one version of HAPI FHIR to another version. +The `migrate-database` command may be used to Migrate a database schema when upgrading a [HAPI FHIR JPA](/docs/server_jpa/introduction.html) project from one version of HAPI FHIR to another version. -See Upgrading HAPI FHIR JPA for information on how to use this command. +See [Upgrading HAPI FHIR JPA](/docs/server_jpa/upgrading.html) for information on how to use this command. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/introduction.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/introduction.md new file mode 100644 index 00000000000..e10175c1b0a --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/introduction.md @@ -0,0 +1,14 @@ +# Validation Introduction + +This section contains details on several strategies for validating resources: + +* **[Parser Error Handler](./parser_error_handler.html)** validation is validation at runtime during the parsing of a resource. It can be used to catch input data that is impossible to fit into the HAPI data model. For example, it can be used to throw exceptions or display error messages if a resource being parsed contains elements for which there are no appropriate fields in a HAPI data structure. This is useful in order to ensure that no data is being lost during parsing, but is less comprehensive than resource validation against raw text data. + + Parser Validation is extremely fast and lightweight since it happens within the parser and has no dependencies to outside resources. + + +* **[Profile Validation](./profile_validator.html)** is validation of the raw or parsed resource against the official FHIR validation rules (ie. the official FHIR definitions, expressed as profile resources such as [StructureDefinition](http://hl7.org/fhir/structuredefinition.html) and [ValueSet](http://hl7.org/fhir/valueset.html). + + Profile Validation can also be used to validate resources against individual Implementation Guides which derive from the core specification (e.g. the [US Core](http://hl7.com/uscore) implementation guide). + +* **[Schema/Schematron Validation](./schema_validator.html)** is validation using XSD/SCH validation files provided by FHIR. This validator performs well but produces less usable error messages than Profile Validation. diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/parser_error_handler.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/parser_error_handler.md new file mode 100644 index 00000000000..cefb2c4c31f --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/parser_error_handler.md @@ -0,0 +1,28 @@ +# Parser Error Handler + +Parser Error Handler validation is enabled by calling [IParser#setParserErrorHandler(IParserErrorHandler)](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/parser/IParser.html#setParserErrorHandler(ca.uhn.fhir.parser.IParserErrorHandler)) on either the FhirContext or on individual parser instances. This method takes an [IParserErrorHandler](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/parser/IParserErrorHandler.html), which is a callback that will be invoked any time a parse issue is detected. + +There are two implementations of IParserErrorHandler that come built into HAPI FHIR. You can also supply your own implementation if you want. + +* [**LenientErrorHandler**](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/parser/LenientErrorHandler.html) logs any errors but does not abort parsing. By default this handler is used, and it logs errors at "warning" level. It can also be configured to silently ignore issues. LenientErrorHandler is the default. + +* [**StrictErrorHandler**](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/parser/StrictErrorHandler.html) throws a [DataFormatException](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/parser/DataFormatException.html) if any errors are detected. + +The following example shows how to configure a parser to use strict validation. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|parserValidation}} +``` + +You can also configure the error handler at the FhirContext level, which is useful for clients. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|clientValidation}} +``` + +FhirContext level validators can also be useful on servers. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|serverValidation}} +``` + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/profile_validator.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/profile_validator.md new file mode 100644 index 00000000000..5e71c9064eb --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/profile_validator.md @@ -0,0 +1,103 @@ +# Profile Validator + +# Validator Modules + +HAPI provides a built-in and configurable mechanism for validating resources. This mechanism is called the *Resource Validator*. + +The resource validator is an extendible and modular system, and you can configure it in a number of ways in order to get the specific type of validation you want to achieve. + +The validator can be manually invoked at any time by creating a validator and configuring it with one or more [IValidatorModule](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/validation/IValidatorModule.html) instances. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|validationIntro}} +``` + +
+ Note that in earlier releases of HAPI FHIR it was common to register different kinds of validator modules (such as [Schema/Schematron](./schema_validator.html)) because the FHIR Instance Validator module described below was not mature. This is no longer the case, and it is generally recommended to use the FHIR Instance Validator. +
+ +# FHIR Conformance Packages + +There are a few key concepts worth explaining before getting into how validation is performed in HAPI FHIR. + +Conformance Resources: + +* [StructureDefinition](http://hl7.org/fhir/structuredefinition.html) – Contains definitions of the valid fields in a given resource, including details about their datatypes, min/max cardinalities, valid values, and other rules about what content is valid and what is not. StructureDefinition resources are also used to express derivative profiles (e.g. a description of a constraint on a FHIR resource for a specfic purpose) as well as to describe extensions. + +* [CodeSystem](http://hl7.org/fhir/codesystem.html) – Contains definiitions of codes and vocabularies that can be used in FHIR resources, or even outside of FHIR resources. + +* [ValueSet](http://hl7.org/fhir/valueset.html) – Contains lists of codes drawn from one or more CodeSystems that are suitable for use in a specific field in a FHIR resource. + + +# FHIR Instance Validator + +HAPI has very complete support for validation against FHIR conformance resources. + +This functionality is proviided by the HAPI FHIR "reference validator", which is able +to check a resource for conformance to FHIR profiles. + +The FHIR instance validator is very powerful. It will use terminology services to validate codes, StructureDefinitions to validate semantics, and uses a customized XML/JSON parser in order to provide descriptive error messages. + +It is always worth considering the performance implications of using the Instance Validator at runtime in a production system. While efforts are made to keep the Instance Validator and its supporting infrastructure performant, the act of performing deep semantic validation is never going to be without some performance cost. + +The FHIR instance validator can be used to validate a resource against the +official structure definitions (produced by HL7) as well as against custom +definitions provided either by HL7 or by the user. + +# Running the Validator + +
+ Note on FHIR Versions: Many of the classes described on this page have + multiple versions, and you should use the version of the class the is appropriate + for the version of FHIR you are looking to validate. For example, the + examples and links below are using the + org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator class to + validate FHIR R4 resources, but you would want to use the class + org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator + if you need to validate DSTU3 content. +
+ +To execute the validator, you simply create an instance of [FhirInstanceValidator](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/r4/hapi/validation/FhirInstanceValidator.html) and register it to new validator, as shown in the example below. + +Note that the example below uses the official FHIR StructureDefintions and ValueSets +to validate the resource. It will not work unless you include the +**hapi-fhir-validation-resources-[version].jar** module/JAR on your classpath. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|instanceValidator}} +``` + +# Supplying Your Own Definitions + +The FhirInstanceValidator relies on an implementation of an interface called [IValidationSupport](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/ctx/IValidationSupport.html) interface to load StructureDefinitions, validate codes, etx. + +By default, an implementation of this interface called [DefaultProfileValidationSupport](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/ctx/DefaultProfileValidationSupport.html) is used. This implementation simply uses the built-in official FHIR definitions to validate against (and in many cases, this is good enough). + +However, if you have needs beyond simply validating against the core FHIR specification, you may wish to use something more. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|validateSupplyProfiles}} +``` + +# Buiilt-In Validation Support Classes + +There are a several implementations of the [IValidationSupport](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/ctx/IValidationSupport.html) interface built into HAPI FHIR that can be used, typically in a chain. + +* [**DefaultProfileValidationSupport**](/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/hapi/ctx/DefaultProfileValidationSupport.html) - Supplies the built-in FHIR core structure definitions, including both structures and vocabulary. + +* [**ValidationSupportChain**](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/r4/hapi/validation/ValidationSupportChain.html) - Can be used to chain multiple implementations together so that for every request, each support class instance in the chain is tried in sequence. + +* [**PrePopulatedValidationSupport**](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/r4/hapi/validation/PrePopulatedValidationSupport.html) - Contains a series of HashMaps that store loaded conformance resources in memory. Typically this is initialized at startup in order to add custom conformance resources into the chain. + +* [**PrePopulatedValidationSupport**](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/r4/hapi/validation/PrePopulatedValidationSupport.html) - Contains a series of HashMaps that store loaded conformance resources in memory. Typically this is initialized at startup in order to add custom conformance resources into the chain. + +* [**CachingValidationSupport**](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/r4/hapi/validation/CachingValidationSupport.html) - Caches results of calls to a wrapped service implementation for a period of time. This class can be a significant help in terms of performance if you are loading conformance resources or performing terminology operations from a database or disk. + +* [**SnapshotGeneratingValidationSupport**](/hapi-fhir/apidocs/hapi-fhir-validation/org/hl7/fhir/r4/hapi/validation/SnapshotGeneratingValidationSupport.html) - Generates StructureDefinition snapshots as needed. This should be added to your chain if you are working wiith differential StructueDefinitions that do not include the snapshot view. + + + + + + + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/schema_validator.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/schema_validator.md new file mode 100644 index 00000000000..ad4cc53a62e --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/docs/validation/schema_validator.md @@ -0,0 +1,28 @@ +# Schema / Schematron Validator + +FHIR resource definitions are distributed with a set of XML schema files (XSD) as well as a set of XML Schematron (SCH) files. These two sets of files are complimentary to each other, meaning that in order to claim compliance to the FHIR specification, your resources must validate against both sets. + +The two sets of files are included with HAPI, and it uses them to perform validation. + +# Preparation + +In order to use HAPI's Schematron support, a libaray called [Ph-Schematron](https://github.com/phax/ph-schematron) is used, so this library must be added to your classpath (or Maven POM file, Gradle file, etc.) + +Note that this library is specified as an optional dependency by HAPI FHIR so you need to explicitly include it if you want to use this functionality. + +# Validating a Resource + +To validate a resource instance, a new validator instance is requested from the FHIR Context. This validator is then applied against a specific resource instance, as shown in the example below. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|basicValidation}} +``` + +## Validating a Set of Files + +The following example shows how to load a set of resources from files on disk and validate each one. + +```java +{{snippet:classpath:/ca/uhn/hapi/fhir/docs/ValidatorExamples.java|validateFiles}} +``` + diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java index 6886f188b10..719a0ac209f 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/DaoConfig.java @@ -67,7 +67,8 @@ public class DaoConfig { *
  • message
  • * */ - private static final Set DEFAULT_BUNDLE_TYPES_ALLOWED_FOR_STORAGE = Collections.unmodifiableSet(new TreeSet<>(Sets.newHashSet( + @SuppressWarnings("WeakerAccess") + public static final Set DEFAULT_BUNDLE_TYPES_ALLOWED_FOR_STORAGE = Collections.unmodifiableSet(new TreeSet<>(Sets.newHashSet( Bundle.BundleType.COLLECTION.toCode(), Bundle.BundleType.DOCUMENT.toCode(), Bundle.BundleType.MESSAGE.toCode() diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java index 70656ae4531..835dd022033 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/entity/TermValueSetConceptView.java @@ -24,37 +24,42 @@ import org.hibernate.annotations.Immutable; import org.hibernate.annotations.Subselect; import javax.persistence.Column; +import javax.persistence.EmbeddedId; import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; import javax.persistence.Id; import java.io.Serializable; @Entity @Immutable @Subselect( - "SELECT CONCAT(vsc.PID, ' ', vscd.PID) AS PID, " + - " vsc.PID AS CONCEPT_PID, " + - " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " + - " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " + - " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " + - " vsc.CODEVAL AS CONCEPT_CODEVAL, " + - " vsc.DISPLAY AS CONCEPT_DISPLAY, " + - " vscd.PID AS DESIGNATION_PID, " + - " vscd.LANG AS DESIGNATION_LANG, " + - " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " + - " vscd.USE_CODE AS DESIGNATION_USE_CODE, " + - " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " + - " vscd.VAL AS DESIGNATION_VAL " + - "FROM TRM_VALUESET_CONCEPT vsc " + - " LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID" + /* + * Note about the CONCAT function below- We need a primary key (an @Id) column + * because hibernate won't allow the view the function without it, but + */ + "SELECT CONCAT(vsc.PID, CONCAT(' ', vscd.PID)) AS PID, " + + " vsc.PID AS CONCEPT_PID, " + + " vsc.VALUESET_PID AS CONCEPT_VALUESET_PID, " + + " vsc.VALUESET_ORDER AS CONCEPT_VALUESET_ORDER, " + + " vsc.SYSTEM_URL AS CONCEPT_SYSTEM_URL, " + + " vsc.CODEVAL AS CONCEPT_CODEVAL, " + + " vsc.DISPLAY AS CONCEPT_DISPLAY, " + + " vscd.PID AS DESIGNATION_PID, " + + " vscd.LANG AS DESIGNATION_LANG, " + + " vscd.USE_SYSTEM AS DESIGNATION_USE_SYSTEM, " + + " vscd.USE_CODE AS DESIGNATION_USE_CODE, " + + " vscd.USE_DISPLAY AS DESIGNATION_USE_DISPLAY, " + + " vscd.VAL AS DESIGNATION_VAL " + + "FROM TRM_VALUESET_CONCEPT vsc " + + "LEFT OUTER JOIN TRM_VALUESET_C_DESIGNATION vscd ON vsc.PID = vscd.VALUESET_CONCEPT_PID" ) public class TermValueSetConceptView implements Serializable { private static final long serialVersionUID = 1L; - private static final int MAX_LENGTH = 500; - @Id - @Column(name="PID", length = MAX_LENGTH) - private String myPid; + @Column(name="PID", length = 1000 /* length only needed to satisfy JpaEntityTest, it's not used*/) + private String id; // still set automatically @Column(name = "CONCEPT_PID") private Long myConceptPid; diff --git a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/ValueSetExpansionR4Test.java b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/ValueSetExpansionR4Test.java index 560a1116d37..cbca3b0e808 100644 --- a/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/ValueSetExpansionR4Test.java +++ b/hapi-fhir-jpaserver-base/src/test/java/ca/uhn/fhir/jpa/term/ValueSetExpansionR4Test.java @@ -120,6 +120,28 @@ public class ValueSetExpansionR4Test extends BaseTermR4Test { } @Test + public void testExpandTermValueSetAndChildren2() throws Exception { + myDaoConfig.setPreExpandValueSets(true); + + CodeSystem codeSystem = loadResource(myFhirCtx, CodeSystem.class, "/r4/CodeSystem-iar-chymh-cb-calculated-cap-10.xml"); + myCodeSystemDao.create(codeSystem); + + ValueSet valueSet = loadResource(myFhirCtx, ValueSet.class, "/r4/ValueSet-iar-chymh-cb-calculated-cap-10.xml"); + myValueSetDao.create(valueSet); + + + myTermSvc.preExpandDeferredValueSetsToTerminologyTables(); + + myCaptureQueriesListener.clear(); + + ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 0, 100); + ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet)); + + assertEquals(3, expandedValueSet.getExpansion().getContains().size()); + } + + + @Test public void testExpandExistingValueSetNotPreExpanded() throws Exception { loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST); diff --git a/hapi-fhir-jpaserver-base/src/test/resources/r4/CodeSystem-iar-chymh-cb-calculated-cap-10.xml b/hapi-fhir-jpaserver-base/src/test/resources/r4/CodeSystem-iar-chymh-cb-calculated-cap-10.xml new file mode 100644 index 00000000000..70944dc8b1a --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/resources/r4/CodeSystem-iar-chymh-cb-calculated-cap-10.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-jpaserver-base/src/test/resources/r4/ValueSet-iar-chymh-cb-calculated-cap-10.xml b/hapi-fhir-jpaserver-base/src/test/resources/r4/ValueSet-iar-chymh-cb-calculated-cap-10.xml new file mode 100644 index 00000000000..9fed2b964a4 --- /dev/null +++ b/hapi-fhir-jpaserver-base/src/test/resources/r4/ValueSet-iar-chymh-cb-calculated-cap-10.xml @@ -0,0 +1,34 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java index cffe2dbb64c..f05ec1beae4 100644 --- a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java +++ b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/taskdef/BaseTask.java @@ -24,6 +24,8 @@ import ca.uhn.fhir.jpa.migrate.DriverTypeEnum; import org.intellij.lang.annotations.Language; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.dao.DataAccessException; +import org.springframework.dao.DataIntegrityViolationException; import org.springframework.jdbc.core.JdbcTemplate; import org.springframework.transaction.support.TransactionTemplate; @@ -47,6 +49,7 @@ public abstract class BaseTask { private boolean myDryRun; private List myExecutedStatements = new ArrayList<>(); private boolean myNoColumnShrink; + private boolean myFailureAllowed; private final String myProductVersion; private final String mySchemaVersion; @@ -101,9 +104,19 @@ public abstract class BaseTask { if (isDryRun() == false) { Integer changes = getConnectionProperties().getTxTemplate().execute(t -> { JdbcTemplate jdbcTemplate = getConnectionProperties().newJdbcTemplate(); - int changesCount = jdbcTemplate.update(theSql, theArguments); + try { + int changesCount = jdbcTemplate.update(theSql, theArguments); logInfo(ourLog, "SQL \"{}\" returned {}", theSql, changesCount); - return changesCount; + return changesCount; + } catch (DataAccessException e) { + if (myFailureAllowed) { + ourLog.info("Task did not exit successfully, but task is allowed to fail"); + ourLog.debug("Error was: {}", e.getMessage(), e); + return 0; + } else { + throw e; + } + } }); myChangesCount += changes; @@ -144,6 +157,10 @@ public abstract class BaseTask { public abstract void execute() throws SQLException; + public void setFailureAllowed(boolean theFailureAllowed) { + myFailureAllowed = theFailureAllowed; + } + public String getFlywayVersion() { String releasePart = myProductVersion; if (releasePart.startsWith("V")) { diff --git a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java index 0c1190f5e50..48694005e01 100644 --- a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java +++ b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/HapiFhirJpaMigrationTasks.java @@ -61,13 +61,18 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks { protected void init410() { // 20190815 - present Builder version = forVersion(VersionEnum.V4_1_0); - version.onTable("HFJ_SPIDX_NUMBER").modifyColumn("20190920.1", "RES_ID").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); - version.onTable("HFJ_SPIDX_COORDS").modifyColumn("20190920.2", "RES_ID").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); - version.onTable("HFJ_SPIDX_TOKEN").modifyColumn("20190920.3", "RES_ID").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); - version.onTable("HFJ_SPIDX_STRING").modifyColumn("20190920.4", "RES_ID").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); - version.onTable("HFJ_SPIDX_DATE").modifyColumn("20190920.5", "RES_ID").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); - version.onTable("HFJ_SPIDX_QUANTITY").modifyColumn("20190920.6", "RES_ID").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); - version.onTable("HFJ_SPIDX_URI").modifyColumn("20190920.7", "RES_ID").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + /* + * Note: The following tasks are markes as failure allowed - This is because all we're + * doing is setting a not-null on a column that will never be null anyway. Setting not null + * fails on SQL Server because there is an index on this column... Which is dumb, but hey. + */ + version.onTable("HFJ_SPIDX_NUMBER").modifyColumn("20190920.1", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + version.onTable("HFJ_SPIDX_COORDS").modifyColumn("20190920.2", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + version.onTable("HFJ_SPIDX_TOKEN").modifyColumn("20190920.3", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + version.onTable("HFJ_SPIDX_STRING").modifyColumn("20190920.4", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + version.onTable("HFJ_SPIDX_DATE").modifyColumn("20190920.5", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + version.onTable("HFJ_SPIDX_QUANTITY").modifyColumn("20190920.6", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + version.onTable("HFJ_SPIDX_URI").modifyColumn("20190920.7", "RES_ID").nonNullable().failureAllowed().withType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); // HFJ_SEARCH version.onTable("HFJ_SEARCH").addColumn("20190921.1", "EXPIRY_OR_NULL").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.DATE_TIMESTAMP); diff --git a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java index 6b87e22d53e..42e0b2a9549 100644 --- a/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java +++ b/hapi-fhir-jpaserver-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/tasks/api/Builder.java @@ -196,7 +196,7 @@ public class Builder { /** * @param theOldName The old column name * @param theNewName The new column name - * @param isOkayIfNeitherColumnExists Setting this to true means that it's not an error if neither column exists + * @param isOkayIfNeitherColumnExists Setting this to true means that it's not an error if neither column exists * @param theDeleteTargetColumnFirstIfBothExist Setting this to true causes the migrator to be ok with the target column existing. It will make sure that there is no data in the column with the new name, then delete it if so in order to make room for the renamed column. If there is data it will still bomb out. */ public BuilderWithTableName renameColumn(String theVersion, String theOldName, String theNewName, boolean isOkayIfNeitherColumnExists, boolean theDeleteTargetColumnFirstIfBothExist) { @@ -279,6 +279,7 @@ public class Builder { public class BuilderModifyColumnWithNameAndNullable { private final String myVersion; private final boolean myNullable; + private boolean myFailureAllowed; public BuilderModifyColumnWithNameAndNullable(String theVersion, boolean theNullable) { myVersion = theVersion; @@ -308,8 +309,14 @@ public class Builder { } task.setNullable(myNullable); task.setColumnType(theColumnType); + task.setFailureAllowed(myFailureAllowed); addTask(task); } + + public BuilderModifyColumnWithNameAndNullable failureAllowed() { + myFailureAllowed = true; + return this; + } } } diff --git a/hapi-fhir-jpaserver-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTest.java b/hapi-fhir-jpaserver-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTest.java index 7593938d305..559af8ec09a 100644 --- a/hapi-fhir-jpaserver-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTest.java +++ b/hapi-fhir-jpaserver-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/taskdef/ModifyColumnTest.java @@ -1,7 +1,9 @@ package ca.uhn.fhir.jpa.migrate.taskdef; import ca.uhn.fhir.jpa.migrate.JdbcUtils; +import org.flywaydb.core.internal.command.DbMigrate; import org.junit.Test; +import org.springframework.dao.DataIntegrityViolationException; import java.sql.SQLException; @@ -213,4 +215,43 @@ public class ModifyColumnTest extends BaseTest { assertThat(JdbcUtils.getColumnNames(getConnectionProperties(), "SOMETABLE"), containsInAnyOrder("PID", "TEXTCOL")); } + @Test + public void testFailureAllowed() throws SQLException { + executeSql("create table SOMETABLE (PID bigint, TEXTCOL varchar(255))"); + executeSql("insert into SOMETABLE (TEXTCOL) values ('HELLO')"); + + ModifyColumnTask task = new ModifyColumnTask("1", "1"); + task.setTableName("SOMETABLE"); + task.setColumnName("TEXTCOL"); + task.setColumnType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + task.setNullable(true); + task.setFailureAllowed(true); + getMigrator().addTask(task); + + getMigrator().migrate(); + assertEquals(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, JdbcUtils.getColumnType(getConnectionProperties(), "SOMETABLE", "TEXTCOL").getColumnTypeEnum()); + + } + + @Test + public void testFailureNotAllowed() throws SQLException { + executeSql("create table SOMETABLE (PID bigint, TEXTCOL varchar(255))"); + executeSql("insert into SOMETABLE (TEXTCOL) values ('HELLO')"); + + ModifyColumnTask task = new ModifyColumnTask("1", "1"); + task.setTableName("SOMETABLE"); + task.setColumnName("TEXTCOL"); + task.setColumnType(BaseTableColumnTypeTask.ColumnTypeEnum.LONG); + task.setNullable(true); + getMigrator().addTask(task); + + try { + getMigrator().migrate(); + fail(); + } catch (DbMigrate.FlywayMigrateException e) { + // expected + } + + } + } diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index 8fdae251c75..f92fd6871e2 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -74,6 +74,16 @@ Saxon-HE true + + xpp3 + xpp3 + true + + + org.fhir + ucum + true + @@ -303,6 +313,16 @@ + + org.apache.maven.plugins + maven-javadoc-plugin + + true + + ca.uhn.hapi.fhir:org.hl7.fhir.dstu2 + + +
    diff --git a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/SnapshotGeneratingValidationSupport.java b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/SnapshotGeneratingValidationSupport.java index af1c8469ce7..189a9d2e38b 100644 --- a/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/SnapshotGeneratingValidationSupport.java +++ b/hapi-fhir-validation/src/main/java/org/hl7/fhir/r4/hapi/validation/SnapshotGeneratingValidationSupport.java @@ -21,7 +21,7 @@ import java.util.List; /** * Simple validation support module that handles profile snapshot generation. This is - * separate from other funcrtions since it needs a link to a validation support + * separate from other functions since it needs a link to a validation support * module itself, and it is useful to be able to pass a chain in. */ public class SnapshotGeneratingValidationSupport implements IValidationSupport { diff --git a/src/changes/changes.xml b/src/changes/changes.xml index c4510b4d816..d9c96b0bf4e 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -46,6 +46,10 @@ database migration tasks that have already been applied. The hapi-fhir-cli migrate tool has been changed to use flyway. Learn more about flyway here: https://flywaydb.org/. + + ValueSet Precalculation sometimes failed on Oracle DBs due to an invalid SQL function. This + has been corrected. + diff --git a/src/site/xdoc/doc_resource_references.xml b/src/site/xdoc/doc_resource_references.xml index fc29addb9c8..6e4b3f5e220 100644 --- a/src/site/xdoc/doc_resource_references.xml +++ b/src/site/xdoc/doc_resource_references.xml @@ -1,256 +1,258 @@ - - - - - Resource References - James Agnew - - - - - -
    - -

    - Resource references are a key part of the HAPI FHIR model, - since almost any resource will have references to other resources - within it. -

    - -

    - The ResourceReferenceDt - type is the datatype for references. This datatype has a number of properties which help - make working with FHIR simple. -

    - -

    - The getReference() method returns an IdDt instance which contains the identity of the - resource being referenced. This is the item which is most commonly populated when - interacting with FHIR. For example, consider the following Patient resource, which - contains a reference to an Organization resource: -

    - - - - - - - - -]]> - -

    - Given a Patient resource obtained by invoking a client operation, a call to - IdDt ref = patient.getManagingOrganization().getReference(); - returns an instance of IdDt which contains the "Organization/112" reference. -

    - -

    - ResourceReferenceDt also has a field for storing actual resource instances however, - and this can be very useful. -

    - - -
    - -
    - -

    - In client code, if a resource reference refers to a resource which was received as a - part of the same response, getResource() will be populated with the - actual resource. This can happen because either the resource was received as a - contained resource, or the resource was received as a separate resource in a bundle. -

    - -
    - -
    - -

    - In server code, you will often want to return a resource which contains - a link to another resource. Generally these "linked" resources are - not actually included in the response, but rather a link to the - resource is included and the client may request that resource directly - (by ID) if it is needed. -

    - -

    - The following example shows a Patient resource being created which will have a - link to its managing organization when encoded from a server: -

    - - - - -

    - Your server code may also wish to add additional resource to a bundle - being returned (e.g. because of an _include directive in the client's request). -

    - -

    - To do this, you can implement your server method to simply return - List<IResource> and then simply add your extra resources to - the list. Another technique however, is to populate the reference as shown - in the example below, but ensure that the referenced resource has an ID set. -

    - -

    - In the following example, the Organization resource has an ID set, so it will not - be contained but will rather appear as a distinct entry in any returned - bundles. Both resources are added to a bundle, which will then have - two entries: -

    - - - - - -

    - This will give the following output: -

    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]]> - -
    - - - -

    - On the other hand, if the linked resource - does not have an ID set, the linked resource will - be included in the returned bundle as a "contained" resource. In this - case, HAPI itself will define a local reference ID (e.g. "#1"). -

    - - -

    - This will give the following output: -

    - - - - - - - - - - - - - -]]> - -
    - -

    - Note that you may also "contain" resources manually in your own code if you - prefer. The following example show how to do this: -

    - - - - - - - -
    - -
    - -

    - By default, HAPI will strip resource versions from references between resources. - For example, if you set a reference to Patient.managingOrganization - to the value Patient/123/_history/2, HAPI will encode this - reference as Patient/123. -

    -

    - This is because in most circumstances, references between resources should be - versionless (e.g. the reference just points to the latest version, whatever - version that might be). -

    -

    - There are valid circumstances however for wanting versioned references. If you - need HAPI to emit versionned references, you have a few options: -

    -

    - You can force the parser to never strip versions: -

    - - - - -

    - You can also disable this behaviour entirely on the context (so that it - will apply to all parsers): -

    - - - - -

    - You can also configure HAPI to not strip versions only on certain fields. This - is desirable if you want versionless references in most places but need them - in some places: -

    - - - - -
    - - -
    + + + + + + + Resource References + James Agnew + + + + + +
    + +

    + Resource references are a key part of the HAPI FHIR model, + since almost any resource will have references to other resources + within it. +

    + +

    + The ResourceReferenceDt + type is the datatype for references. This datatype has a number of properties which help + make working with FHIR simple. +

    + +

    + The getReference() method returns an IdDt instance which contains the identity of the + resource being referenced. This is the item which is most commonly populated when + interacting with FHIR. For example, consider the following Patient resource, which + contains a reference to an Organization resource: +

    + + + + + + + + +]]> + +

    + Given a Patient resource obtained by invoking a client operation, a call to + IdDt ref = patient.getManagingOrganization().getReference(); + returns an instance of IdDt which contains the "Organization/112" reference. +

    + +

    + ResourceReferenceDt also has a field for storing actual resource instances however, + and this can be very useful. +

    + + +
    + +
    + +

    + In client code, if a resource reference refers to a resource which was received as a + part of the same response, getResource() will be populated with the + actual resource. This can happen because either the resource was received as a + contained resource, or the resource was received as a separate resource in a bundle. +

    + +
    + +
    + +

    + In server code, you will often want to return a resource which contains + a link to another resource. Generally these "linked" resources are + not actually included in the response, but rather a link to the + resource is included and the client may request that resource directly + (by ID) if it is needed. +

    + +

    + The following example shows a Patient resource being created which will have a + link to its managing organization when encoded from a server: +

    + + + + +

    + Your server code may also wish to add additional resource to a bundle + being returned (e.g. because of an _include directive in the client's request). +

    + +

    + To do this, you can implement your server method to simply return + List<IResource> and then simply add your extra resources to + the list. Another technique however, is to populate the reference as shown + in the example below, but ensure that the referenced resource has an ID set. +

    + +

    + In the following example, the Organization resource has an ID set, so it will not + be contained but will rather appear as a distinct entry in any returned + bundles. Both resources are added to a bundle, which will then have + two entries: +

    + + + + + +

    + This will give the following output: +

    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> + +
    + + + +

    + On the other hand, if the linked resource + does not have an ID set, the linked resource will + be included in the returned bundle as a "contained" resource. In this + case, HAPI itself will define a local reference ID (e.g. "#1"). +

    + + +

    + This will give the following output: +

    + + + + + + + + + + + + + +]]> + +
    + +

    + Note that you may also "contain" resources manually in your own code if you + prefer. The following example show how to do this: +

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

    + By default, HAPI will strip resource versions from references between resources. + For example, if you set a reference to Patient.managingOrganization + to the value Patient/123/_history/2, HAPI will encode this + reference as Patient/123. +

    +

    + This is because in most circumstances, references between resources should be + versionless (e.g. the reference just points to the latest version, whatever + version that might be). +

    +

    + There are valid circumstances however for wanting versioned references. If you + need HAPI to emit versionned references, you have a few options: +

    +

    + You can force the parser to never strip versions: +

    + + + + +

    + You can also disable this behaviour entirely on the context (so that it + will apply to all parsers): +

    + + + + +

    + You can also configure HAPI to not strip versions only on certain fields. This + is desirable if you want versionless references in most places but need them + in some places: +

    + + + + +
    + + +
    diff --git a/src/site/xdoc/doc_rest_client.xml b/src/site/xdoc/doc_rest_client.xml index d5b7127726a..a55ee31fba8 100644 --- a/src/site/xdoc/doc_rest_client.xml +++ b/src/site/xdoc/doc_rest_client.xml @@ -2,6 +2,8 @@ + + RESTful Client James Agnew diff --git a/src/site/xdoc/doc_rest_client_annotation.xml b/src/site/xdoc/doc_rest_client_annotation.xml index 1c422c96598..db1582d7bf4 100644 --- a/src/site/xdoc/doc_rest_client_annotation.xml +++ b/src/site/xdoc/doc_rest_client_annotation.xml @@ -1,156 +1,158 @@ - - - - - Annotation Client - James Agnew - - - - -
    - -

    - HAPI also provides a second style of client, called the annotation-driven client. - If you are using the - Fluent/Generic Client - do not need to read this page. -

    - -

    - The design of the annotation-driven client - is intended to be similar to that of - JAX-WS, so users of that - specification should be comfortable with - this one. It uses a user-defined interface containing special - annotated methods which HAPI binds to calls against a server. -

    - -

    - The annotation-driven client is particularly useful if you have a server that - exposes a set of specific operations (search parameter combinations, named queries, etc.) - and you want to let developers have a stongly/statically typed interface to that - server. -

    -

    - There is no difference in terms of capability between the two styles of - client. There is simply a difference in programming style and complexity. It - is probably safe to say that the generic client is easier to use and leads to - more readable code, at the expense of not giving any visibility into the - specific capabilities of the server you are interacting with. -

    - - - -

    - The first step in creating an annotation-driven client is to define a - restful client interface. -

    - -

    - A restful client interface class must extend the - IRestfulClient - interface, - and will contain one or more methods which have been - annotated with special annotations indicating which RESTful - operation - that method supports. Below is a simple example of a - resource provider - which supports the - read - operation (i.e. retrieve a single resource by ID) as well as the - search - operation (i.e. find any resources matching a given criteria) for a - specific - search criteria. -

    - -

    - You may notice that this interface looks a lot like the Resource - Provider - which is defined for use by the RESTful server. In fact, it - supports all - of the same annotations and is essentially identical, - other than the - fact that for a client you must use an interface but for a server you - must use a concrete class with method implementations. -

    - - - - - - -

    - You will probably want to add more methods - to your client interface. - See - RESTful Operations - for - lots more examples of how to add methods for various operations. -

    - -
    - - - -

    - Once your client interface is created, all that is left is to - create a FhirContext and instantiate the client and you are - ready to - start using it. -

    - - - - - - -
    - - - -

    - Restful client interfaces that you create will also extend - the interface - IRestfulClient, - which comes with some helpful methods for configuring the way that - the client will interact with the server. -

    -

    - The following snippet shows how to configure the cliet to explicitly - request JSON or XML responses, and how to request "pretty printed" responses - on servers that support this (HAPI based servers currently). -

    - - - - - - -
    - - - -

    - The following is a complete example showing a RESTful client - using - HAPI FHIR. -

    - - - - - - -
    - -
    - - - -
    + + + + + + + Annotation Client + James Agnew + + + + +
    + +

    + HAPI also provides a second style of client, called the annotation-driven client. + If you are using the + Fluent/Generic Client + do not need to read this page. +

    + +

    + The design of the annotation-driven client + is intended to be similar to that of + JAX-WS, so users of that + specification should be comfortable with + this one. It uses a user-defined interface containing special + annotated methods which HAPI binds to calls against a server. +

    + +

    + The annotation-driven client is particularly useful if you have a server that + exposes a set of specific operations (search parameter combinations, named queries, etc.) + and you want to let developers have a stongly/statically typed interface to that + server. +

    +

    + There is no difference in terms of capability between the two styles of + client. There is simply a difference in programming style and complexity. It + is probably safe to say that the generic client is easier to use and leads to + more readable code, at the expense of not giving any visibility into the + specific capabilities of the server you are interacting with. +

    + + + +

    + The first step in creating an annotation-driven client is to define a + restful client interface. +

    + +

    + A restful client interface class must extend the + IRestfulClient + interface, + and will contain one or more methods which have been + annotated with special annotations indicating which RESTful + operation + that method supports. Below is a simple example of a + resource provider + which supports the + read + operation (i.e. retrieve a single resource by ID) as well as the + search + operation (i.e. find any resources matching a given criteria) for a + specific + search criteria. +

    + +

    + You may notice that this interface looks a lot like the Resource + Provider + which is defined for use by the RESTful server. In fact, it + supports all + of the same annotations and is essentially identical, + other than the + fact that for a client you must use an interface but for a server you + must use a concrete class with method implementations. +

    + + + + + + +

    + You will probably want to add more methods + to your client interface. + See + RESTful Operations + for + lots more examples of how to add methods for various operations. +

    + +
    + + + +

    + Once your client interface is created, all that is left is to + create a FhirContext and instantiate the client and you are + ready to + start using it. +

    + + + + + + +
    + + + +

    + Restful client interfaces that you create will also extend + the interface + IRestfulClient, + which comes with some helpful methods for configuring the way that + the client will interact with the server. +

    +

    + The following snippet shows how to configure the cliet to explicitly + request JSON or XML responses, and how to request "pretty printed" responses + on servers that support this (HAPI based servers currently). +

    + + + + + + +
    + + + +

    + The following is a complete example showing a RESTful client + using + HAPI FHIR. +

    + + + + + + +
    + +
    + + + +
    diff --git a/src/site/xdoc/doc_rest_client_examples.xml b/src/site/xdoc/doc_rest_client_examples.xml index 91bf9665bb9..e3bc069e57d 100644 --- a/src/site/xdoc/doc_rest_client_examples.xml +++ b/src/site/xdoc/doc_rest_client_examples.xml @@ -1,136 +1,138 @@ - - - - - RESTful Client Examples - James Agnew - - - - -
    - -

    - This page contains examples of how to use the client to perform - complete tasks. If you have an example you could contribute, we'd - love to hear from you! -

    - - - -

    - The following example shows how to post a transaction with two resources, - where one resource contains a reference to the other. A temporary ID (a UUID) - is used as an ID to refer to, and this ID will be replaced by the server by - a permanent ID. -

    - - - - - - -

    - This code creates the following transaction bundle:
    - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -]]> -

    - -

    - The server responds with the following response. Note that - the ID of the already existing patient is returned, and the - ID of the newly created Observation is too.
    - - - - - - - - - - - - - - - - - - - - - - - - -]]> -

    - -
    - - - -

    - This example - shows how to load all pages of a bundle by fetching each page one-after-the-other and then - joining the resuts. -

    - -
    - -
    - - - -
    + + + + + RESTful Client Examples + James Agnew + + + + + + +
    + +

    + This page contains examples of how to use the client to perform + complete tasks. If you have an example you could contribute, we'd + love to hear from you! +

    + + + +

    + The following example shows how to post a transaction with two resources, + where one resource contains a reference to the other. A temporary ID (a UUID) + is used as an ID to refer to, and this ID will be replaced by the server by + a permanent ID. +

    + + + + + + +

    + This code creates the following transaction bundle:
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +]]> +

    + +

    + The server responds with the following response. Note that + the ID of the already existing patient is returned, and the + ID of the newly created Observation is too.
    + + + + + + + + + + + + + + + + + + + + + + + + +]]> +

    + +
    + + + +

    + This example + shows how to load all pages of a bundle by fetching each page one-after-the-other and then + joining the resuts. +

    + +
    + +
    + + + +
    diff --git a/src/site/xdoc/doc_rest_client_http_config.xml.vm b/src/site/xdoc/doc_rest_client_http_config.xml.vm index 25965bd4e3f..b34df1be3ac 100644 --- a/src/site/xdoc/doc_rest_client_http_config.xml.vm +++ b/src/site/xdoc/doc_rest_client_http_config.xml.vm @@ -1,190 +1,192 @@ - - - - - Client Configuration - James Agnew - - - -
    - -

    - This page outlines ways that the client can be configured - for specific behaviour. -

    - -
    - - - -
    - - -

    - By default, the client will query the server before the very first - operation to download the server's conformance/metadata statement - and verify that the server is appropriate for the given client. - This check is only done once per server endpoint for a given - FhirContext. -

    -

    - This check is useful to prevent bugs or unexpected behaviour - when talking to servers. It may introduce unneccesary overhead - however in circumstances where the client and server are known - to be compatible. The following example shows how to disable this - check. -

    - - - - -
    - - - -

    - By default, HAPI will scan each model type it encounters - as soon as it encounters it. This scan includes a check for - all fields within the type, and makes use of reflection to do this. -

    -

    - While this process is not particularly significant on reasonably - performant machines (one benchmark showed that this takes - roughly 0.6 seconds to scan all types on one developer workstation), on some devices - (e.g. Android phones where every millisecond counts) - it may be desirable to defer this scan. -

    -

    - When the scan is deferred, objects will only be scanned when they - are actually accessed, meaning that only types that are - actually used in an application get scanned. -

    -

    - The following example shows how to defer model scanning: -

    - - - - - -
    - -
    - -
    - -

    - RESTful clients (both Generic and Annotation-Driven) use - Apache HTTP Client - as a provider by default (except on Android, where - OkHttp - is the default). -

    -

    - The Apache HTTP Client is very powerful and extremely - flexible, - but can be confusing at first to configure, because of the low-level - approach that - the library uses. -

    - -

    - In many cases, the default configuration should suffice. HAPI FHIR - also encapsulates some of the more common configuration settings you - might want to use (socket timesouts, proxy settings, etc.) so that these - can be configured through HAPI's API without needing to understand the - underlying HTTP Client library. -

    - -

    - This configuration is provided by accessing the - IRestfulClientFactory - class from the FhirContext. -

    - -

    - Note that individual requests and responses - can be tweaked using - Client Interceptors. - This approach is generally useful for configuration involving - tweaking the HTTP request/response, such as adding authorization headers - or logging. -

    - - -

    - The following example shows how to configure low level - socket timeouts for client operations. -

    - - - - -
    - - - -

    - The following example shows how to configure the use of an HTTP - proxy in the client. -

    - - - - - - -
    - - - -

    - As of HAPI FHIR 2.0, an alternate client implementation - is available. This client replaces the low-level - Apache HttpClient implementation with the - Square - OkHttp - library. -

    -

    - Changing HTTP implementations should be mostly - transparent (it has no effect on the actual FHIR - semantics which are transmitted over the wire) but - might be useful if you have an application that - uses OkHttp in other parts of the application and - has specific configuration for that library. -

    -

    - Note that as of HAPI FHIR 2.1, OkHttp is the default - provider on Android, and will be used without any - configuration being required. This is done because - HttpClient is deprecated on Android and has caused - problems in the past. -

    -

    - To use OkHttp, first add the library as a dependency to your project POM: -

    - - ca.uhn.hapi.fhir - hapi-fhir-client-okhttp - ${hapi_stable_version} -]]> - -

    - Then, set the client factory to use OkHttp. -

    - - - - -
    -
    - - - -
    + + + + + + + Client Configuration + James Agnew + + + +
    + +

    + This page outlines ways that the client can be configured + for specific behaviour. +

    + +
    + + + +
    + + +

    + By default, the client will query the server before the very first + operation to download the server's conformance/metadata statement + and verify that the server is appropriate for the given client. + This check is only done once per server endpoint for a given + FhirContext. +

    +

    + This check is useful to prevent bugs or unexpected behaviour + when talking to servers. It may introduce unneccesary overhead + however in circumstances where the client and server are known + to be compatible. The following example shows how to disable this + check. +

    + + + + +
    + + + +

    + By default, HAPI will scan each model type it encounters + as soon as it encounters it. This scan includes a check for + all fields within the type, and makes use of reflection to do this. +

    +

    + While this process is not particularly significant on reasonably + performant machines (one benchmark showed that this takes + roughly 0.6 seconds to scan all types on one developer workstation), on some devices + (e.g. Android phones where every millisecond counts) + it may be desirable to defer this scan. +

    +

    + When the scan is deferred, objects will only be scanned when they + are actually accessed, meaning that only types that are + actually used in an application get scanned. +

    +

    + The following example shows how to defer model scanning: +

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

    + RESTful clients (both Generic and Annotation-Driven) use + Apache HTTP Client + as a provider by default (except on Android, where + OkHttp + is the default). +

    +

    + The Apache HTTP Client is very powerful and extremely + flexible, + but can be confusing at first to configure, because of the low-level + approach that + the library uses. +

    + +

    + In many cases, the default configuration should suffice. HAPI FHIR + also encapsulates some of the more common configuration settings you + might want to use (socket timesouts, proxy settings, etc.) so that these + can be configured through HAPI's API without needing to understand the + underlying HTTP Client library. +

    + +

    + This configuration is provided by accessing the + IRestfulClientFactory + class from the FhirContext. +

    + +

    + Note that individual requests and responses + can be tweaked using + Client Interceptors. + This approach is generally useful for configuration involving + tweaking the HTTP request/response, such as adding authorization headers + or logging. +

    + + +

    + The following example shows how to configure low level + socket timeouts for client operations. +

    + + + + +
    + + + +

    + The following example shows how to configure the use of an HTTP + proxy in the client. +

    + + + + + + +
    + + + +

    + As of HAPI FHIR 2.0, an alternate client implementation + is available. This client replaces the low-level + Apache HttpClient implementation with the + Square + OkHttp + library. +

    +

    + Changing HTTP implementations should be mostly + transparent (it has no effect on the actual FHIR + semantics which are transmitted over the wire) but + might be useful if you have an application that + uses OkHttp in other parts of the application and + has specific configuration for that library. +

    +

    + Note that as of HAPI FHIR 2.1, OkHttp is the default + provider on Android, and will be used without any + configuration being required. This is done because + HttpClient is deprecated on Android and has caused + problems in the past. +

    +

    + To use OkHttp, first add the library as a dependency to your project POM: +

    + + ca.uhn.hapi.fhir + hapi-fhir-client-okhttp + ${hapi_stable_version} +]]> + +

    + Then, set the client factory to use OkHttp. +

    + + + + +
    +
    + + + +
    diff --git a/src/site/xdoc/doc_rest_etag.xml b/src/site/xdoc/doc_rest_etag.xml index ab4cca222bd..4d8def62cc6 100644 --- a/src/site/xdoc/doc_rest_etag.xml +++ b/src/site/xdoc/doc_rest_etag.xml @@ -21,60 +21,7 @@ -
    - -

    - ETag features are added simply by adding fluent method calls to the - client method chain, as shown in the following examples. -

    - - - -

    - To notify the server that it should return an HTTP 304 Not Modified - if the content has not changed, add an ifVersionMatches(foo).[operation] - invocation. -

    - - - - - - -

    - This method will add the following header to the request: -

    - If-None-Match: "001" - -
    - -
    - - -

    - To implement version aware updates, specify a version in the - request. This will notify the server that it should only update the - resource on the server if the version matches the given version. This - is useful to prevent two clients from attempting to modify the - resource at the same time, and having one client's updates overwrite - the other's. -

    - - - - - - -

    - The following header will be added to the request as a part of this - interaction. -

    - If-Match: "001" - -
    - -
    diff --git a/src/site/xdoc/doc_rest_operations.xml b/src/site/xdoc/doc_rest_operations.xml index 0223df7f693..56275a79c47 100644 --- a/src/site/xdoc/doc_rest_operations.xml +++ b/src/site/xdoc/doc_rest_operations.xml @@ -1090,7 +1090,7 @@ If-Match: W/"3"]]>

    It is also possible to annotate search methods and/or parameters with the - @Description + @Description annotation. This annotation allows you to add a description of the method and the individual parameters. These descriptions will be placed in the server's conformance statement, which can be helpful to anyone who is developing diff --git a/src/site/xdoc/doc_rest_server_jaxrs.xml b/src/site/xdoc/doc_rest_server_jaxrs.xml index 908fb05a90c..3ad9c720d55 100644 --- a/src/site/xdoc/doc_rest_server_jaxrs.xml +++ b/src/site/xdoc/doc_rest_server_jaxrs.xml @@ -1,89 +1,91 @@ - - - - - JAX-RS Server - James Agnew - - - - -

    -

    - The standard server is implemented using Servlet technology. A module - exists which implements the server using JAX-RS technology. - This enables the usage of existing Java EE interceptors and annotations. This module does not provide the full set of features. - - The server currently supports - Conformance Statements, - @Read, - @Search, - @Create, - @Update, - @Delete and - @Operation. -

    -

    - The primary intention for this project is to ensure that other web technologies (JAX-RS in this case) can be used together with the base-server functionality. - An example server can be found in the Git repo here. -

    - - -

    - The set-up of a JAX-RS server goes beyond the scope of this documentation. The implementation of the server follows the same pattern as the standard server. It is required - to put the correct annotation on the methods in the Resource Providers in order to be able to call them. -

    - -

    - Implementing a JAX-RS Resource Provider requires some JAX-RS annotations. The @Path - annotation needs to define the resource path. The @Produces annotation - needs to declare the produced formats. The constructor needs to pass the class of the object explicitely in order to avoid problems with proxy classes in a Java EE environment. - It is necessary to extend the abstract class - AbstractJaxRsResourceProvider. - - - - -

    - -

    - - Extended Operations require the correct JAX-RS ( - @Path, - @GET or - @POST) annotations. The body of the method needs to call the - method AbstractJaxRsResourceProvider#customOperation - with the correct parameters. The server will then call the method with corresponding name. - - - - -

    - -

    - In order to create the conformance profile, a conformance provider class needs to be deployed which exports the provider's conformance statements. - These providers need to be returned as the result of - the method AbstractJaxRsResourceProvider#getProviders. - This method is called once, during PostConstruct. - - - - -

    -
    - -
    - -
    - -

    - A complete example showing how to implement a JAX-RS RESTful server can - be found in our Git repo here: - https://github.com/jamesagnew/hapi-fhir/tree/master/hapi-fhir-jaxrsserver-example -

    - -
    - - - - + + + + + + + JAX-RS Server + James Agnew + + + + +
    +

    + The standard server is implemented using Servlet technology. A module + exists which implements the server using JAX-RS technology. + This enables the usage of existing Java EE interceptors and annotations. This module does not provide the full set of features. + + The server currently supports + Conformance Statements, + @Read, + @Search, + @Create, + @Update, + @Delete and + @Operation. +

    +

    + The primary intention for this project is to ensure that other web technologies (JAX-RS in this case) can be used together with the base-server functionality. + An example server can be found in the Git repo here. +

    + + +

    + The set-up of a JAX-RS server goes beyond the scope of this documentation. The implementation of the server follows the same pattern as the standard server. It is required + to put the correct annotation on the methods in the Resource Providers in order to be able to call them. +

    + +

    + Implementing a JAX-RS Resource Provider requires some JAX-RS annotations. The @Path + annotation needs to define the resource path. The @Produces annotation + needs to declare the produced formats. The constructor needs to pass the class of the object explicitely in order to avoid problems with proxy classes in a Java EE environment. + It is necessary to extend the abstract class + AbstractJaxRsResourceProvider. + + + + +

    + +

    + + Extended Operations require the correct JAX-RS ( + @Path, + @GET or + @POST) annotations. The body of the method needs to call the + method AbstractJaxRsResourceProvider#customOperation + with the correct parameters. The server will then call the method with corresponding name. + + + + +

    + +

    + In order to create the conformance profile, a conformance provider class needs to be deployed which exports the provider's conformance statements. + These providers need to be returned as the result of + the method AbstractJaxRsResourceProvider#getProviders. + This method is called once, during PostConstruct. + + + + +

    +
    + +
    + +
    + +

    + A complete example showing how to implement a JAX-RS RESTful server can + be found in our Git repo here: + https://github.com/jamesagnew/hapi-fhir/tree/master/hapi-fhir-jaxrsserver-example +

    + +
    + + + +
    diff --git a/src/site/xdoc/doc_rest_server_security.xml b/src/site/xdoc/doc_rest_server_security.xml index b7c2b6b8701..df18f897c62 100644 --- a/src/site/xdoc/doc_rest_server_security.xml +++ b/src/site/xdoc/doc_rest_server_security.xml @@ -315,7 +315,7 @@

    HAPI FHIR 3.7.0 introduced a new interceptor, the - SearchNarrowingInterceptor. + SearchNarrowingInterceptor.

    This interceptor is designed to be used in conjunction with AuthorizationInterceptor. It diff --git a/src/site/xdoc/doc_server_tester.xml.vm b/src/site/xdoc/doc_server_tester.xml.vm index 090fedc7fbc..b8e0cb73891 100644 --- a/src/site/xdoc/doc_server_tester.xml.vm +++ b/src/site/xdoc/doc_server_tester.xml.vm @@ -1,203 +1,205 @@ - - - - - Server Tester - James Agnew - - - - -

    - - - - -

    - HAPI FHIR includes a web UI that can be used to test your server implementation. - This UI is the same UI used on the http://fhirtest.uhn.ca - public server. -

    - -

    - The Tester is a - Maven WAR Overlay, - meaning that you create your own WAR project (which you would likely be doing anyway - to create your server) and the overlay drops a number of files into your project. -

    - - - -

    - These instructions assume that you have an exsiting web project - which uses Maven to build. The POM.xml should have a "packaging" - type of "war". -

    - -

    - Adding the overlay to your project is relatively simple. First, - add the "hapi-fhir-testpage-overlay" dependency to the dependencies - section of your POM.xml file. - - - - - ca.uhn.hapi.fhir - hapi-fhir-testpage-overlay - ${project.version} - war - provided - - - ca.uhn.hapi.fhir - hapi-fhir-testpage-overlay - ${project.version} - classes - provided - -]]> -

    - -

    - Then, add the following WAR plugin to the plugins section - of your POM.xml - - - - - - org.apache.maven.plugins - maven-war-plugin - - - - ca.uhn.hapi.fhir - hapi-fhir-testpage-overlay - - - - - -]]> -

    - -

    - Then, create a Java source file - called FhirTesterConfig.java - and copy in the following contents: -

    - - - - -

    - Note that the URL in the file above must be customized to point to - the FHIR endpoint your server will be deployed to. For example, if you - are naming your project "myfhir-1.0.war" and your endpoint in the WAR is - deployed to "/fhirbase/*" then you should put a URL similar to - http://localhost:8080/myfhir-1.0/fhirbase -

    - -

    - Next, create the following directory in your project - if it doesn't already exist:
    - src/main/webapp/WEB-INF -

    - -

    - In this directory you should open your web.xml file, or create - it if it doesn't exist. - This file is - required in order to deploy to a servlet container and you should create it if - it does not already exist. Place the following contents in that file, adjusting - the package on the FhirTesterConfig to match the - actual package in which you placed this file. -

    - - - spring - org.springframework.web.servlet.DispatcherServlet - - contextClass - org.springframework.web.context.support.AnnotationConfigWebApplicationContext - - - contextConfigLocation - ca.uhn.example.config.FhirTesterConfig - - 2 - - - spring - /tester/* - -]]> - -
    - - - -

    - The most important customization required is to - set the FHIR server base URL in the - hapi-fhir-tester-config.xml - configuration file created during the - previous step. -

    - -

    - Beyond this, the entire tester application is built - from a number of - Thymeleaf - template files, any of which can be replaced to - create your own look and feel. All of the templates - can be found in your built war (after running the Maven - build), or in the target directory's staging area, in - WEB-INF/templates. By placing a file - with the same path/name in your src/main/webapp/WEB-INF/templates - directory you can replace the built in template - with your own file. -

    - -
    - - - -

    - The "Restful Server Example" project contains a complete working - example of the FHIR Tester as a part of its configuration. You may - wish to browse its source to see how this works:
    - https://github.com/jamesagnew/hapi-fhir/tree/master/restful-server-example -

    - -
    - -
    - -
    - -

    - The testing UI uses its own client to talk to your FHIR server. In other words, there are no - special "hooks" which the tested uses to retrieve data from your server, it acts as an HTTP client - just like any other client. -

    - -

    - This does mean that if your server has any authorization requirements, you will need to configure the - tester UI to meet those requirements. For example, if your server has been configured to require - a HTTP Basic Auth header (e.g. Authorization: Basic VVNFUjpQQVNT) you need to - configure the tester UI to send those credentials across when it is acting as - a FHIR client. -

    - -

    - This is done by providing your own implementation of the ITestingUiClientFactory - interface. This interface takes in some details about the incoming request and produces - a client. -

    - -
    - - - - + + + + + + + Server Tester + James Agnew + + + + +
    + + + + +

    + HAPI FHIR includes a web UI that can be used to test your server implementation. + This UI is the same UI used on the http://fhirtest.uhn.ca + public server. +

    + +

    + The Tester is a + Maven WAR Overlay, + meaning that you create your own WAR project (which you would likely be doing anyway + to create your server) and the overlay drops a number of files into your project. +

    + + + +

    + These instructions assume that you have an exsiting web project + which uses Maven to build. The POM.xml should have a "packaging" + type of "war". +

    + +

    + Adding the overlay to your project is relatively simple. First, + add the "hapi-fhir-testpage-overlay" dependency to the dependencies + section of your POM.xml file. + + + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + ${project.version} + war + provided + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + ${project.version} + classes + provided + +]]> +

    + +

    + Then, add the following WAR plugin to the plugins section + of your POM.xml + + + + + + org.apache.maven.plugins + maven-war-plugin + + + + ca.uhn.hapi.fhir + hapi-fhir-testpage-overlay + + + + + +]]> +

    + +

    + Then, create a Java source file + called FhirTesterConfig.java + and copy in the following contents: +

    + + + + +

    + Note that the URL in the file above must be customized to point to + the FHIR endpoint your server will be deployed to. For example, if you + are naming your project "myfhir-1.0.war" and your endpoint in the WAR is + deployed to "/fhirbase/*" then you should put a URL similar to + http://localhost:8080/myfhir-1.0/fhirbase +

    + +

    + Next, create the following directory in your project + if it doesn't already exist:
    + src/main/webapp/WEB-INF +

    + +

    + In this directory you should open your web.xml file, or create + it if it doesn't exist. + This file is + required in order to deploy to a servlet container and you should create it if + it does not already exist. Place the following contents in that file, adjusting + the package on the FhirTesterConfig to match the + actual package in which you placed this file. +

    + + + spring + org.springframework.web.servlet.DispatcherServlet + + contextClass + org.springframework.web.context.support.AnnotationConfigWebApplicationContext + + + contextConfigLocation + ca.uhn.example.config.FhirTesterConfig + + 2 + + + spring + /tester/* + +]]> + +
    + + + +

    + The most important customization required is to + set the FHIR server base URL in the + hapi-fhir-tester-config.xml + configuration file created during the + previous step. +

    + +

    + Beyond this, the entire tester application is built + from a number of + Thymeleaf + template files, any of which can be replaced to + create your own look and feel. All of the templates + can be found in your built war (after running the Maven + build), or in the target directory's staging area, in + WEB-INF/templates. By placing a file + with the same path/name in your src/main/webapp/WEB-INF/templates + directory you can replace the built in template + with your own file. +

    + +
    + + + +

    + The "Restful Server Example" project contains a complete working + example of the FHIR Tester as a part of its configuration. You may + wish to browse its source to see how this works:
    + https://github.com/jamesagnew/hapi-fhir/tree/master/restful-server-example +

    + +
    + +
    + +
    + +

    + The testing UI uses its own client to talk to your FHIR server. In other words, there are no + special "hooks" which the tested uses to retrieve data from your server, it acts as an HTTP client + just like any other client. +

    + +

    + This does mean that if your server has any authorization requirements, you will need to configure the + tester UI to meet those requirements. For example, if your server has been configured to require + a HTTP Basic Auth header (e.g. Authorization: Basic VVNFUjpQQVNT) you need to + configure the tester UI to send those credentials across when it is acting as + a FHIR client. +

    + +

    + This is done by providing your own implementation of the ITestingUiClientFactory + interface. This interface takes in some details about the incoming request and produces + a client. +

    + +
    + + + +
    diff --git a/src/site/xdoc/doc_tinder.xml.vm b/src/site/xdoc/doc_tinder.xml.vm index 2ed8d09945f..19b71a0391f 100644 --- a/src/site/xdoc/doc_tinder.xml.vm +++ b/src/site/xdoc/doc_tinder.xml.vm @@ -1,98 +1,100 @@ - - - - - Tinder - James Agnew - - - - -
    - - - - -

    - According to the FHIR specification, any conformant server - must be able to export a Conformance statement, which - indicates all of the resource types and potential operations - that the server supports. -

    - -

    - HAPI provides a Maven plugin called "Tinder" which is able to automatically - generate a client based on that conformance statement. -

    - -
    - -
    - -

    - The following example shows a simple Maven plugin which - builds a client for the Health Intersections reference - server. -

    - -

    - Note that as of HAPI 0.8, you need to add a dependency to the - plugin containing the version of FHIR you are building custom - structures against. -

    - - - - ca.uhn.hapi.fhir - hapi-tinder-plugin - ${project.version} - - - generate-structures - - ca.uhn.hitest.HiTest - http://fhir.healthintersections.com.au/open - true - - - - - - ca.uhn.hapi.fhir - hapi-fhir-structures-dstu - ${project.version} - - - -]]> - -

    - This example will create a class called - ca.uhn.hitest.HiTest which has - methods to invoke the various server operations. -

    - -

    - It is then possible to use this client as simply as: -

    - - - -
    - - - -
    + + + + + Tinder + James Agnew + + + + + + +
    + + + + +

    + According to the FHIR specification, any conformant server + must be able to export a Conformance statement, which + indicates all of the resource types and potential operations + that the server supports. +

    + +

    + HAPI provides a Maven plugin called "Tinder" which is able to automatically + generate a client based on that conformance statement. +

    + +
    + +
    + +

    + The following example shows a simple Maven plugin which + builds a client for the Health Intersections reference + server. +

    + +

    + Note that as of HAPI 0.8, you need to add a dependency to the + plugin containing the version of FHIR you are building custom + structures against. +

    + + + + ca.uhn.hapi.fhir + hapi-tinder-plugin + ${project.version} + + + generate-structures + + ca.uhn.hitest.HiTest + http://fhir.healthintersections.com.au/open + true + + + + + + ca.uhn.hapi.fhir + hapi-fhir-structures-dstu + ${project.version} + + + +]]> + +

    + This example will create a class called + ca.uhn.hitest.HiTest which has + methods to invoke the various server operations. +

    + +

    + It is then possible to use this client as simply as: +

    + + + +
    + + + +
    diff --git a/src/site/xdoc/doc_validation.xml b/src/site/xdoc/doc_validation.xml index bd964fae98f..50bf5bcb91c 100644 --- a/src/site/xdoc/doc_validation.xml +++ b/src/site/xdoc/doc_validation.xml @@ -1,6 +1,8 @@ + + Validation James Agnew