diff --git a/hapi-deployable-pom/pom.xml b/hapi-deployable-pom/pom.xml index e2b1a4e85c4..524ebabd632 100644 --- a/hapi-deployable-pom/pom.xml +++ b/hapi-deployable-pom/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-android/pom.xml b/hapi-fhir-android/pom.xml index 6c2342e66dd..0366e720771 100644 --- a/hapi-fhir-android/pom.xml +++ b/hapi-fhir-android/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/pom.xml b/hapi-fhir-base/pom.xml index 37aa8760b9b..b9310e594e5 100644 --- a/hapi-fhir-base/pom.xml +++ b/hapi-fhir-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java index 3e48b0dc0ee..ecd8073b0eb 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/context/FhirContext.java @@ -24,7 +24,6 @@ import ca.uhn.fhir.rest.client.api.IBasicClient; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IRestfulClient; import ca.uhn.fhir.rest.client.api.IRestfulClientFactory; -import ca.uhn.fhir.tls.TlsAuthentication; import ca.uhn.fhir.util.FhirTerser; import ca.uhn.fhir.util.ReflectionUtil; import ca.uhn.fhir.util.VersionUtil; diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java index 47384a87f58..21fdc0b710a 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/UrlUtil.java @@ -488,9 +488,12 @@ public class UrlUtil { if (theString == null) { return null; } + // If the user passes "_outputFormat" as a GET request parameter directly in the URL: + final boolean shouldEscapePlus = !theString.startsWith("application/"); + for (int i = 0; i < theString.length(); i++) { char nextChar = theString.charAt(i); - if (nextChar == '%' || nextChar == '+') { + if (nextChar == '%' || (nextChar == '+' && shouldEscapePlus)) { try { // Yes it would be nice to not use a string "UTF-8" but the equivalent // method that takes Charset is JDK10+ only... sigh.... diff --git a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java index 75e2433a626..9bf12999bf2 100644 --- a/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java +++ b/hapi-fhir-base/src/main/java/ca/uhn/fhir/util/VersionEnum.java @@ -103,8 +103,10 @@ public enum VersionEnum { V6_1_0, V6_1_1, V6_1_2, + V6_1_3, + V6_1_4, V6_2_0, - V6_3_0, + V6_3_0 ; public static VersionEnum latestVersion() { diff --git a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java index 6c2fd7cc914..a92e7dc73de 100644 --- a/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java +++ b/hapi-fhir-base/src/test/java/ca/uhn/fhir/util/UrlUtilTest.java @@ -1,10 +1,12 @@ package ca.uhn.fhir.util; +import ca.uhn.fhir.rest.api.Constants; import org.apache.http.message.BasicNameValuePair; import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -45,6 +47,20 @@ public class UrlUtilTest { assertEquals("A%2BB", UrlUtil.escapeUrlParam("A+B")); } + @Test + public void testUnescape() { + assertAll( + () -> assertEquals(Constants.CT_JSON, UrlUtil.unescape(Constants.CT_JSON)), + () -> assertEquals(Constants.CT_NDJSON, UrlUtil.unescape(Constants.CT_NDJSON)), + () -> assertEquals(Constants.CT_XML, UrlUtil.unescape(Constants.CT_XML)), + () -> assertEquals(Constants.CT_XML_PATCH, UrlUtil.unescape(Constants.CT_XML_PATCH)), + () -> assertEquals(Constants.CT_APPLICATION_GZIP, UrlUtil.unescape(Constants.CT_APPLICATION_GZIP)), + () -> assertEquals(Constants.CT_RDF_TURTLE, UrlUtil.unescape(Constants.CT_RDF_TURTLE)), + () -> assertEquals(Constants.CT_FHIR_JSON, UrlUtil.unescape(Constants.CT_FHIR_JSON)), + () -> assertEquals(Constants.CT_FHIR_NDJSON, UrlUtil.unescape(Constants.CT_FHIR_NDJSON)) + ); + } + @Test public void testIsValid() { assertTrue(UrlUtil.isValid("http://foo")); diff --git a/hapi-fhir-batch/pom.xml b/hapi-fhir-batch/pom.xml index 4c835e08e17..5932cb89615 100644 --- a/hapi-fhir-batch/pom.xml +++ b/hapi-fhir-batch/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-bom/pom.xml b/hapi-fhir-bom/pom.xml index 68e9fcd26b1..820c713da15 100644 --- a/hapi-fhir-bom/pom.xml +++ b/hapi-fhir-bom/pom.xml @@ -3,14 +3,14 @@ 4.0.0 ca.uhn.hapi.fhir hapi-fhir-bom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT pom HAPI FHIR BOM ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-checkstyle/pom.xml b/hapi-fhir-checkstyle/pom.xml index 6b762465e87..33c519ab52a 100644 --- a/hapi-fhir-checkstyle/pom.xml +++ b/hapi-fhir-checkstyle/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml index 201b0a61378..b6fb1879185 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-api/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml index f025c1daf09..8b7f778705b 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-app/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir-cli - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml index 9426400ce16..fee873f3abe 100644 --- a/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml +++ b/hapi-fhir-cli/hapi-fhir-cli-jpaserver/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../../hapi-deployable-pom diff --git a/hapi-fhir-cli/pom.xml b/hapi-fhir-cli/pom.xml index 1d093cab89b..734a5bb1564 100644 --- a/hapi-fhir-cli/pom.xml +++ b/hapi-fhir-cli/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-client-okhttp/pom.xml b/hapi-fhir-client-okhttp/pom.xml index ce54439eed4..fe36758adea 100644 --- a/hapi-fhir-client-okhttp/pom.xml +++ b/hapi-fhir-client-okhttp/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/pom.xml b/hapi-fhir-client/pom.xml index 83c21fee9d3..88c20c70f95 100644 --- a/hapi-fhir-client/pom.xml +++ b/hapi-fhir-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java index 8580f47d8f2..414aa2d2b68 100644 --- a/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java +++ b/hapi-fhir-client/src/main/java/ca/uhn/fhir/rest/client/impl/GenericClient.java @@ -2234,7 +2234,6 @@ public class GenericClient extends BaseClient implements IGenericClient { return new TransactionExecutable<>(theResources); } - } private class UpdateInternal extends BaseSearch diff --git a/hapi-fhir-converter/pom.xml b/hapi-fhir-converter/pom.xml index 21a43107a8b..49d5394bcac 100644 --- a/hapi-fhir-converter/pom.xml +++ b/hapi-fhir-converter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java b/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java index b1b29b126ab..a8cf61d1d26 100644 --- a/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java +++ b/hapi-fhir-converter/src/main/java/ca/uhn/hapi/converters/server/VersionedApiConverterInterceptor.java @@ -23,6 +23,7 @@ package ca.uhn.hapi.converters.server; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; +import ca.uhn.fhir.interceptor.api.Interceptor; import ca.uhn.fhir.model.api.IResource; import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.server.RequestDetails; @@ -30,6 +31,7 @@ import ca.uhn.fhir.rest.api.server.ResponseDetails; import ca.uhn.fhir.rest.server.exceptions.AuthenticationException; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter; +import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationConstants; import org.hl7.fhir.converter.NullVersionConverterAdvisor10_30; import org.hl7.fhir.converter.NullVersionConverterAdvisor10_40; import org.hl7.fhir.convertors.factory.VersionConvertorFactory_10_30; @@ -54,6 +56,8 @@ import static org.apache.commons.lang3.StringUtils.*; * Versioned API features. *

*/ + +@Interceptor(order = AuthorizationConstants.ORDER_CONVERTER_INTERCEPTOR) public class VersionedApiConverterInterceptor extends InterceptorAdapter { private final FhirContext myCtxDstu2; private final FhirContext myCtxDstu2Hl7Org; diff --git a/hapi-fhir-dist/pom.xml b/hapi-fhir-dist/pom.xml index 0672fad4433..a53207d9d6d 100644 --- a/hapi-fhir-dist/pom.xml +++ b/hapi-fhir-dist/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-docs/pom.xml b/hapi-fhir-docs/pom.xml index ca16d485654..657315bfe15 100644 --- a/hapi-fhir-docs/pom.xml +++ b/hapi-fhir-docs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_3/upgrade.md b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_3/upgrade.md new file mode 100644 index 00000000000..e69de29bb2d diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_3/version.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_3/version.yaml new file mode 100644 index 00000000000..1b57632767c --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_1_3/version.yaml @@ -0,0 +1,3 @@ +--- +release-date: "2022-10-06" +codename: "Unicorn" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4111-mdm-message-key.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4111-mdm-message-key.yaml index 9d23f25b8a9..014414c2bdb 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4111-mdm-message-key.yaml +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4111-mdm-message-key.yaml @@ -1,5 +1,6 @@ --- type: fix issue: 4111 +backport: 6.1.3 title: "MDM messages were using the resource id as a message key when it should be using the EID as a partition hash key. This could lead to duplicate golden resources on systems using Kafka as a message broker." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4207-getpagesoffset-set-to-total-number-of-resources-results-in-inconsistent-amount-of-entries-when-requests-are-sent-consecutively.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4207-getpagesoffset-set-to-total-number-of-resources-results-in-inconsistent-amount-of-entries-when-requests-are-sent-consecutively.yaml new file mode 100644 index 00000000000..06391321901 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4207-getpagesoffset-set-to-total-number-of-resources-results-in-inconsistent-amount-of-entries-when-requests-are-sent-consecutively.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 4207 +title: "Previously to improve performance, if the total number of resources was less than the _getpageoffset, + the results would default to last resource offset. This is especially evident when requests are consecutive + resulting in one entry being displayed in some requests. This issue is now fixed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4210-wrong-bundle-entry-uri-in-transaction-bundle.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4210-wrong-bundle-entry-uri-in-transaction-bundle.yaml new file mode 100644 index 00000000000..ca8f939292e --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4210-wrong-bundle-entry-uri-in-transaction-bundle.yaml @@ -0,0 +1,5 @@ +--- +type: fix +issue: 4210 +jira: SMILE-4685 +title: "Generating Bundle with resources was setting `entry.request.url` as absolute url when it should be relative. This has been fixed" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4218-bulk-export-get-output-format-param-string-escape-issue.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4218-bulk-export-get-output-format-param-string-escape-issue.yaml new file mode 100644 index 00000000000..d279b9c6a74 --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4218-bulk-export-get-output-format-param-string-escape-issue.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 4218 +title: "Performing a bulk export with an _outputParam value encoded in a GET request URL that contains a '+' (ex: 'application/fhir+ndjson') will result in a 400 because the '+' is replaced with a ' '. After this fix the '+' will remain in the parameter value." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4224-migration-lock-clear.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4224-migration-lock-clear.yaml new file mode 100644 index 00000000000..6e23328163d --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4224-migration-lock-clear.yaml @@ -0,0 +1,4 @@ +--- +type: add +issue: 4224 +title: "Added new System Property called 'CLEAR_LOCK_TABLE_WITH_DESCRIPTION' that when set to the uuid of a lock record, will clear that lock record before attempting to insert a new one." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4232-default-export-bulk-to-all-registered-resource-types.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4232-default-export-bulk-to-all-registered-resource-types.yaml new file mode 100644 index 00000000000..36ad58b411e --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4232-default-export-bulk-to-all-registered-resource-types.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 4232 +title: "Previously during Bulk Export, if no `_type` parameter was provided, an error would be thrown. This has been changed, and if the `_type` parameter is omitted, Bulk Export will default to all registered types." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4234-consent-with-convert.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4234-consent-with-convert.yaml new file mode 100644 index 00000000000..94e8f53584e --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4234-consent-with-convert.yaml @@ -0,0 +1,6 @@ +--- +type: fix +issue: 4234 +jira: SMILE-4765 +title: "Fixed a bug which caused a failure when combining a Consent Interceptor with version conversion via the `Accept` header." + diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4247-bulk-export-job-reuse.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4247-bulk-export-job-reuse.yaml new file mode 100644 index 00000000000..25f3e3354bb --- /dev/null +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/4247-bulk-export-job-reuse.yaml @@ -0,0 +1,4 @@ +--- +type: fix +issue: 4247 +title: "Previously, Bulk Export jobs were always reused, even if completed. Now, jobs are only reused if an identical job is already running, and has not yet completed or failed." diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml index 4b79306acf9..92d154bf813 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_2_0/version.yaml @@ -1,3 +1,3 @@ --- release-date: "2022-11-18" -codename: "TBD" +codename: "Vishwa" diff --git a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_3_0/version.yaml b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_3_0/version.yaml index 74332cf46c0..65e91d915a7 100644 --- a/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_3_0/version.yaml +++ b/hapi-fhir-docs/src/main/resources/ca/uhn/hapi/fhir/changelog/6_3_0/version.yaml @@ -1,3 +1,3 @@ --- -release-date: "TBD" +release-date: "2022-02-18" codename: "TBD" diff --git a/hapi-fhir-jacoco/pom.xml b/hapi-fhir-jacoco/pom.xml index f5efb715ded..48cdfdfbc2e 100644 --- a/hapi-fhir-jacoco/pom.xml +++ b/hapi-fhir-jacoco/pom.xml @@ -11,7 +11,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jaxrsserver-base/pom.xml b/hapi-fhir-jaxrsserver-base/pom.xml index a3ebdf61763..1123f8f69e1 100644 --- a/hapi-fhir-jaxrsserver-base/pom.xml +++ b/hapi-fhir-jaxrsserver-base/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpa/pom.xml b/hapi-fhir-jpa/pom.xml index fdaed9ee04e..cf796af2e2d 100644 --- a/hapi-fhir-jpa/pom.xml +++ b/hapi-fhir-jpa/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-jpaserver-base/pom.xml b/hapi-fhir-jpaserver-base/pom.xml index 1a18839bc90..06ec5bf9d74 100644 --- a/hapi-fhir-jpaserver-base/pom.xml +++ b/hapi-fhir-jpaserver-base/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java index d56d34d4442..2ab5cbd51d5 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/batch2/JpaJobPersistenceImpl.java @@ -35,6 +35,7 @@ import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity; import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity; import ca.uhn.fhir.jpa.util.JobInstanceUtil; import ca.uhn.fhir.model.api.PagingIterator; +import ca.uhn.fhir.narrative.BaseThymeleafNarrativeGenerator; import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.Validate; import org.slf4j.Logger; diff --git a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java index a551022bb7d..74335ffad0c 100644 --- a/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java +++ b/hapi-fhir-jpaserver-base/src/main/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDao.java @@ -160,6 +160,7 @@ public abstract class BaseHapiFhirResourceDao extends B public static final String BASE_RESOURCE_NAME = "resource"; private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirResourceDao.class); + @Autowired protected PlatformTransactionManager myPlatformTransactionManager; @Autowired(required = false) diff --git a/hapi-fhir-jpaserver-cql/pom.xml b/hapi-fhir-jpaserver-cql/pom.xml index db7a25faeba..13f6ab13be8 100644 --- a/hapi-fhir-jpaserver-cql/pom.xml +++ b/hapi-fhir-jpaserver-cql/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml index 3ae132f069d..bef3ac53647 100644 --- a/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-elastic-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-mdm/pom.xml b/hapi-fhir-jpaserver-mdm/pom.xml index 0bbc1a3799d..4134515a4d1 100644 --- a/hapi-fhir-jpaserver-mdm/pom.xml +++ b/hapi-fhir-jpaserver-mdm/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-model/pom.xml b/hapi-fhir-jpaserver-model/pom.xml index 2c24cb96fdf..b14d33165e1 100644 --- a/hapi-fhir-jpaserver-model/pom.xml +++ b/hapi-fhir-jpaserver-model/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-searchparam/pom.xml b/hapi-fhir-jpaserver-searchparam/pom.xml index d0edd4fb80a..2bb451fe257 100755 --- a/hapi-fhir-jpaserver-searchparam/pom.xml +++ b/hapi-fhir-jpaserver-searchparam/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-subscription/pom.xml b/hapi-fhir-jpaserver-subscription/pom.xml index 8972baf7789..6bc6104870b 100644 --- a/hapi-fhir-jpaserver-subscription/pom.xml +++ b/hapi-fhir-jpaserver-subscription/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu2/pom.xml b/hapi-fhir-jpaserver-test-dstu2/pom.xml index dbe117f54a6..0fcc342eb08 100644 --- a/hapi-fhir-jpaserver-test-dstu2/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java index 1301aa2eedb..d23a07ae335 100644 --- a/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java +++ b/hapi-fhir-jpaserver-test-dstu2/src/test/java/ca/uhn/fhir/jpa/dao/dstu2/FhirResourceDaoDstu2SearchCustomSearchParamTest.java @@ -37,6 +37,7 @@ import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException; +import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails; import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; diff --git a/hapi-fhir-jpaserver-test-dstu3/pom.xml b/hapi-fhir-jpaserver-test-dstu3/pom.xml index e75a6ceb78c..c2632b3107c 100644 --- a/hapi-fhir-jpaserver-test-dstu3/pom.xml +++ b/hapi-fhir-jpaserver-test-dstu3/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3BundleTest.java b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3BundleTest.java index 1f84eb75211..48d67088c64 100644 --- a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3BundleTest.java +++ b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3BundleTest.java @@ -4,11 +4,13 @@ import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException; import org.hl7.fhir.dstu3.model.Bundle; import org.hl7.fhir.dstu3.model.CapabilityStatement; +import org.hl7.fhir.dstu3.model.CarePlan; import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.dstu3.model.PrimitiveType; import org.hl7.fhir.dstu3.model.StringType; import org.junit.jupiter.api.Test; +import java.util.ArrayList; import java.util.List; import java.util.Optional; @@ -56,7 +58,27 @@ public class ResourceProviderDstu3BundleTest extends BaseResourceProviderDstu3Te assertTrue(searchInclude.stream().map(PrimitiveType::getValue).anyMatch(stringRevIncludes -> stringRevIncludes.equals("Patient:general-practitioner"))); assertEquals(searchInclude.size(), 4); } - - } + + @Test + void testTransactionBundleEntryUri() { + CarePlan carePlan = new CarePlan(); + carePlan.getText().setDivAsString("A CarePlan"); + carePlan.setId("ACarePlan"); + ourClient.create().resource(carePlan).execute(); + + // GET CarePlans from server + Bundle bundle = ourClient.search() + .byUrl(ourServerBase + "/CarePlan") + .returnBundle(Bundle.class).execute(); + + // Create and populate list of CarePlans + List carePlans = new ArrayList<>(); + bundle.getEntry().forEach(entry -> carePlans.add((CarePlan) entry.getResource())); + + // Post CarePlans should not get: HAPI-2006: Unable to perform PUT, URL provided is invalid... + ourClient.transaction().withResources(carePlans).execute(); + } + + } diff --git a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java index 867b07ab2d5..2be35bd3c08 100644 --- a/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java +++ b/hapi-fhir-jpaserver-test-dstu3/src/test/java/ca/uhn/fhir/jpa/provider/dstu3/ResourceProviderDstu3Test.java @@ -5,7 +5,6 @@ import ca.uhn.fhir.jpa.api.config.DaoConfig; import ca.uhn.fhir.jpa.dao.data.ISearchDao; import ca.uhn.fhir.jpa.entity.Search; import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.util.QueryParameterUtils; import ca.uhn.fhir.model.api.TemporalPrecisionEnum; import ca.uhn.fhir.model.primitive.InstantDt; @@ -17,7 +16,6 @@ import ca.uhn.fhir.rest.api.Constants; import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.SearchTotalModeEnum; import ca.uhn.fhir.rest.api.SummaryEnum; -import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.client.api.IClientInterceptor; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.IHttpRequest; @@ -30,7 +28,6 @@ import ca.uhn.fhir.rest.param.ParamPrefixEnum; import ca.uhn.fhir.rest.param.StringAndListParam; import ca.uhn.fhir.rest.param.StringOrListParam; import ca.uhn.fhir.rest.param.StringParam; -import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; @@ -107,7 +104,6 @@ import org.hl7.fhir.dstu3.model.Organization; import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.dstu3.model.Patient; import org.hl7.fhir.dstu3.model.Period; -import org.hl7.fhir.dstu3.model.Person; import org.hl7.fhir.dstu3.model.PlanDefinition; import org.hl7.fhir.dstu3.model.Practitioner; import org.hl7.fhir.dstu3.model.ProcedureRequest; @@ -2354,7 +2350,7 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test { assertEquals(1, ((Patient) history.getEntry().get(0).getResource()).getName().size()); assertEquals(HTTPVerb.DELETE, history.getEntry().get(1).getRequest().getMethodElement().getValue()); - assertEquals("http://localhost:" + ourPort + "/fhir/context/Patient/" + id.getIdPart() + "/_history/2", history.getEntry().get(1).getRequest().getUrl()); + assertEquals("Patient/" + id.getIdPart() + "/_history/2", history.getEntry().get(1).getRequest().getUrl()); assertEquals(null, history.getEntry().get(1).getResource()); assertEquals(id.withVersion("1").getValue(), history.getEntry().get(2).getResource().getId()); diff --git a/hapi-fhir-jpaserver-test-r4/pom.xml b/hapi-fhir-jpaserver-test-r4/pom.xml index 9fbe1e4995b..1629009d032 100644 --- a/hapi-fhir-jpaserver-test-r4/pom.xml +++ b/hapi-fhir-jpaserver-test-r4/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderTest.java index 3bff9990352..f5f3e8d90cf 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkDataExportProviderTest.java @@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.bulk; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.model.Batch2JobInfo; import ca.uhn.fhir.jpa.api.model.Batch2JobOperationResult; import ca.uhn.fhir.jpa.api.model.BulkExportJobResults; @@ -57,6 +58,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; +import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Stream; @@ -67,12 +69,15 @@ import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.nullValue; +import static org.junit.jupiter.api.Assertions.assertAll; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -93,7 +98,7 @@ public class BulkDataExportProviderTest { private IBatch2JobRunner myJobRunner; private DaoConfig myDaoConfig; - + private DaoRegistry myDaoRegistry; private CloseableHttpClient myClient; @InjectMocks @@ -136,6 +141,9 @@ public class BulkDataExportProviderTest { public void injectDaoConfig() { myDaoConfig = new DaoConfig(); myProvider.setDaoConfig(myDaoConfig); + myDaoRegistry = mock(DaoRegistry.class); + lenient().when(myDaoRegistry.getRegisteredDaoTypes()).thenReturn(Set.of("Patient", "Observation", "Encounter")); + myProvider.setDaoRegistry(myDaoRegistry); } public void startWithFixedBaseUrl() { @@ -863,6 +871,52 @@ public class BulkDataExportProviderTest { } } + @Test + public void testGetBulkExport_outputFormat_FhirNdJson_inHeader() throws IOException { + // when + when(myJobRunner.startNewJob(any())) + .thenReturn(createJobStartResponse()); + + // call + final HttpGet httpGet = new HttpGet(String.format("http://localhost:%s/%s", myPort, JpaConstants.OPERATION_EXPORT)); + httpGet.addHeader("_outputFormat", Constants.CT_FHIR_NDJSON); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + + try (CloseableHttpResponse response = myClient.execute(httpGet)) { + ourLog.info("Response: {}", response.toString()); + assertEquals(202, response.getStatusLine().getStatusCode()); + assertEquals("Accepted", response.getStatusLine().getReasonPhrase()); + assertEquals(String.format("http://localhost:%s/$export-poll-status?_jobId=%s", myPort, A_JOB_ID), response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()); + assertTrue(IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8).isEmpty()); + } + + final BulkExportParameters params = verifyJobStart(); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + } + + @Test + public void testGetBulkExport_outputFormat_FhirNdJson_inUrl() throws IOException { + // when + when(myJobRunner.startNewJob(any())) + .thenReturn(createJobStartResponse()); + + // call + final HttpGet httpGet = new HttpGet(String.format("http://localhost:%s/%s?_outputFormat=%s", myPort, JpaConstants.OPERATION_EXPORT, Constants.CT_FHIR_NDJSON)); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + + try (CloseableHttpResponse response = myClient.execute(httpGet)) { + assertAll( + () -> assertEquals(202, response.getStatusLine().getStatusCode()), + () -> assertEquals("Accepted", response.getStatusLine().getReasonPhrase()), + () -> assertEquals(String.format("http://localhost:%s/$export-poll-status?_jobId=%s", myPort, A_JOB_ID), response.getFirstHeader(Constants.HEADER_CONTENT_LOCATION).getValue()), + () -> assertTrue(IOUtils.toString(response.getEntity().getContent(), Charsets.UTF_8).isEmpty()) + ); + } + + final BulkExportParameters params = verifyJobStart(); + assertEquals(Constants.CT_FHIR_NDJSON, params.getOutputFormat()); + } + private void callExportAndAssertJobId(Parameters input, String theExpectedJobId) throws IOException { HttpPost post; post = new HttpPost("http://localhost:" + myPort + "/" + JpaConstants.OPERATION_EXPORT); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java index 9bace0e1a7a..fe279c65d6a 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/bulk/BulkExportUseCaseTest.java @@ -25,12 +25,14 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Binary; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Coverage; +import org.hl7.fhir.r4.model.Encounter; import org.hl7.fhir.r4.model.Enumerations; import org.hl7.fhir.r4.model.Group; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Reference; +import org.jetbrains.annotations.NotNull; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Nested; @@ -41,6 +43,7 @@ import org.springframework.beans.factory.annotation.Autowired; import java.io.IOException; import java.nio.charset.StandardCharsets; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -48,6 +51,7 @@ import java.util.List; import java.util.Map; import java.util.Optional; import java.util.Set; +import java.util.stream.Collectors; import static org.awaitility.Awaitility.await; import static org.hamcrest.CoreMatchers.is; @@ -56,6 +60,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.empty; import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.Matchers.hasSize; import static org.hamcrest.Matchers.not; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -63,7 +68,6 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; - public class BulkExportUseCaseTest extends BaseResourceProviderR4Test { private static final Logger ourLog = LoggerFactory.getLogger(BulkExportUseCaseTest.class); @@ -76,6 +80,29 @@ public class BulkExportUseCaseTest extends BaseResourceProviderR4Test { @Nested public class SpecConformanceTests { + + @Test + public void testBatchJobsAreOnlyReusedIfInProgress() throws IOException { + //Given a patient exists + Patient p = new Patient(); + p.setId("Pat-1"); + myClient.update().resource(p).execute(); + + //And Given we start a bulk export job + String pollingLocation = submitBulkExportForTypes("Patient"); + String jobId = getJobIdFromPollingLocation(pollingLocation); + myBatch2JobHelper.awaitJobCompletion(jobId); + + //When we execute another batch job, it should not have the same job id. + String secondPollingLocation = submitBulkExportForTypes("Patient"); + String secondJobId = getJobIdFromPollingLocation(secondPollingLocation); + + //Then the job id should be different + assertThat(secondJobId, not(equalTo(jobId))); + + + myBatch2JobHelper.awaitJobCompletion(secondJobId); + } @Test public void testPollingLocationContainsAllRequiredAttributesUponCompletion() throws IOException { @@ -85,14 +112,8 @@ public class BulkExportUseCaseTest extends BaseResourceProviderR4Test { myClient.update().resource(p).execute(); //And Given we start a bulk export job - HttpGet httpGet = new HttpGet(myClient.getServerBase() + "/$export?_type=Patient"); - httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); - String pollingLocation; - try (CloseableHttpResponse status = ourHttpClient.execute(httpGet)) { - Header[] headers = status.getHeaders("Content-Location"); - pollingLocation = headers[0].getValue(); - } - String jobId = pollingLocation.substring(pollingLocation.indexOf("_jobId=") + 7); + String pollingLocation = submitBulkExportForTypes("Patient"); + String jobId = getJobIdFromPollingLocation(pollingLocation); myBatch2JobHelper.awaitJobCompletion(jobId); //Then: When the poll shows as complete, all attributes should be filled. @@ -113,6 +134,143 @@ public class BulkExportUseCaseTest extends BaseResourceProviderR4Test { assertThat(responseContent, containsString("\"error\" : [ ]")); } } + + @NotNull + private String getJobIdFromPollingLocation(String pollingLocation) { + return pollingLocation.substring(pollingLocation.indexOf("_jobId=") + 7); + } + + @Test + public void export_shouldExportPatientResource_whenTypeParameterOmitted() throws IOException { + + //Given a patient exists + Patient p = new Patient(); + p.setId("Pat-1"); + myClient.update().resource(p).execute(); + + //And Given we start a bulk export job + HttpGet httpGet = new HttpGet(myClient.getServerBase() + "/$export"); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + String pollingLocation; + try (CloseableHttpResponse status = ourHttpClient.execute(httpGet)) { + Header[] headers = status.getHeaders("Content-Location"); + pollingLocation = headers[0].getValue(); + } + String jobId = getJobIdFromPollingLocation(pollingLocation); + myBatch2JobHelper.awaitJobCompletion(jobId); + + //Then: When the poll shows as complete, all attributes should be filled. + HttpGet statusGet = new HttpGet(pollingLocation); + String expectedOriginalUrl = myClient.getServerBase() + "/$export"; + try (CloseableHttpResponse status = ourHttpClient.execute(statusGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); + + ourLog.info(responseContent); + + BulkExportResponseJson result = JsonUtil.deserialize(responseContent, BulkExportResponseJson.class); + assertThat(result.getRequest(), is(equalTo(expectedOriginalUrl))); + assertThat(result.getRequiresAccessToken(), is(equalTo(true))); + assertThat(result.getTransactionTime(), is(notNullValue())); + assertThat(result.getOutput(), is(not(empty()))); + + //We assert specifically on content as the deserialized version will "helpfully" fill in missing fields. + assertThat(responseContent, containsString("\"error\" : [ ]")); + } + } + + @Test + public void export_shouldExportPatientAndObservationAndEncounterResources_whenTypeParameterOmitted() throws IOException { + + Patient patient = new Patient(); + patient.setId("Pat-1"); + myClient.update().resource(patient).execute(); + + Observation observation = new Observation(); + observation.setId("Obs-1"); + myClient.update().resource(observation).execute(); + + Encounter encounter = new Encounter(); + encounter.setId("Enc-1"); + myClient.update().resource(encounter).execute(); + + HttpGet httpGet = new HttpGet(myClient.getServerBase() + "/$export"); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + String pollingLocation; + try (CloseableHttpResponse status = ourHttpClient.execute(httpGet)) { + Header[] headers = status.getHeaders("Content-Location"); + pollingLocation = headers[0].getValue(); + } + String jobId = getJobIdFromPollingLocation(pollingLocation); + myBatch2JobHelper.awaitJobCompletion(jobId); + + HttpGet statusGet = new HttpGet(pollingLocation); + String expectedOriginalUrl = myClient.getServerBase() + "/$export"; + try (CloseableHttpResponse status = ourHttpClient.execute(statusGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); + BulkExportResponseJson result = JsonUtil.deserialize(responseContent, BulkExportResponseJson.class); + assertThat(result.getRequest(), is(equalTo(expectedOriginalUrl))); + assertThat(result.getRequiresAccessToken(), is(equalTo(true))); + assertThat(result.getTransactionTime(), is(notNullValue())); + assertEquals(result.getOutput().size(), 3); + assertEquals(1, result.getOutput().stream().filter(o -> o.getType().equals("Patient")).collect(Collectors.toList()).size()); + assertEquals(1, result.getOutput().stream().filter(o -> o.getType().equals("Observation")).collect(Collectors.toList()).size()); + assertEquals(1, result.getOutput().stream().filter(o -> o.getType().equals("Encounter")).collect(Collectors.toList()).size()); + + //We assert specifically on content as the deserialized version will "helpfully" fill in missing fields. + assertThat(responseContent, containsString("\"error\" : [ ]")); + } + } + + @Test + public void export_shouldNotExportBinaryResource_whenTypeParameterOmitted() throws IOException { + + Patient patient = new Patient(); + patient.setId("Pat-1"); + myClient.update().resource(patient).execute(); + + Binary binary = new Binary(); + binary.setId("Bin-1"); + myClient.update().resource(binary).execute(); + + HttpGet httpGet = new HttpGet(myClient.getServerBase() + "/$export"); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + String pollingLocation; + try (CloseableHttpResponse status = ourHttpClient.execute(httpGet)) { + Header[] headers = status.getHeaders("Content-Location"); + pollingLocation = headers[0].getValue(); + } + String jobId = getJobIdFromPollingLocation(pollingLocation); + myBatch2JobHelper.awaitJobCompletion(jobId); + + HttpGet statusGet = new HttpGet(pollingLocation); + String expectedOriginalUrl = myClient.getServerBase() + "/$export"; + try (CloseableHttpResponse status = ourHttpClient.execute(statusGet)) { + String responseContent = IOUtils.toString(status.getEntity().getContent(), StandardCharsets.UTF_8); + BulkExportResponseJson result = JsonUtil.deserialize(responseContent, BulkExportResponseJson.class); + assertThat(result.getRequest(), is(equalTo(expectedOriginalUrl))); + assertThat(result.getRequiresAccessToken(), is(equalTo(true))); + assertThat(result.getTransactionTime(), is(notNullValue())); + assertEquals(result.getOutput().size(), 1); + assertEquals(1, result.getOutput().stream().filter(o -> o.getType().equals("Patient")).collect(Collectors.toList()).size()); + assertEquals(0, result.getOutput().stream().filter(o -> o.getType().equals("Binary")).collect(Collectors.toList()).size()); + + //We assert specifically on content as the deserialized version will "helpfully" fill in missing fields. + assertThat(responseContent, containsString("\"error\" : [ ]")); + } + } + + } + + private String submitBulkExportForTypes(String... theTypes) throws IOException { + String typeString = String.join(",", theTypes); + HttpGet httpGet = new HttpGet(myClient.getServerBase() + "/$export?_type=" + typeString); + httpGet.addHeader(Constants.HEADER_PREFER, Constants.HEADER_PREFER_RESPOND_ASYNC); + String pollingLocation; + try (CloseableHttpResponse status = ourHttpClient.execute(httpGet)) { + Header[] headers = status.getHeaders("Content-Location"); + pollingLocation = headers[0].getValue(); + } + return pollingLocation; } @Nested @@ -233,7 +391,6 @@ public class BulkExportUseCaseTest extends BaseResourceProviderR4Test { } - @Nested public class PatientBulkExportTests { diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java index cf924be002b..ef3646d3543 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/dao/BaseHapiFhirResourceDaoTest.java @@ -41,6 +41,8 @@ import javax.persistence.EntityManager; import java.util.List; +import java.util.List; + import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java index 9abba0bdf60..257b4aeb873 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ConsentInterceptorResourceProviderR4Test.java @@ -24,6 +24,7 @@ import ca.uhn.fhir.rest.server.interceptor.consent.IConsentService; import ca.uhn.fhir.util.BundleUtil; import ca.uhn.fhir.util.StopWatch; import ca.uhn.fhir.util.UrlUtil; +import ca.uhn.hapi.converters.server.VersionedApiConverterInterceptor; import com.google.common.base.Charsets; import com.google.common.collect.Lists; import org.apache.commons.collections4.ListUtils; @@ -282,6 +283,21 @@ public class ConsentInterceptorResourceProviderR4Test extends BaseResourceProvid }); } + @Test + public void testConsentWorksWithVersionedApiConverterInterceptor() { + myConsentInterceptor = new ConsentInterceptor(new IConsentService() { + }); + ourRestServer.getInterceptorService().registerInterceptor(myConsentInterceptor); + ourRestServer.getInterceptorService().registerInterceptor(new VersionedApiConverterInterceptor()); + + myClient.create().resource(new Patient().setGender(Enumerations.AdministrativeGender.MALE).addName(new HumanName().setFamily("1"))).execute(); + Bundle response = myClient.search().forResource(Patient.class).count(1).accept("application/fhir+json; fhirVersion=3.0").returnBundle(Bundle.class).execute(); + + assertEquals(1, response.getEntry().size()); + assertNull(response.getTotalElement().getValue()); + + } + @Test public void testHistoryAndBlockSome() { create50Observations(); diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java index 89f6d0f1213..4c8d1d13a31 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4BundleTest.java @@ -10,6 +10,7 @@ import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Bundle.BundleType; import org.hl7.fhir.r4.model.Bundle.HTTPVerb; +import org.hl7.fhir.r4.model.CarePlan; import org.hl7.fhir.r4.model.Condition; import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender; import org.hl7.fhir.r4.model.OperationOutcome; @@ -331,4 +332,25 @@ public class ResourceProviderR4BundleTest extends BaseResourceProviderR4Test { return ids; } + + @Test + void testTransactionBundleEntryUri() { + CarePlan carePlan = new CarePlan(); + carePlan.getText().setDivAsString("A CarePlan"); + carePlan.setId("ACarePlan"); + myClient.create().resource(carePlan).execute(); + + // GET CarePlans from server + Bundle bundle = myClient.search() + .byUrl(ourServerBase + "/CarePlan") + .returnBundle(Bundle.class).execute(); + + // Create and populate list of CarePlans + List carePlans = new ArrayList<>(); + bundle.getEntry().forEach(entry -> carePlans.add((CarePlan) entry.getResource())); + + // Post CarePlans should not get: HAPI-2006: Unable to perform PUT, URL provided is invalid... + myClient.transaction().withResources(carePlans).execute(); + } + } diff --git a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java index b8e7a32b8e0..1358cfe0729 100644 --- a/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java +++ b/hapi-fhir-jpaserver-test-r4/src/test/java/ca/uhn/fhir/jpa/provider/r4/ResourceProviderR4Test.java @@ -10,7 +10,6 @@ import ca.uhn.fhir.jpa.model.entity.ResourceHistoryTable; import ca.uhn.fhir.jpa.model.util.JpaConstants; import ca.uhn.fhir.jpa.model.util.UcumServiceUtil; import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.term.ZipCollectionBuilder; import ca.uhn.fhir.jpa.test.config.TestR4Config; import ca.uhn.fhir.jpa.util.QueryParameterUtils; @@ -25,7 +24,6 @@ import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.api.PreferReturnEnum; import ca.uhn.fhir.rest.api.SearchTotalModeEnum; import ca.uhn.fhir.rest.api.SummaryEnum; -import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.client.apache.ResourceEntity; import ca.uhn.fhir.rest.client.api.IClientInterceptor; import ca.uhn.fhir.rest.client.api.IGenericClient; @@ -41,7 +39,6 @@ import ca.uhn.fhir.rest.param.ParamPrefixEnum; import ca.uhn.fhir.rest.param.StringAndListParam; import ca.uhn.fhir.rest.param.StringOrListParam; import ca.uhn.fhir.rest.param.StringParam; -import ca.uhn.fhir.rest.param.TokenParam; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException; @@ -71,7 +68,6 @@ import org.apache.http.entity.ContentType; import org.apache.http.entity.StringEntity; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; -import org.apache.jena.rdf.model.ModelCon; import org.hamcrest.Matchers; import org.hl7.fhir.common.hapi.validation.validator.FhirInstanceValidator; import org.hl7.fhir.instance.model.api.IAnyResource; @@ -132,7 +128,6 @@ import org.hl7.fhir.r4.model.Organization; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r4.model.Period; -import org.hl7.fhir.r4.model.Person; import org.hl7.fhir.r4.model.Practitioner; import org.hl7.fhir.r4.model.Procedure; import org.hl7.fhir.r4.model.Quantity; @@ -169,6 +164,7 @@ import org.springframework.transaction.support.TransactionCallbackWithoutResult; import org.springframework.transaction.support.TransactionTemplate; import javax.annotation.Nonnull; +import javax.sql.DataSource; import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; @@ -3285,7 +3281,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test { assertEquals(1, ((Patient) history.getEntry().get(0).getResource()).getName().size()); assertEquals(HTTPVerb.DELETE, history.getEntry().get(1).getRequest().getMethodElement().getValue()); - assertEquals("http://localhost:" + ourPort + "/fhir/context/Patient/" + id.getIdPart() + "/_history/2", history.getEntry().get(1).getRequest().getUrl()); + assertEquals("Patient/" + id.getIdPart() + "/_history/2", history.getEntry().get(1).getRequest().getUrl()); assertEquals(null, history.getEntry().get(1).getResource()); assertEquals(id.withVersion("1").getValue(), history.getEntry().get(2).getResource().getId()); diff --git a/hapi-fhir-jpaserver-test-r4b/pom.xml b/hapi-fhir-jpaserver-test-r4b/pom.xml index 1ed22408ee5..99b6ecae0af 100644 --- a/hapi-fhir-jpaserver-test-r4b/pom.xml +++ b/hapi-fhir-jpaserver-test-r4b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r4b/src/test/java/ca/uhn/fhir/jpa/provider/r4b/ResourceProviderR4BTest.java b/hapi-fhir-jpaserver-test-r4b/src/test/java/ca/uhn/fhir/jpa/provider/r4b/ResourceProviderR4BTest.java index 6d835cd99de..e3ab35f3eee 100644 --- a/hapi-fhir-jpaserver-test-r4b/src/test/java/ca/uhn/fhir/jpa/provider/r4b/ResourceProviderR4BTest.java +++ b/hapi-fhir-jpaserver-test-r4b/src/test/java/ca/uhn/fhir/jpa/provider/r4b/ResourceProviderR4BTest.java @@ -13,20 +13,17 @@ import com.google.common.base.Charsets; import org.apache.commons.io.IOUtils; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpGet; -import org.apache.http.client.methods.HttpPost; -import org.apache.http.entity.ContentType; -import org.apache.http.entity.StringEntity; import org.hamcrest.Matchers; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r4b.model.Bundle; import org.hl7.fhir.r4b.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r4b.model.CarePlan; import org.hl7.fhir.r4b.model.CodeableConcept; import org.hl7.fhir.r4b.model.Condition; import org.hl7.fhir.r4b.model.DateTimeType; import org.hl7.fhir.r4b.model.MedicationRequest; import org.hl7.fhir.r4b.model.Observation; import org.hl7.fhir.r4b.model.Observation.ObservationComponentComponent; -import org.hl7.fhir.r4b.model.OperationOutcome; import org.hl7.fhir.r4b.model.Organization; import org.hl7.fhir.r4b.model.Parameters; import org.hl7.fhir.r4b.model.Patient; @@ -464,6 +461,28 @@ public class ResourceProviderR4BTest extends BaseResourceProviderR4BTest { assertThat(ids, Matchers.not(hasItem(o2Id))); } + @Test + void testTransactionBundleEntryUri() { + CarePlan carePlan = new CarePlan(); + carePlan.getText().setDivAsString("A CarePlan"); + carePlan.setId("ACarePlan"); + myClient.create().resource(carePlan).execute(); + + // GET CarePlans from server + Bundle bundle = myClient.search() + .byUrl(ourServerBase + "/CarePlan") + .returnBundle(Bundle.class).execute(); + + // Create and populate list of CarePlans + List carePlans = new ArrayList<>(); + bundle.getEntry().forEach(entry -> carePlans.add((CarePlan) entry.getResource())); + + // Post CarePlans should not get: HAPI-2006: Unable to perform PUT, URL provided is invalid... + myClient.transaction().withResources(carePlans).execute(); + } + + + private IIdType createOrganization(String methodName, String s) { Organization o1 = new Organization(); o1.setName(methodName + s); diff --git a/hapi-fhir-jpaserver-test-r5/pom.xml b/hapi-fhir-jpaserver-test-r5/pom.xml index a84c5d01af4..db78d26cb1f 100644 --- a/hapi-fhir-jpaserver-test-r5/pom.xml +++ b/hapi-fhir-jpaserver-test-r5/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5Test.java b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5Test.java index 8d1d556fc7e..3171fb4af85 100644 --- a/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5Test.java +++ b/hapi-fhir-jpaserver-test-r5/src/test/java/ca/uhn/fhir/jpa/provider/r5/ResourceProviderR5Test.java @@ -19,6 +19,7 @@ import org.hamcrest.Matchers; import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.r5.model.Bundle; import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent; +import org.hl7.fhir.r5.model.CarePlan; import org.hl7.fhir.r5.model.CodeableConcept; import org.hl7.fhir.r5.model.Condition; import org.hl7.fhir.r5.model.DateTimeType; @@ -481,6 +482,27 @@ public class ResourceProviderR5Test extends BaseResourceProviderR5Test { assertThat(ids, Matchers.not(hasItem(o2Id))); } + + @Test + void testTransactionBundleEntryUri() { + CarePlan carePlan = new CarePlan(); + carePlan.getText().setDivAsString("A CarePlan"); + carePlan.setId("ACarePlan"); + myClient.create().resource(carePlan).execute(); + + // GET CarePlans from server + Bundle bundle = myClient.search() + .byUrl(ourServerBase + "/CarePlan") + .returnBundle(Bundle.class).execute(); + + // Create and populate list of CarePlans + List carePlans = new ArrayList<>(); + bundle.getEntry().forEach(entry -> carePlans.add((CarePlan) entry.getResource())); + + // Post CarePlans should not get: HAPI-2006: Unable to perform PUT, URL provided is invalid... + myClient.transaction().withResources(carePlans).execute(); + } + private IIdType createOrganization(String methodName, String s) { Organization o1 = new Organization(); o1.setName(methodName + s); diff --git a/hapi-fhir-jpaserver-test-utilities/pom.xml b/hapi-fhir-jpaserver-test-utilities/pom.xml index 9ca5a676fa1..a2687d0790c 100644 --- a/hapi-fhir-jpaserver-test-utilities/pom.xml +++ b/hapi-fhir-jpaserver-test-utilities/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml index 41298dfc6f7..12b6a283f49 100644 --- a/hapi-fhir-jpaserver-uhnfhirtest/pom.xml +++ b/hapi-fhir-jpaserver-uhnfhirtest/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-server-mdm/pom.xml b/hapi-fhir-server-mdm/pom.xml index 1d9e1d02ef1..c8c2f0475a0 100644 --- a/hapi-fhir-server-mdm/pom.xml +++ b/hapi-fhir-server-mdm/pom.xml @@ -7,7 +7,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server-openapi/pom.xml b/hapi-fhir-server-openapi/pom.xml index 567d2d91d91..ef7f94f06b0 100644 --- a/hapi-fhir-server-openapi/pom.xml +++ b/hapi-fhir-server-openapi/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/pom.xml b/hapi-fhir-server/pom.xml index 11d42001f7f..9ebf005be9e 100644 --- a/hapi-fhir-server/pom.xml +++ b/hapi-fhir-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java index f138a14568e..51c1e7c2567 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/interceptor/auth/AuthorizationConstants.java @@ -24,6 +24,7 @@ public class AuthorizationConstants { public static final int ORDER_CONSENT_INTERCEPTOR = 100; public static final int ORDER_AUTH_INTERCEPTOR = 200; + public static final int ORDER_CONVERTER_INTERCEPTOR = 300; private AuthorizationConstants() { super(); diff --git a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java index cb81c181887..a284ea7b1c7 100644 --- a/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java +++ b/hapi-fhir-server/src/main/java/ca/uhn/fhir/rest/server/method/BaseResourceReturningMethodBinding.java @@ -369,17 +369,15 @@ public abstract class BaseResourceReturningMethodBinding extends BaseMethodBindi count = result.preferredPageSize(); } - Integer offsetI = RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_PAGINGOFFSET); - if (offsetI == null || offsetI < 0) { - offsetI = 0; + Integer offset = RestfulServerUtils.tryToExtractNamedParameter(theRequest, Constants.PARAM_PAGINGOFFSET); + if (offset == null || offset < 0) { + offset = 0; } Integer resultSize = result.size(); - int start; + int start = offset; if (resultSize != null) { - start = Math.max(0, Math.min(offsetI, resultSize - 1)); - } else { - start = offsetI; + start = Math.max(0, Math.min(offset, resultSize)); } ResponseEncoding responseEncoding = RestfulServerUtils.determineResponseEncodingNoDefault(theRequest, theServer.getDefaultResponseEncoding()); diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml index 6b54240e8ec..d04ab284bc5 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-autoconfigure/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml index d604e590ee6..b9b1218fc42 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-apache/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT hapi-fhir-spring-boot-sample-client-apache diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml index a2b86796529..e86304e27c4 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-client-okhttp/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT hapi-fhir-spring-boot-sample-client-okhttp diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml index 90a9ac73b68..1f399a743da 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/hapi-fhir-spring-boot-sample-server-jersey/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot-samples - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT hapi-fhir-spring-boot-sample-server-jersey diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml index 040bd66fd2e..528f4f7c923 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-samples/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir-spring-boot - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT hapi-fhir-spring-boot-samples diff --git a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml index f934e564e8c..1132d0beac2 100644 --- a/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml +++ b/hapi-fhir-spring-boot/hapi-fhir-spring-boot-starter/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-spring-boot/pom.xml b/hapi-fhir-spring-boot/pom.xml index d00b63f9e79..2daa1947a43 100644 --- a/hapi-fhir-spring-boot/pom.xml +++ b/hapi-fhir-spring-boot/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-sql-migrate/pom.xml b/hapi-fhir-sql-migrate/pom.xml index 79a854a1e53..df5bad0e721 100644 --- a/hapi-fhir-sql-migrate/pom.xml +++ b/hapi-fhir-sql-migrate/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationLock.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationLock.java index 68a4b4643d2..a65761f50be 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationLock.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationLock.java @@ -21,18 +21,25 @@ package ca.uhn.fhir.jpa.migrate; */ import ca.uhn.fhir.i18n.Msg; +import ca.uhn.fhir.jpa.migrate.entity.HapiMigrationEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Optional; import java.util.UUID; +import static org.apache.commons.lang3.StringUtils.isBlank; + /** * The approach used in this class is borrowed from org.flywaydb.community.database.ignite.thin.IgniteThinDatabase */ public class HapiMigrationLock implements AutoCloseable { + static final Integer LOCK_PID = -100; private static final Logger ourLog = LoggerFactory.getLogger(HapiMigrationLock.class); public static final int SLEEP_MILLIS_BETWEEN_LOCK_RETRIES = 1000; - public static final int MAX_RETRY_ATTEMPTS = 50; + public static final int DEFAULT_MAX_RETRY_ATTEMPTS = 50; + public static int ourMaxRetryAttempts = DEFAULT_MAX_RETRY_ATTEMPTS; + public static final String CLEAR_LOCK_TABLE_WITH_DESCRIPTION = "CLEAR_LOCK_TABLE_WITH_DESCRIPTION"; private final String myLockDescription = UUID.randomUUID().toString(); @@ -47,6 +54,7 @@ public class HapiMigrationLock implements AutoCloseable { } private void lock() { + cleanLockTableIfRequested(); int retryCount = 0; do { @@ -55,23 +63,57 @@ public class HapiMigrationLock implements AutoCloseable { return; } retryCount++; - ourLog.info("Waiting for lock on " + this); - Thread.sleep(SLEEP_MILLIS_BETWEEN_LOCK_RETRIES); + + if (retryCount < ourMaxRetryAttempts) { + ourLog.info("Waiting for lock on {}. Retry {}/{}", myMigrationStorageSvc.getMigrationTablename(), retryCount, ourMaxRetryAttempts); + Thread.sleep(SLEEP_MILLIS_BETWEEN_LOCK_RETRIES); + } } catch (InterruptedException ex) { // Ignore - if interrupted, we still need to wait for lock to become available } - } while (retryCount < MAX_RETRY_ATTEMPTS); + } while (retryCount < ourMaxRetryAttempts); - throw new HapiMigrationException(Msg.code(2153) + "Unable to obtain table lock - another database migration may be running. If no " + + String message = "Unable to obtain table lock - another database migration may be running. If no " + "other database migration is running, then the previous migration did not shut down properly and the " + "lock record needs to be deleted manually. The lock record is located in the " + myMigrationStorageSvc.getMigrationTablename() + " table with " + - "INSTALLED_RANK = " + HapiMigrationStorageSvc.LOCK_PID); + "INSTALLED_RANK = " + LOCK_PID; + + Optional otherLockFound = myMigrationStorageSvc.findFirstByPidAndNotDescription(LOCK_PID, myLockDescription); + if (otherLockFound.isPresent()) { + message += " and DESCRIPTION = " + otherLockFound.get().getDescription(); + } + + throw new HapiMigrationException(Msg.code(2153) + message); + } + + /** + * + * @return whether a lock record was successfully deleted + */ + boolean cleanLockTableIfRequested() { + String description = System.getProperty(CLEAR_LOCK_TABLE_WITH_DESCRIPTION); + if (isBlank(description)) { + description = System.getenv(CLEAR_LOCK_TABLE_WITH_DESCRIPTION); + } + if (isBlank(description)) { + return false; + } + + ourLog.info("Repairing lock table. Removing row in " + myMigrationStorageSvc.getMigrationTablename() + " with INSTALLED_RANK = " + LOCK_PID + " and DESCRIPTION = " + description); + boolean result = myMigrationStorageSvc.deleteLockRecord(description); + if (result) { + ourLog.info("Successfully removed lock record"); + } else { + ourLog.info("No lock record found"); + } + return result; } private boolean insertLockingRow() { try { return myMigrationStorageSvc.insertLockRecord(myLockDescription); } catch (Exception e) { + ourLog.debug("Failed to insert lock record: {}", e.getMessage()); return false; } } @@ -83,4 +125,8 @@ public class HapiMigrationLock implements AutoCloseable { ourLog.error("Failed to delete migration lock record for description = [{}]", myLockDescription); } } + + public static void setMaxRetryAttempts(int theMaxRetryAttempts) { + ourMaxRetryAttempts = theMaxRetryAttempts; + } } diff --git a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationStorageSvc.java b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationStorageSvc.java index 2ea84380ed2..566f332bd21 100644 --- a/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationStorageSvc.java +++ b/hapi-fhir-sql-migrate/src/main/java/ca/uhn/fhir/jpa/migrate/HapiMigrationStorageSvc.java @@ -32,7 +32,6 @@ import java.util.Set; public class HapiMigrationStorageSvc { public static final String UNKNOWN_VERSION = "unknown"; private static final String LOCK_TYPE = "hapi-fhir-lock"; - static final Integer LOCK_PID = -100; private final HapiMigrationDao myHapiMigrationDao; @@ -104,11 +103,11 @@ public class HapiMigrationStorageSvc { verifyNoOtherLocksPresent(theLockDescription); // Remove the locking row - return myHapiMigrationDao.deleteLockRecord(LOCK_PID, theLockDescription); + return myHapiMigrationDao.deleteLockRecord(HapiMigrationLock.LOCK_PID, theLockDescription); } void verifyNoOtherLocksPresent(String theLockDescription) { - Optional otherLockFound = myHapiMigrationDao.findFirstByPidAndNotDescription(LOCK_PID, theLockDescription); + Optional otherLockFound = myHapiMigrationDao.findFirstByPidAndNotDescription(HapiMigrationLock.LOCK_PID, theLockDescription); // Check that there are no other locks in place. This should not happen! if (otherLockFound.isPresent()) { @@ -118,7 +117,7 @@ public class HapiMigrationStorageSvc { public boolean insertLockRecord(String theLockDescription) { HapiMigrationEntity entity = new HapiMigrationEntity(); - entity.setPid(LOCK_PID); + entity.setPid(HapiMigrationLock.LOCK_PID); entity.setType(LOCK_TYPE); entity.setDescription(theLockDescription); entity.setExecutionTime(0); @@ -126,4 +125,8 @@ public class HapiMigrationStorageSvc { return myHapiMigrationDao.save(entity); } + + public Optional findFirstByPidAndNotDescription(Integer theLockPid, String theLockDescription) { + return myHapiMigrationDao.findFirstByPidAndNotDescription(theLockPid, theLockDescription); + } } diff --git a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/HapiMigratorIT.java b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/HapiMigratorIT.java index 109b4174e6b..1edb81611d9 100644 --- a/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/HapiMigratorIT.java +++ b/hapi-fhir-sql-migrate/src/test/java/ca/uhn/fhir/jpa/migrate/HapiMigratorIT.java @@ -1,7 +1,9 @@ package ca.uhn.fhir.jpa.migrate; import ca.uhn.fhir.interceptor.api.HookParams; +import ca.uhn.fhir.jpa.migrate.dao.HapiMigrationDao; import ca.uhn.fhir.jpa.migrate.taskdef.BaseTask; +import ca.uhn.fhir.jpa.migrate.taskdef.NopTask; import ca.uhn.test.concurrency.IPointcutLatch; import ca.uhn.test.concurrency.PointcutLatch; import org.apache.commons.dbcp2.BasicDataSource; @@ -16,6 +18,7 @@ import org.springframework.jdbc.core.JdbcTemplate; import javax.annotation.Nonnull; import java.util.List; +import java.util.UUID; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; @@ -25,6 +28,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; class HapiMigratorIT { private static final Logger ourLog = LoggerFactory.getLogger(HapiMigratorIT.class); @@ -32,6 +36,7 @@ class HapiMigratorIT { private final BasicDataSource myDataSource = BaseMigrationTest.getDataSource(); private final JdbcTemplate myJdbcTemplate = new JdbcTemplate(myDataSource); + private HapiMigrationStorageSvc myMigrationStorageSvc; @BeforeEach void before() { @@ -39,12 +44,17 @@ class HapiMigratorIT { migrator.createMigrationTableIfRequired(); Integer count = myJdbcTemplate.queryForObject("SELECT COUNT(*) FROM " + MIGRATION_TABLENAME, Integer.class); assertTrue(count > 0); + HapiMigrationDao migrationDao = new HapiMigrationDao(myDataSource, DriverTypeEnum.H2_EMBEDDED, MIGRATION_TABLENAME); + myMigrationStorageSvc = new HapiMigrationStorageSvc(migrationDao); + } @AfterEach void after() { myJdbcTemplate.execute("DROP TABLE " + MIGRATION_TABLENAME); assertEquals(0, myDataSource.getNumActive()); + HapiMigrationLock.setMaxRetryAttempts(HapiMigrationLock.DEFAULT_MAX_RETRY_ATTEMPTS); + System.clearProperty(HapiMigrationLock.CLEAR_LOCK_TABLE_WITH_DESCRIPTION); } @Test @@ -76,8 +86,7 @@ class HapiMigratorIT { LatchMigrationTask latchMigrationTask2 = new LatchMigrationTask("second new", "2"); LatchMigrationTask latchMigrationTask3 = new LatchMigrationTask("third repeat", "1"); - HapiMigrator migrator2 = buildMigrator(latchMigrationTask2); - migrator2.addTask(latchMigrationTask3); + HapiMigrator migrator2 = buildMigrator(latchMigrationTask2, latchMigrationTask3); // We only expect the first migration to run because the second one will block on the lock and by the time the lock // is released, the first one will have already run so there will be nothing to do @@ -108,10 +117,77 @@ class HapiMigratorIT { assertThat(result2.succeededTasks, hasSize(1)); } + @Test + void test_twoSequentialCalls_noblock() throws InterruptedException, ExecutionException { + + ExecutorService executor = Executors.newSingleThreadExecutor(); + LatchMigrationTask latchMigrationTask = new LatchMigrationTask("first", "1"); + + HapiMigrator migrator = buildMigrator(latchMigrationTask); + assertEquals(0, countLockRecords()); + + { + latchMigrationTask.setExpectedCount(1); + Future future = executor.submit(() -> migrator.migrate()); + latchMigrationTask.awaitExpected(); + assertEquals(1, countLockRecords()); + latchMigrationTask.release("1"); + + MigrationResult result = future.get(); + assertEquals(0, countLockRecords()); + assertThat(result.succeededTasks, hasSize(1)); + } + + { + Future future = executor.submit(() -> migrator.migrate()); + + MigrationResult result = future.get(); + assertEquals(0, countLockRecords()); + assertThat(result.succeededTasks, hasSize(0)); + } + + } + + + @Test + void test_oldLockFails_block() { + HapiMigrationLock.setMaxRetryAttempts(0); + String description = UUID.randomUUID().toString(); + HapiMigrator migrator = buildMigrator(); + myMigrationStorageSvc.insertLockRecord(description); + + try { + migrator.migrate(); + fail(); + } catch (HapiMigrationException e) { + assertEquals("HAPI-2153: Unable to obtain table lock - another database migration may be running. If no other database migration is running, then the previous migration did not shut down properly and the lock record needs to be deleted manually. The lock record is located in the TEST_MIGRATOR_TABLE table with INSTALLED_RANK = -100 and DESCRIPTION = " + description, e.getMessage()); + } + } + + @Test + void test_oldLockWithSystemProperty_cleared() { + HapiMigrationLock.setMaxRetryAttempts(0); + String description = UUID.randomUUID().toString(); + HapiMigrator migrator = buildMigrator(new NopTask("1", "1")); + myMigrationStorageSvc.insertLockRecord(description); + + System.setProperty(HapiMigrationLock.CLEAR_LOCK_TABLE_WITH_DESCRIPTION, description); + + MigrationResult result = migrator.migrate(); + assertThat(result.succeededTasks, hasSize(1)); + } + + + private int countLockRecords() { + return myJdbcTemplate.queryForObject("SELECT COUNT(*) FROM " + MIGRATION_TABLENAME + " WHERE \"installed_rank\" = " + HapiMigrationLock.LOCK_PID, Integer.class); + } + @Nonnull - private HapiMigrator buildMigrator(LatchMigrationTask theLatchMigrationTask) { + private HapiMigrator buildMigrator(BaseTask... theTasks) { HapiMigrator retval = buildMigrator(); - retval.addTask(theLatchMigrationTask); + for (BaseTask next : theTasks) { + retval.addTask(next); + } return retval; } diff --git a/hapi-fhir-storage-batch2-jobs/pom.xml b/hapi-fhir-storage-batch2-jobs/pom.xml index 66d907374b1..48b4ae31e66 100644 --- a/hapi-fhir-storage-batch2-jobs/pom.xml +++ b/hapi-fhir-storage-batch2-jobs/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidator.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidator.java index 61179319cde..cf695ecd5aa 100644 --- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidator.java +++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidator.java @@ -43,11 +43,8 @@ public class BulkExportJobParametersValidator implements IJobParametersValidator List errorMsgs = new ArrayList<>(); // initial validation - - if (theParameters.getResourceTypes() == null || theParameters.getResourceTypes().isEmpty()) { - errorMsgs.add("Resource Types are required for an export job."); - } - else { + List resourceTypes = theParameters.getResourceTypes(); + if (resourceTypes != null && !resourceTypes.isEmpty()) { for (String resourceType : theParameters.getResourceTypes()) { if (resourceType.equalsIgnoreCase("Binary")) { errorMsgs.add("Bulk export of Binary resources is forbidden"); diff --git a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java index 1560638dfa0..d512e8c79e0 100644 --- a/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java +++ b/hapi-fhir-storage-batch2-jobs/src/main/java/ca/uhn/fhir/batch2/jobs/export/FetchResourceIdsStep.java @@ -31,6 +31,7 @@ import ca.uhn.fhir.batch2.jobs.export.models.BulkExportJobParameters; import ca.uhn.fhir.batch2.jobs.models.Id; import ca.uhn.fhir.i18n.Msg; import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.bulk.export.api.IBulkExportProcessor; import ca.uhn.fhir.jpa.bulk.export.model.ExportPIDIteratorParameters; import ca.uhn.fhir.rest.api.server.storage.ResourcePersistentId; diff --git a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidatorTest.java b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidatorTest.java index d03ba0ade23..16179fda782 100644 --- a/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidatorTest.java +++ b/hapi-fhir-storage-batch2-jobs/src/test/java/ca/uhn/fhir/batch2/jobs/export/BulkExportJobParametersValidatorTest.java @@ -130,7 +130,7 @@ public class BulkExportJobParametersValidatorTest { } @Test - public void validate_omittedResourceTypes_returnsErrorMessages() { + public void validate_omittedResourceTypes_returnsNoErrorMessages() { // setup BulkExportJobParameters parameters = createSystemExportParameters(); parameters.setResourceTypes(null); @@ -140,8 +140,7 @@ public class BulkExportJobParametersValidatorTest { // verify assertNotNull(results); - assertEquals(1, results.size()); - assertTrue(results.contains("Resource Types are required for an export job.")); + assertEquals(0, results.size()); } @Test diff --git a/hapi-fhir-storage-batch2/pom.xml b/hapi-fhir-storage-batch2/pom.xml index 1b6ba40bef2..c2cf092ed43 100644 --- a/hapi-fhir-storage-batch2/pom.xml +++ b/hapi-fhir-storage-batch2/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java index 4466e4df3a5..00e822465fd 100644 --- a/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java +++ b/hapi-fhir-storage-batch2/src/main/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImpl.java @@ -96,14 +96,9 @@ public class JobCoordinatorImpl implements IJobCoordinator { if (isBlank(paramsString)) { throw new InvalidRequestException(Msg.code(2065) + "No parameters supplied"); } - // if cache - use that first if (theStartRequest.isUseCache()) { - FetchJobInstancesRequest request = new FetchJobInstancesRequest(theStartRequest.getJobDefinitionId(), theStartRequest.getParameters(), - StatusEnum.QUEUED, - StatusEnum.IN_PROGRESS, - StatusEnum.COMPLETED - ); + FetchJobInstancesRequest request = new FetchJobInstancesRequest(theStartRequest.getJobDefinitionId(), theStartRequest.getParameters(), getStatesThatTriggerCache()); List existing = myJobPersistence.fetchInstances(request, 0, 1000); if (!existing.isEmpty()) { @@ -142,6 +137,13 @@ public class JobCoordinatorImpl implements IJobCoordinator { return response; } + /** + * Cache will be used if an identical job is QUEUED or IN_PROGRESS. Otherwise a new one will kickoff. + */ + private StatusEnum[] getStatesThatTriggerCache() { + return new StatusEnum[]{StatusEnum.QUEUED, StatusEnum.IN_PROGRESS}; + } + @Override public JobInstance getInstance(String theInstanceId) { return myJobQuerySvc.fetchInstance(theInstanceId); diff --git a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java index 6572c4742d1..24ad9149e81 100644 --- a/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java +++ b/hapi-fhir-storage-batch2/src/test/java/ca/uhn/fhir/batch2/coordinator/JobCoordinatorImplTest.java @@ -42,6 +42,7 @@ import java.util.Arrays; import java.util.Optional; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -151,9 +152,10 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { } @Test - public void startInstance_usingExistingCache_returnsExistingJobFirst() { + public void startInstance_usingExistingCache_returnsExistingIncompleteJobFirst() { // setup - String instanceId = "completed-id"; + String completedInstanceId = "completed-id"; + String inProgressInstanceId = "someId"; JobInstanceStartRequest startRequest = new JobInstanceStartRequest(); startRequest.setJobDefinitionId(JOB_DEFINITION_ID); startRequest.setUseCache(true); @@ -162,32 +164,32 @@ public class JobCoordinatorImplTest extends BaseBatch2Test { JobDefinition def = createJobDefinition(); JobInstance existingInProgInstance = createInstance(); - existingInProgInstance.setInstanceId("someId"); + existingInProgInstance.setInstanceId(inProgressInstanceId); existingInProgInstance.setStatus(StatusEnum.IN_PROGRESS); + JobInstance existingCompletedInstance = createInstance(); existingCompletedInstance.setStatus(StatusEnum.COMPLETED); - existingCompletedInstance.setInstanceId(instanceId); + existingCompletedInstance.setInstanceId(completedInstanceId); // when when(myJobDefinitionRegistry.getLatestJobDefinition(eq(JOB_DEFINITION_ID))) .thenReturn(Optional.of(def)); when(myJobInstancePersister.fetchInstances(any(FetchJobInstancesRequest.class), anyInt(), anyInt())) - .thenReturn(Arrays.asList(existingInProgInstance, existingCompletedInstance)); + .thenReturn(Arrays.asList(existingInProgInstance)); // test Batch2JobStartResponse startResponse = mySvc.startInstance(startRequest); // verify - assertEquals(instanceId, startResponse.getJobId()); // make sure it's the completed one + assertEquals(inProgressInstanceId, startResponse.getJobId()); // make sure it's the completed one assertTrue(startResponse.isUsesCachedResult()); ArgumentCaptor requestArgumentCaptor = ArgumentCaptor.forClass(FetchJobInstancesRequest.class); verify(myJobInstancePersister) .fetchInstances(requestArgumentCaptor.capture(), anyInt(), anyInt()); FetchJobInstancesRequest req = requestArgumentCaptor.getValue(); - assertEquals(3, req.getStatuses().size()); + assertEquals(2, req.getStatuses().size()); assertTrue( - req.getStatuses().contains(StatusEnum.COMPLETED) - && req.getStatuses().contains(StatusEnum.IN_PROGRESS) + req.getStatuses().contains(StatusEnum.IN_PROGRESS) && req.getStatuses().contains(StatusEnum.QUEUED) ); } diff --git a/hapi-fhir-storage-mdm/pom.xml b/hapi-fhir-storage-mdm/pom.xml index 0cc54962563..5abca8298d7 100644 --- a/hapi-fhir-storage-mdm/pom.xml +++ b/hapi-fhir-storage-mdm/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage-mdm/src/main/java/ca/uhn/fhir/mdm/batch2/MdmBatch2Config.java b/hapi-fhir-storage-mdm/src/main/java/ca/uhn/fhir/mdm/batch2/MdmBatch2Config.java index 51720a90d9b..3eb1ac9f7b4 100644 --- a/hapi-fhir-storage-mdm/src/main/java/ca/uhn/fhir/mdm/batch2/MdmBatch2Config.java +++ b/hapi-fhir-storage-mdm/src/main/java/ca/uhn/fhir/mdm/batch2/MdmBatch2Config.java @@ -51,6 +51,6 @@ public class MdmBatch2Config { JobDefinition clearJobDefinition = myApplicationContext.getBean(MDM_CLEAR_JOB_BEAN_NAME, JobDefinition.class); myJobDefinitionRegistry.addJobDefinitionIfNotRegistered(clearJobDefinition); JobDefinition submitJobDefinition = myApplicationContext.getBean(MDM_SUBMIT_JOB_BEAN_NAME, JobDefinition.class); - myJobDefinitionRegistry.addJobDefinitionIfNotRegistered(clearJobDefinition); + myJobDefinitionRegistry.addJobDefinitionIfNotRegistered(submitJobDefinition); } } diff --git a/hapi-fhir-storage-test-utilities/pom.xml b/hapi-fhir-storage-test-utilities/pom.xml index 76f9b766ddd..00afd3a83ea 100644 --- a/hapi-fhir-storage-test-utilities/pom.xml +++ b/hapi-fhir-storage-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml 4.0.0 diff --git a/hapi-fhir-storage/pom.xml b/hapi-fhir-storage/pom.xml index 3002598eb2b..3ab139e591b 100644 --- a/hapi-fhir-storage/pom.xml +++ b/hapi-fhir-storage/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/bulk/export/provider/BulkDataExportProvider.java b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/bulk/export/provider/BulkDataExportProvider.java index 21596f30d72..f43dc089261 100644 --- a/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/bulk/export/provider/BulkDataExportProvider.java +++ b/hapi-fhir-storage/src/main/java/ca/uhn/fhir/jpa/bulk/export/provider/BulkDataExportProvider.java @@ -26,6 +26,7 @@ import ca.uhn.fhir.interceptor.api.HookParams; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.Pointcut; import ca.uhn.fhir.jpa.api.config.DaoConfig; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.model.Batch2JobInfo; import ca.uhn.fhir.jpa.api.model.Batch2JobOperationResult; import ca.uhn.fhir.jpa.api.model.BulkExportJobResults; @@ -68,6 +69,7 @@ import org.springframework.beans.factory.annotation.Autowired; import javax.servlet.http.HttpServletResponse; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Date; @@ -100,6 +102,9 @@ public class BulkDataExportProvider { @Autowired private DaoConfig myDaoConfig; + @Autowired + private DaoRegistry myDaoRegistry; + /** * $export */ @@ -136,6 +141,13 @@ public class BulkDataExportProvider { // Set the original request URL as part of the job information, as this is used in the poll-status-endpoint, and is needed for the report. parameters.setOriginalRequestUrl(theRequestDetails.getCompleteUrl()); + // If no _type parameter is provided, default to all resource types except Binary + if (theOptions.getResourceTypes() == null || theOptions.getResourceTypes().isEmpty()) { + List resourceTypes = new ArrayList<>(myDaoRegistry.getRegisteredDaoTypes()); + resourceTypes.remove("Binary"); + parameters.setResourceTypes(resourceTypes); + } + // start job Batch2JobStartResponse response = myJobRunner.startNewJob(parameters); @@ -486,4 +498,9 @@ public class BulkDataExportProvider { public void setDaoConfig(DaoConfig theDaoConfig) { myDaoConfig = theDaoConfig; } + + @VisibleForTesting + public void setDaoRegistry(DaoRegistry theDaoRegistry) { + myDaoRegistry = theDaoRegistry; + } } diff --git a/hapi-fhir-structures-dstu2.1/pom.xml b/hapi-fhir-structures-dstu2.1/pom.xml index 7fb29f3b479..ce2d5de8f96 100644 --- a/hapi-fhir-structures-dstu2.1/pom.xml +++ b/hapi-fhir-structures-dstu2.1/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu2/pom.xml b/hapi-fhir-structures-dstu2/pom.xml index 1ab9b676a87..18b841b3c98 100644 --- a/hapi-fhir-structures-dstu2/pom.xml +++ b/hapi-fhir-structures-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/pom.xml b/hapi-fhir-structures-dstu3/pom.xml index e870ec9b19a..8012d551911 100644 --- a/hapi-fhir-structures-dstu3/pom.xml +++ b/hapi-fhir-structures-dstu3/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/Dstu3BundleFactory.java b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/Dstu3BundleFactory.java index c7b3015047f..9813efc5694 100644 --- a/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/Dstu3BundleFactory.java +++ b/hapi-fhir-structures-dstu3/src/main/java/org/hl7/fhir/dstu3/hapi/rest/server/Dstu3BundleFactory.java @@ -136,7 +136,7 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory { if (httpVerb != null) { entry.getRequest().getMethodElement().setValueAsString(httpVerb); if (id != null) { - entry.getRequest().setUrl(id.getValue()); + entry.getRequest().setUrl(id.toUnqualified().getValue()); } } if ("DELETE".equals(httpVerb)) { diff --git a/hapi-fhir-structures-hl7org-dstu2/pom.xml b/hapi-fhir-structures-hl7org-dstu2/pom.xml index a0888be5bad..61133ecaeaa 100644 --- a/hapi-fhir-structures-hl7org-dstu2/pom.xml +++ b/hapi-fhir-structures-hl7org-dstu2/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/pom.xml b/hapi-fhir-structures-r4/pom.xml index 299b268d308..c0d7fa43908 100644 --- a/hapi-fhir-structures-r4/pom.xml +++ b/hapi-fhir-structures-r4/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/R4BundleFactory.java b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/R4BundleFactory.java index 893bf9e86c3..d80fca6b4ed 100644 --- a/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/R4BundleFactory.java +++ b/hapi-fhir-structures-r4/src/main/java/org/hl7/fhir/r4/hapi/rest/server/R4BundleFactory.java @@ -138,7 +138,7 @@ public class R4BundleFactory implements IVersionSpecificBundleFactory { if (httpVerb != null) { entry.getRequest().getMethodElement().setValueAsString(httpVerb); if (id != null) { - entry.getRequest().setUrl(id.getValue()); + entry.getRequest().setUrl(id.toUnqualified().getValue()); } } if ("DELETE".equals(httpVerb)) { diff --git a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/PagingTest.java b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/PagingTest.java index 6f4f1ee87b2..47b0352e606 100644 --- a/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/PagingTest.java +++ b/hapi-fhir-structures-r4/src/test/java/ca/uhn/fhir/rest/server/PagingTest.java @@ -146,6 +146,37 @@ public class PagingTest { } } + @Test() + public void testSendingSameRequestConsecutivelyResultsInSameResponse() throws Exception { + initBundleProvider(10); + myServerExtension.getRestfulServer().registerProvider(new DummyPatientResourceProvider()); + myServerExtension.getRestfulServer().setPagingProvider(pagingProvider); + + when(pagingProvider.canStoreSearchResults()).thenReturn(true); + when(pagingProvider.getDefaultPageSize()).thenReturn(10); + when(pagingProvider.getMaximumPageSize()).thenReturn(50); + when(pagingProvider.storeResultList(any(RequestDetails.class), any(IBundleProvider.class))).thenReturn("ABCD"); + when(pagingProvider.retrieveResultList(any(RequestDetails.class), anyString())).thenReturn(ourBundleProvider); + + String nextLink; + String base = "http://localhost:" + myServerExtension.getPort(); + HttpGet get = new HttpGet(base + "/Patient?_getpagesoffset=10"); + String responseContent; + try (CloseableHttpResponse resp = ourClient.execute(get)) { + assertEquals(200, resp.getStatusLine().getStatusCode()); + responseContent = IOUtils.toString(resp.getEntity().getContent(), Charsets.UTF_8); + + Bundle bundle = ourContext.newJsonParser().parseResource(Bundle.class, responseContent); + assertEquals(0, bundle.getEntry().size()); + } + try (CloseableHttpResponse resp = ourClient.execute(get)) { + assertEquals(200, resp.getStatusLine().getStatusCode()); + responseContent = IOUtils.toString(resp.getEntity().getContent(), Charsets.UTF_8); + + Bundle bundle = ourContext.newJsonParser().parseResource(Bundle.class, responseContent); + assertEquals(0, bundle.getEntry().size()); + } + } private void checkParam(String theUri, String theCheckedParam, String theExpectedValue) { Optional paramValue = URLEncodedUtils.parse(theUri, CHARSET_UTF8).stream() .filter(nameValuePair -> nameValuePair.getName().equals(theCheckedParam)) diff --git a/hapi-fhir-structures-r4b/pom.xml b/hapi-fhir-structures-r4b/pom.xml index f8e1975157b..684b3326585 100644 --- a/hapi-fhir-structures-r4b/pom.xml +++ b/hapi-fhir-structures-r4b/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r4b/src/main/java/org/hl7/fhir/r4b/hapi/rest/server/R4BBundleFactory.java b/hapi-fhir-structures-r4b/src/main/java/org/hl7/fhir/r4b/hapi/rest/server/R4BBundleFactory.java index fc1ee804e61..2a1c7f7d910 100644 --- a/hapi-fhir-structures-r4b/src/main/java/org/hl7/fhir/r4b/hapi/rest/server/R4BBundleFactory.java +++ b/hapi-fhir-structures-r4b/src/main/java/org/hl7/fhir/r4b/hapi/rest/server/R4BBundleFactory.java @@ -138,7 +138,7 @@ public class R4BBundleFactory implements IVersionSpecificBundleFactory { if (httpVerb != null) { entry.getRequest().getMethodElement().setValueAsString(httpVerb); if (id != null) { - entry.getRequest().setUrl(id.getValue()); + entry.getRequest().setUrl(id.toUnqualified().getValue()); } } if ("DELETE".equals(httpVerb)) { diff --git a/hapi-fhir-structures-r5/pom.xml b/hapi-fhir-structures-r5/pom.xml index 99903f06a14..5b650763736 100644 --- a/hapi-fhir-structures-r5/pom.xml +++ b/hapi-fhir-structures-r5/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/rest/server/R5BundleFactory.java b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/rest/server/R5BundleFactory.java index 2bc8bac0c48..47d6f1b4fa2 100644 --- a/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/rest/server/R5BundleFactory.java +++ b/hapi-fhir-structures-r5/src/main/java/org/hl7/fhir/r5/hapi/rest/server/R5BundleFactory.java @@ -138,7 +138,7 @@ public class R5BundleFactory implements IVersionSpecificBundleFactory { if (httpVerb != null) { entry.getRequest().getMethodElement().setValueAsString(httpVerb); if (id != null) { - entry.getRequest().setUrl(id.getValue()); + entry.getRequest().setUrl(id.toUnqualified().getValue()); } } if ("DELETE".equals(httpVerb)) { diff --git a/hapi-fhir-test-utilities/pom.xml b/hapi-fhir-test-utilities/pom.xml index 5df3a925631..3e62baf3581 100644 --- a/hapi-fhir-test-utilities/pom.xml +++ b/hapi-fhir-test-utilities/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-testpage-overlay/pom.xml b/hapi-fhir-testpage-overlay/pom.xml index e4474237130..395d44fb36b 100644 --- a/hapi-fhir-testpage-overlay/pom.xml +++ b/hapi-fhir-testpage-overlay/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-fhir-validation-resources-dstu2.1/pom.xml b/hapi-fhir-validation-resources-dstu2.1/pom.xml index c2a1a7eb6eb..1270d1ad574 100644 --- a/hapi-fhir-validation-resources-dstu2.1/pom.xml +++ b/hapi-fhir-validation-resources-dstu2.1/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu2/pom.xml b/hapi-fhir-validation-resources-dstu2/pom.xml index 1cda9139883..dc201566889 100644 --- a/hapi-fhir-validation-resources-dstu2/pom.xml +++ b/hapi-fhir-validation-resources-dstu2/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-dstu3/pom.xml b/hapi-fhir-validation-resources-dstu3/pom.xml index 6570d325bd4..c62b00d908f 100644 --- a/hapi-fhir-validation-resources-dstu3/pom.xml +++ b/hapi-fhir-validation-resources-dstu3/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r4/pom.xml b/hapi-fhir-validation-resources-r4/pom.xml index ddf5804120e..5d7a57d989d 100644 --- a/hapi-fhir-validation-resources-r4/pom.xml +++ b/hapi-fhir-validation-resources-r4/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation-resources-r5/pom.xml b/hapi-fhir-validation-resources-r5/pom.xml index 5abcf27bd4a..6768c96a0d7 100644 --- a/hapi-fhir-validation-resources-r5/pom.xml +++ b/hapi-fhir-validation-resources-r5/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-fhir-validation/pom.xml b/hapi-fhir-validation/pom.xml index e6bf11151fc..64869c2ca5c 100644 --- a/hapi-fhir-validation/pom.xml +++ b/hapi-fhir-validation/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-deployable-pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../hapi-deployable-pom/pom.xml diff --git a/hapi-tinder-plugin/pom.xml b/hapi-tinder-plugin/pom.xml index e8250473245..f70a6ef5f7e 100644 --- a/hapi-tinder-plugin/pom.xml +++ b/hapi-tinder-plugin/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/hapi-tinder-test/pom.xml b/hapi-tinder-test/pom.xml index 3700638251c..3f99e8a50e5 100644 --- a/hapi-tinder-test/pom.xml +++ b/hapi-tinder-test/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../pom.xml diff --git a/pom.xml b/pom.xml index 8eadeea9c1f..c68f07bb811 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir pom - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT HAPI-FHIR An open-source implementation of the FHIR specification in Java. https://hapifhir.io @@ -1083,6 +1083,13 @@ okhttp ${okhttp_version} + + + com.squareup.okio + okio-jvm + 3.2.0 + + com.sun.activation javax.activation @@ -2063,7 +2070,7 @@ ca.uhn.hapi.fhir hapi-fhir-checkstyle - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT diff --git a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml index b247541c7a6..96ab6543e2c 100644 --- a/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml +++ b/tests/hapi-fhir-base-test-jaxrsserver-kotlin/pom.xml @@ -6,7 +6,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-client/pom.xml b/tests/hapi-fhir-base-test-mindeps-client/pom.xml index 2277e49cecc..fba882bfbb0 100644 --- a/tests/hapi-fhir-base-test-mindeps-client/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-client/pom.xml @@ -4,7 +4,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../../pom.xml diff --git a/tests/hapi-fhir-base-test-mindeps-server/pom.xml b/tests/hapi-fhir-base-test-mindeps-server/pom.xml index 5f60aff00de..24cdaae6511 100644 --- a/tests/hapi-fhir-base-test-mindeps-server/pom.xml +++ b/tests/hapi-fhir-base-test-mindeps-server/pom.xml @@ -5,7 +5,7 @@ ca.uhn.hapi.fhir hapi-fhir - 6.3.0-PRE2-SNAPSHOT + 6.3.0-PRE3-SNAPSHOT ../../pom.xml