From 69c035f0a1ab89ba05b52fe0245cd095c3a66d31 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Sun, 23 Jan 2022 22:12:26 -0700 Subject: [PATCH 01/12] WIP Test Framework --- .vscode/settings.json | 3 +- common/README.md | 60 ++++ common/pom.xml | 44 +++ .../DaoRegistryOperationProvider.java | 25 ++ .../cqf/ruler/common/utility/Canonicals.java | 151 ++++++++++ .../cqf/ruler/common/utility/Clients.java | 101 +++++-- .../ruler/common/utility/DaoRegistryUser.java | 133 +++++++++ .../ruler/common/utility/FhirContextUser.java | 7 + .../ruler/common/utility/FhirVersions.java | 45 +++ .../utility/HeaderInjectionInterceptor.java | 2 +- .../cqf/ruler/common/utility/IdCreator.java | 22 ++ .../opencds/cqf/ruler/common/utility/Ids.java | 56 +++- .../cqf/ruler/common/utility/Operations.java | 79 +++++ .../cqf/ruler/common/utility/Reflections.java | 88 +++--- .../common}/utility/ResolutionUtilities.java | 14 +- .../ruler/common/utility/ResourceCreator.java | 29 ++ .../cqf/ruler/common/utility/Searches.java | 46 +++ .../common/utility/TypedBundleProvider.java | 70 +++++ .../cqf/ruler/common/utility/Versions.java | 102 +++++++ .../cqf/ruler/common/utility/ClientsTest.java | 72 +++++ .../common/utility/FhirVersionsTest.java | 27 ++ .../cqf/ruler/common/utility/IdsTest.java | 12 +- .../ruler/common/utility/ReflectionsTest.java | 32 +- .../ruler/common/utility/VersionsTest.java | 24 +- core/pom.xml | 87 +++++- .../cqf/ruler/ExampleServerDstu3IT.java | 239 +++------------ plugin/case-reporting/pom.xml | 2 +- .../r4/MeasureDataProcessProvider.java | 61 ++-- .../r4/MeasureDataProcessProviderIT.java | 55 ++-- plugin/cds-hooks/pom.xml | 2 +- .../discovery/DiscoveryResolutionR4.java | 2 +- .../discovery/DiscoveryResolutionStu3.java | 2 +- .../ruler/cdshooks/dstu3/CdsHooksServlet.java | 7 +- .../ruler/cdshooks/r4/CdsHooksServlet.java | 7 +- plugin/cpg/pom.xml | 2 +- .../provider/LibraryEvaluationProvider.java | 36 +-- .../util/R4BundleLibraryContentProvider.java | 3 +- .../provider/LibraryEvaluationProviderIT.java | 26 +- plugin/cql/pom.xml | 2 +- .../cql/ElmCacheResourceChangeListener.java | 8 +- .../ruler/cql/JpaLibraryContentProvider.java | 4 +- .../cqf/ruler/cql/JpaTerminologyProvider.java | 6 +- .../{LibraryUtilities.java => Libraries.java} | 12 +- .../cqf/ruler/cql/LibraryUtilitiesTest.java | 2 +- plugin/cr/pom.xml | 2 +- .../org/opencds/cqf/ruler/cr/CrConfig.java | 7 +- .../provider/PlanDefinitionApplyProvider.java | 3 +- .../cqf/ruler/cr/r4/ExpressionEvaluation.java | 10 +- .../provider/PlanDefinitionApplyProvider.java | 3 +- .../cr/r4/provider/SubmitDataProvider.java | 89 ++++++ .../cr/dstu3/ExpressionEvaluationIT.java | 26 +- .../ActivityDefinitionApplyProviderIT.java | 20 +- .../PlanDefinitionApplyProviderIT.java | 26 +- .../ruler/cr/r4/ExpressionEvaluationIT.java | 33 +-- .../ActivityDefinitionApplyProviderIT.java | 23 +- .../provider/MeasureEvaluateProviderIT.java | 31 +- .../PlanDefinitionApplyProviderIT.java | 26 +- .../cr/r4/provider/SubmitDataProviderIT.java | 75 +++++ plugin/dev-tools/pom.xml | 2 +- .../dstu3/CacheValueSetsProvider.java | 6 +- .../dstu3/CodeSystemUpdateProvider.java | 6 +- .../devtools/r4/CacheValueSetsProvider.java | 6 +- .../devtools/r4/CodeSystemUpdateProvider.java | 6 +- .../dstu3/CacheValueSetsProviderIT.java | 45 +-- .../devtools/dstu3/CodeSystemProviderIT.java | 276 ++++++++---------- .../devtools/r4/CacheValueSetsProviderIT.java | 43 +-- .../devtools/r4/CodeSystemProviderIT.java | 70 ++--- .../cqf/ruler/hello/HelloWorldProviderIT.java | 7 +- plugin/pom.xml | 19 +- plugin/ra/pom.xml | 2 +- .../cqf/ruler/ra/r4/ReportProvider.java | 101 +++---- .../cqf/ruler/ra/r4/ReportProviderIT.java | 133 +++++---- plugin/sdc/pom.xml | 2 +- .../cqf/ruler/sdc/dstu3/ExtractProvider.java | 12 +- .../ruler/sdc/dstu3/TransformProvider.java | 6 +- .../cqf/ruler/sdc/r4/ExtractProvider.java | 12 +- .../cqf/ruler/sdc/r4/TransformProvider.java | 6 +- .../cqf/ruler/sdc/r4/ExtractProviderIT.java | 31 +- .../ruler/security/dstu3/OAuthProviderIT.java | 5 +- .../ruler/security/r4/OAuthProviderIT.java | 5 +- plugin/utility/README.md | 3 - plugin/utility/pom.xml | 11 - .../cqf/ruler/utility/CanonicalUtilities.java | 140 --------- .../cqf/ruler/utility/ExecutionUtilities.java | 43 --- .../cqf/ruler/utility/OperatorUtilities.java | 140 --------- .../cqf/ruler/utility/VersionUtilities.java | 89 ------ .../main/resources/META-INF/spring.factories | 0 .../ruler/utility/ClientUtilitiesTest.java | 72 ----- .../MultiTenantResolutionUtilitiesIT.java | 74 ----- .../ruler/utility/ResolutionUtilitiesIT.java | 160 ---------- pom.xml | 1 + server/pom.xml | 5 +- test/pom.xml | 24 +- .../cqf/ruler/test/DaoIntegrationTest.java | 26 ++ .../opencds/cqf/ruler/test/DaoOnlyConfig.java | 8 + ...{ITestSupport.java => ResourceLoader.java} | 90 +++--- .../cqf/ruler/test/RestIntegrationTest.java | 50 ++++ .../test/{ClientUtilities.java => Urls.java} | 12 +- ...ClientUtilitiesTest.java => UrlsTest.java} | 6 +- 99 files changed, 2096 insertions(+), 1842 deletions(-) create mode 100644 common/README.md create mode 100644 common/pom.xml create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/provider/DaoRegistryOperationProvider.java create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/Canonicals.java rename plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ClientUtilities.java => common/src/main/java/org/opencds/cqf/ruler/common/utility/Clients.java (68%) create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/DaoRegistryUser.java create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirContextUser.java create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirVersions.java rename {plugin/utility/src/main/java/org/opencds/cqf/ruler => common/src/main/java/org/opencds/cqf/ruler/common}/utility/HeaderInjectionInterceptor.java (96%) create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/IdCreator.java rename plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/IdUtilities.java => common/src/main/java/org/opencds/cqf/ruler/common/utility/Ids.java (65%) create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/Operations.java rename plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ReflectionUtilities.java => common/src/main/java/org/opencds/cqf/ruler/common/utility/Reflections.java (57%) rename {plugin/utility/src/main/java/org/opencds/cqf/ruler => common/src/main/java/org/opencds/cqf/ruler/common}/utility/ResolutionUtilities.java (97%) create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/ResourceCreator.java create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/Searches.java create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/TypedBundleProvider.java create mode 100644 common/src/main/java/org/opencds/cqf/ruler/common/utility/Versions.java create mode 100644 common/src/test/java/org/opencds/cqf/ruler/common/utility/ClientsTest.java create mode 100644 common/src/test/java/org/opencds/cqf/ruler/common/utility/FhirVersionsTest.java rename plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/IdUtilitiesTest.java => common/src/test/java/org/opencds/cqf/ruler/common/utility/IdsTest.java (72%) rename plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ReflectionUtilitiesTest.java => common/src/test/java/org/opencds/cqf/ruler/common/utility/ReflectionsTest.java (62%) rename plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/VersionUtilitiesTest.java => common/src/test/java/org/opencds/cqf/ruler/common/utility/VersionsTest.java (60%) rename plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/{LibraryUtilities.java => Libraries.java} (81%) create mode 100644 plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java create mode 100644 plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java delete mode 100644 plugin/utility/README.md delete mode 100644 plugin/utility/pom.xml delete mode 100644 plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/CanonicalUtilities.java delete mode 100644 plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ExecutionUtilities.java delete mode 100644 plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/OperatorUtilities.java delete mode 100644 plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/VersionUtilities.java delete mode 100644 plugin/utility/src/main/resources/META-INF/spring.factories delete mode 100644 plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ClientUtilitiesTest.java delete mode 100644 plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/MultiTenantResolutionUtilitiesIT.java delete mode 100644 plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ResolutionUtilitiesIT.java create mode 100644 test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java create mode 100644 test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java rename test/src/main/java/org/opencds/cqf/ruler/test/{ITestSupport.java => ResourceLoader.java} (52%) create mode 100644 test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java rename test/src/main/java/org/opencds/cqf/ruler/test/{ClientUtilities.java => Urls.java} (68%) rename test/src/test/java/org/opencds/cqf/ruler/test/{ClientUtilitiesTest.java => UrlsTest.java} (86%) diff --git a/.vscode/settings.json b/.vscode/settings.json index 2e592f8c4..aa3080041 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -18,7 +18,7 @@ "java", "json", "xml", - "md" + "markdown" ], "cSpell.ignorePaths": [ ".git/objects", @@ -31,6 +31,7 @@ "editor.formatOnSave": true }, "cSpell.words": [ + "DEQM", "Gson", "numer", "reindex" diff --git a/common/README.md b/common/README.md new file mode 100644 index 000000000..eb10079ea --- /dev/null +++ b/common/README.md @@ -0,0 +1,60 @@ +# Common + +This modules provides cross-cutting utility functions and base classes for cqf-ruler plugins. + +## Guidelines + +### Types of Utilities + +In general, reusable utilities are separated along two different dimensions, Classes and Behaviors. + +Class specific utilities are functions that are associated with specific class or interface, and add functionality to that class. + +Behavior specific utilities allow the reuse of behavior across many different classes. + +### Class Specific Utilities + +Utility or Helper methods that are associated with a single class should go into a class that has the pluralized name of the associated class. For example, utilities for `Client` should go into the `Clients` class. The ensures that the utility class is focused on one aspect and allows for more readable code: + +`Clients.forUrl("test.com")` + +as opposed to: + +`ClientUtilities.createClient("test.com")` + +or, if you put unrelated code into the class, you might end up with something like: + +`Clients.parseRegex()` + +If the code doesn't read clearly after you've added an utility, consider that it may not be in the right place. + +In general, all the functions for this type of utility should be `static`. No internal state should be maintained (`static final`, or immutable, state is ok). If you final that your utility class contains mutable state, consider an alternate design. + +Examples + +* Factory functions +* Adding behavior to a class you can't extend + +### Behavior Specific Utilities + +If there is behavior you'd like to share across many classes, model that as an interface and use a name that follows the pattern `"ThingDoer"`. For example, all the classes that access a database might be `DatabaseUser`. Use `default` interface implementations to write logic that can be shared many places. The interfaces themselves shouldn't have mutable state (again `static final` is ok). If it's necessary for the for shared logic to have access to state, model that as an method without a default implementation. For example: + +```java +interface DatabaseUser { + Database getDb(); + + default Entity read(Id id) { + return getDb().connect().find(id); + } +} +``` + +In the above example any class that has access to a `Database` can inherit the `read` behavior. + +Examples + +* Cross-cutting concerns + +### Discovery + +Following conventions such as these make it easier for the next developer to find code that's already been implemented as opposed to reinventing the wheel. diff --git a/common/pom.xml b/common/pom.xml new file mode 100644 index 000000000..3c5825681 --- /dev/null +++ b/common/pom.xml @@ -0,0 +1,44 @@ + + + 4.0.0 + + org.opencds.cqf.ruler + cqf-ruler + 0.5.0-SNAPSHOT + + + cqf-ruler-common + + + + org.opencds.cqf.ruler + cqf-ruler-external + 0.5.0-SNAPSHOT + + + org.opencds.cqf.ruler + cqf-ruler-core + 0.5.0-SNAPSHOT + + + javax.servlet + javax.servlet-api + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + + + + diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/provider/DaoRegistryOperationProvider.java b/common/src/main/java/org/opencds/cqf/ruler/common/provider/DaoRegistryOperationProvider.java new file mode 100644 index 000000000..bc8170dbf --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/provider/DaoRegistryOperationProvider.java @@ -0,0 +1,25 @@ +package org.opencds.cqf.ruler.common.provider; + +import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.common.utility.DaoRegistryUser; +import org.opencds.cqf.ruler.common.utility.FhirContextUser; +import org.springframework.beans.factory.annotation.Autowired; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; + +public class DaoRegistryOperationProvider implements OperationProvider, DaoRegistryUser, FhirContextUser { + @Autowired + private DaoRegistry myDaoRegistry; + + @Autowired + FhirContext myFhirContext; + + public FhirContext getFhirContext() { + return myFhirContext; + } + + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } +} diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Canonicals.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Canonicals.java new file mode 100644 index 000000000..d76a97b1a --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Canonicals.java @@ -0,0 +1,151 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +import ca.uhn.fhir.context.FhirVersionEnum; + +public class Canonicals { + + private Canonicals() { + } + + interface CanonicalParts { + String getVersion(); + + String getUrl(); + + IdType getId(); + } + + public static > String getId(CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.getValue() != null); + + return getId(theCanonicalType.getValue()); + } + + @SuppressWarnings("unchecked") + public static , IdType extends IIdType> IdType getIdElement( + CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.getValue() != null); + + String id = getId(theCanonicalType.getValue()); + String resourceName = getResourceName(theCanonicalType.getValue()); + + return (IdType) Ids.newId(theCanonicalType.getClass(), resourceName, id); + } + + public static > String getResourceName(CanonicalType canonicalType) { + if (canonicalType == null || !canonicalType.hasValue()) { + throw new IllegalArgumentException("CanonicalType must have a value for id extraction"); + } + + return getResourceName(canonicalType.getValue()); + } + + public static String getResourceName(String theCanonical) { + checkNotNull(theCanonical); + + if (!theCanonical.contains("/")) { + return null; + } + + theCanonical = theCanonical.replace(theCanonical.substring(theCanonical.lastIndexOf("/")), ""); + return theCanonical.contains("/") ? theCanonical.substring(theCanonical.lastIndexOf("/") + 1) : theCanonical; + } + + public static String getId(String theCanonical) { + checkNotNull(theCanonical); + + if (!theCanonical.contains("/")) { + return null; + } + + return theCanonical.contains("/") ? theCanonical.substring(theCanonical.lastIndexOf("/") + 1) : theCanonical; + } + + public static String getVersion(String theCanonical) { + checkNotNull(theCanonical); + + if (!theCanonical.contains("|")) { + return null; + } + + String[] urlParts = theCanonical.split("\\|"); + if (urlParts.length <= 1) { + return null; + } + + return urlParts[1]; + } + + public static String getUrl(String theCanonical) { + checkNotNull(theCanonical); + + if (!theCanonical.contains("|")) { + return theCanonical; + } + + String[] urlParts = theCanonical.split("\\|"); + return urlParts[0]; + } + + public static , IdType extends IIdType> CanonicalParts getCanonicalParts( + CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.getValue() != null, "theCanonicalType must have a value"); + + String version = getVersion(theCanonicalType.getValue()); + String url = getUrl(theCanonicalType.getValue()); + IdType id = getIdElement(theCanonicalType); + return new CanonicalParts() { + @Override + public String getVersion() { + return version; + } + + @Override + public IdType getId() { + return id; + } + + @Override + public String getUrl() { + return url; + } + }; + } + + public static CanonicalParts getCanonicalParts(FhirVersionEnum theFhirVersionEnum, + String theCanonical) { + checkNotNull(theFhirVersionEnum); + checkNotNull(theCanonical); + + String version = getVersion(theCanonical); + String url = getUrl(theCanonical); + String resourceType = getResourceName(theCanonical); + String id = getId(theCanonical); + IdType idElement = Ids.newId(theFhirVersionEnum, resourceType, id); + return new CanonicalParts() { + @Override + public String getVersion() { + return version; + } + + @Override + public IdType getId() { + return idElement; + } + + @Override + public String getUrl() { + return url; + } + }; + } +} diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ClientUtilities.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Clients.java similarity index 68% rename from plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ClientUtilities.java rename to common/src/main/java/org/opencds/cqf/ruler/common/utility/Clients.java index 4942b4e09..fd514319c 100644 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ClientUtilities.java +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Clients.java @@ -1,4 +1,6 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; import java.util.Arrays; import java.util.HashMap; @@ -15,10 +17,13 @@ import ca.uhn.fhir.rest.client.interceptor.BearerTokenAuthInterceptor; /** - * This interface provides utility functions for creating IGenericClients and + * This class provides utility functions for creating IGenericClients and * setting up authentication */ -public interface ClientUtilities { +public abstract class Clients { + + private Clients() { + } /** * Creates an IGenericClient for the given url. Defaults to NEVER @@ -28,8 +33,11 @@ public interface ClientUtilities { * @param theUrl the server base url to connect to * @return IGenericClient for the given url */ - default IGenericClient createClient(FhirVersionEnum theFhirVersionEnum, String theUrl) { - return createClient(FhirContext.forCached(theFhirVersionEnum), theUrl); + public static IGenericClient forUrl(FhirVersionEnum theFhirVersionEnum, String theUrl) { + checkNotNull(theFhirVersionEnum); + checkNotNull(theUrl); + + return forUrl(FhirContext.forCached(theFhirVersionEnum), theUrl); } /** @@ -40,8 +48,11 @@ default IGenericClient createClient(FhirVersionEnum theFhirVersionEnum, String t * @param theUrl the server base url to connect to * @return IGenericClient for the given url */ - default IGenericClient createClient(FhirContext theFhirContext, String theUrl) { - return createClient(theFhirContext, theUrl, ServerValidationModeEnum.NEVER); + public static IGenericClient forUrl(FhirContext theFhirContext, String theUrl) { + checkNotNull(theFhirContext); + checkNotNull(theUrl); + + return forUrl(theFhirContext, theUrl, ServerValidationModeEnum.NEVER); } /** @@ -52,9 +63,13 @@ default IGenericClient createClient(FhirContext theFhirContext, String theUrl) { * @param theServerValidationModeEnum the ServerValidationMode to use * @return IGenericClient for the given url, with the server validation mode set */ - default IGenericClient createClient(FhirVersionEnum theFhirVersionEnum, String theUrl, + public static IGenericClient forUrl(FhirVersionEnum theFhirVersionEnum, String theUrl, ServerValidationModeEnum theServerValidationModeEnum) { - return createClient(FhirContext.forCached(theFhirVersionEnum), theUrl, theServerValidationModeEnum); + checkNotNull(theFhirVersionEnum, "theFhirVersionEnum is required"); + checkNotNull(theUrl, "theUrl is required"); + checkNotNull(theServerValidationModeEnum, "theServerValidationModeEnum is required"); + + return forUrl(FhirContext.forCached(theFhirVersionEnum), theUrl, theServerValidationModeEnum); } /** @@ -66,8 +81,12 @@ default IGenericClient createClient(FhirVersionEnum theFhirVersionEnum, String t * @param theServerValidationModeEnum the ServerValidationMode to use * @return IGenericClient for the given url, with the server validation mode set */ - default IGenericClient createClient(FhirContext theFhirContext, String theUrl, + public static IGenericClient forUrl(FhirContext theFhirContext, String theUrl, ServerValidationModeEnum theServerValidationModeEnum) { + checkNotNull(theFhirContext); + checkNotNull(theUrl); + checkNotNull(theServerValidationModeEnum, "theServerValidationModeEnum is required"); + theFhirContext.getRestfulClientFactory().setServerValidationMode(theServerValidationModeEnum); return theFhirContext.newRestfulGenericClient(theUrl); } @@ -79,8 +98,10 @@ default IGenericClient createClient(FhirContext theFhirContext, String theUrl, * @return IGenericClient for the given Endpoint, with appropriate header * interceptors set up */ - default IGenericClient createClient(org.hl7.fhir.dstu3.model.Endpoint theEndpoint) { - return createClient(FhirContext.forDstu3Cached(), theEndpoint); + public static IGenericClient forEndpoint(org.hl7.fhir.dstu3.model.Endpoint theEndpoint) { + checkNotNull(theEndpoint); + + return forEndpoint(FhirContext.forDstu3Cached(), theEndpoint); } /** @@ -91,9 +112,12 @@ default IGenericClient createClient(org.hl7.fhir.dstu3.model.Endpoint theEndpoin * @return IGenericClient for the given Endpoint, with appropriate header * interceptors set up */ - default IGenericClient createClient(FhirContext theFhirContext, + public static IGenericClient forEndpoint(FhirContext theFhirContext, org.hl7.fhir.dstu3.model.Endpoint theEndpoint) { - IGenericClient client = createClient(theFhirContext, theEndpoint.getAddress()); + checkNotNull(theFhirContext); + checkNotNull(theEndpoint); + + IGenericClient client = forUrl(theFhirContext, theEndpoint.getAddress()); if (theEndpoint.hasHeader()) { List headerList = theEndpoint.getHeader().stream().map(headerString -> headerString.asStringValue()) .collect(Collectors.toList()); @@ -109,8 +133,10 @@ default IGenericClient createClient(FhirContext theFhirContext, * @return IGenericClient for the given Endpoint, with appropriate header * interceptors set up */ - default IGenericClient createClient(org.hl7.fhir.r4.model.Endpoint theEndpoint) { - return createClient(FhirContext.forR4Cached(), theEndpoint); + public static IGenericClient forEndpoint(org.hl7.fhir.r4.model.Endpoint theEndpoint) { + checkNotNull(theEndpoint); + + return forEndpoint(FhirContext.forR4Cached(), theEndpoint); } /** @@ -121,8 +147,11 @@ default IGenericClient createClient(org.hl7.fhir.r4.model.Endpoint theEndpoint) * @return IGenericClient for the given Endpoint, with appropriate header * interceptors set up */ - default IGenericClient createClient(FhirContext theFhirContext, org.hl7.fhir.r4.model.Endpoint theEndpoint) { - IGenericClient client = createClient(theFhirContext, theEndpoint.getAddress()); + public static IGenericClient forEndpoint(FhirContext theFhirContext, org.hl7.fhir.r4.model.Endpoint theEndpoint) { + checkNotNull(theFhirContext); + checkNotNull(theEndpoint); + + IGenericClient client = forUrl(theFhirContext, theEndpoint.getAddress()); if (theEndpoint.hasHeader()) { List headerList = theEndpoint.getHeader().stream().map(headerString -> headerString.asStringValue()) .collect(Collectors.toList()); @@ -138,8 +167,10 @@ default IGenericClient createClient(FhirContext theFhirContext, org.hl7.fhir.r4. * @return IGenericClient for the given Endpoint, with appropriate header * interceptors set up */ - default IGenericClient createClient(org.hl7.fhir.r5.model.Endpoint theEndpoint) { - return createClient(FhirContext.forR4Cached(), theEndpoint); + public static IGenericClient forEndpoint(org.hl7.fhir.r5.model.Endpoint theEndpoint) { + checkNotNull(theEndpoint, "theEndpoint is required"); + + return forEndpoint(FhirContext.forR4Cached(), theEndpoint); } /** @@ -150,8 +181,11 @@ default IGenericClient createClient(org.hl7.fhir.r5.model.Endpoint theEndpoint) * @return IGenericClient for the given Endpoint, with appropriate header * interceptors set up */ - default IGenericClient createClient(FhirContext theFhirContext, org.hl7.fhir.r5.model.Endpoint theEndpoint) { - IGenericClient client = createClient(theFhirContext, theEndpoint.getAddress()); + public static IGenericClient forEndpoint(FhirContext theFhirContext, org.hl7.fhir.r5.model.Endpoint theEndpoint) { + checkNotNull(theFhirContext); + checkNotNull(theEndpoint); + + IGenericClient client = forUrl(theFhirContext, theEndpoint.getAddress()); if (theEndpoint.hasHeader()) { List headerList = theEndpoint.getHeader().stream().map(headerString -> headerString.asStringValue()) .collect(Collectors.toList()); @@ -166,8 +200,10 @@ default IGenericClient createClient(FhirContext theFhirContext, org.hl7.fhir.r5. * @param theClient the client to add headers to * @param theHeaders an Array of Strings representing headers to add */ - default void registerHeaders(IGenericClient theClient, String... theHeaders) { - this.registerHeaders(theClient, Arrays.asList(theHeaders)); + public static void registerHeaders(IGenericClient theClient, String... theHeaders) { + checkNotNull(theClient); + + registerHeaders(theClient, Arrays.asList(theHeaders)); } /** @@ -176,7 +212,10 @@ default void registerHeaders(IGenericClient theClient, String... theHeaders) { * @param theClient the client to add headers to * @param theHeaderList a List of Strings representing headers to add */ - default void registerHeaders(IGenericClient theClient, List theHeaderList) { + public static void registerHeaders(IGenericClient theClient, List theHeaderList) { + checkNotNull(theClient); + checkNotNull(theHeaderList); + Map headerMap = setupHeaderMap(theHeaderList); for (Map.Entry entry : headerMap.entrySet()) { IClientInterceptor headInterceptor = new HeaderInjectionInterceptor(entry.getKey(), entry.getValue()); @@ -192,7 +231,9 @@ default void registerHeaders(IGenericClient theClient, List theHeaderLis * @param theUsername the username * @param thePassword the password */ - default void registerBasicAuth(IGenericClient theClient, String theUsername, String thePassword) { + public static void registerBasicAuth(IGenericClient theClient, String theUsername, String thePassword) { + checkNotNull(theClient, "theClient is required"); + if (theUsername != null) { BasicAuthInterceptor authInterceptor = new BasicAuthInterceptor(theUsername, thePassword); theClient.registerInterceptor(authInterceptor); @@ -206,7 +247,9 @@ default void registerBasicAuth(IGenericClient theClient, String theUsername, Str * @param theClient the client to register BearerToken authentication on * @param theToken the bearer token to register */ - default void registerBearerTokenAuth(IGenericClient theClient, String theToken) { + public static void registerBearerTokenAuth(IGenericClient theClient, String theToken) { + checkNotNull(theClient, "theClient is required"); + if (theToken != null) { BearerTokenAuthInterceptor authInterceptor = new BearerTokenAuthInterceptor(theToken); theClient.registerInterceptor(authInterceptor); @@ -220,7 +263,9 @@ default void registerBearerTokenAuth(IGenericClient theClient, String theToken) * @param theHeaderList a List of Strings representing headers to create * @return key-value pairs of headers */ - default Map setupHeaderMap(List theHeaderList) { + static Map setupHeaderMap(List theHeaderList) { + checkNotNull(theHeaderList, "theHeaderList is required"); + Map headerMap = new HashMap(); String leftAuth = null; String rightAuth = null; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/DaoRegistryUser.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/DaoRegistryUser.java new file mode 100644 index 000000000..f8c93a830 --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/DaoRegistryUser.java @@ -0,0 +1,133 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.hl7.fhir.instance.model.api.IBaseBundle; +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; + +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; +import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome; +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; +import ca.uhn.fhir.rest.api.server.IBundleProvider; +import ca.uhn.fhir.rest.api.server.RequestDetails; + +/** + * Simulate FhirDal operations until such time as that is fully baked + */ +public interface DaoRegistryUser { + + public DaoRegistry getDaoRegistry(); + + default T read(IIdType theId) { + checkNotNull(theId); + + return read(theId, null); + } + + @SuppressWarnings("unchecked") + default T read(IIdType theId, RequestDetails requestDetails) { + checkNotNull(theId); + + return (T) getDaoRegistry().getResourceDao(theId.getResourceType()).read(theId, requestDetails); + } + + default DaoMethodOutcome create(T theResource) { + checkNotNull(theResource); + + return create(theResource, null); + } + + @SuppressWarnings("unchecked") + default DaoMethodOutcome create(T theResource, RequestDetails requestDetails) { + checkNotNull(theResource); + + return ((IFhirResourceDao) getDaoRegistry().getResourceDao(theResource.fhirType())).create(theResource, + requestDetails); + } + + default DaoMethodOutcome update(T theResource) { + checkNotNull(theResource); + + return update(theResource, null); + } + + @SuppressWarnings("unchecked") + default DaoMethodOutcome update(T theResource, RequestDetails requestDetails) { + checkNotNull(theResource); + + return ((IFhirResourceDao) getDaoRegistry().getResourceDao(theResource.fhirType())).update(theResource, + requestDetails); + } + + default DaoMethodOutcome delete(T theResource) { + checkNotNull(theResource); + + return delete(theResource, null); + } + + @SuppressWarnings("unchecked") + default DaoMethodOutcome delete(T theResource, RequestDetails requestDetails) { + checkNotNull(theResource); + + return ((IFhirResourceDao) getDaoRegistry().getResourceDao(theResource.fhirType())) + .delete(theResource.getIdElement(), requestDetails); + } + + default DaoMethodOutcome delete(IIdType theIdType) { + checkNotNull(theIdType); + + return delete(theIdType, null); + } + + default DaoMethodOutcome delete(IIdType theIdType, RequestDetails requestDetails) { + checkNotNull(theIdType); + + return getDaoRegistry().getResourceDao(theIdType.getResourceType()).delete(theIdType, requestDetails); + } + + default T transaction(T theTransaction) { + checkNotNull(theTransaction); + + return transaction(theTransaction, null); + } + + @SuppressWarnings("unchecked") + default T transaction(T theTransaction, RequestDetails theRequestDetails) { + checkNotNull(theTransaction); + + return (T) getDaoRegistry().getSystemDao().transaction(theRequestDetails, theTransaction); + } + + default TypedBundleProvider search(Class theResourceClass, + SearchParameterMap theSearchMap) { + checkNotNull(theResourceClass); + checkNotNull(theSearchMap); + + return search(theResourceClass, theSearchMap, null); + } + + default TypedBundleProvider search(Class theResourceClass, SearchParameterMap theSearchMap, + RequestDetails theRequestDetails) { + checkNotNull(theResourceClass); + checkNotNull(theSearchMap); + + return TypedBundleProvider.fromBundleProvider(getDaoRegistry().getResourceDao(theResourceClass).search(theSearchMap, theRequestDetails)); + } + + default IBundleProvider search(String theResourceName, SearchParameterMap theSearchMap) { + checkNotNull(theResourceName); + checkNotNull(theSearchMap); + + return search(theResourceName, theSearchMap, null); + } + + default IBundleProvider search(String theResourceName, SearchParameterMap theSearchMap, + RequestDetails theRequestDetails) { + checkNotNull(theResourceName); + checkNotNull(theSearchMap); + + return getDaoRegistry().getResourceDao(theResourceName).search(theSearchMap); + } +} diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirContextUser.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirContextUser.java new file mode 100644 index 000000000..372fa7016 --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirContextUser.java @@ -0,0 +1,7 @@ +package org.opencds.cqf.ruler.common.utility; + +import ca.uhn.fhir.context.FhirContext; + +public interface FhirContextUser { + FhirContext getFhirContext(); +} diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirVersions.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirVersions.java new file mode 100644 index 000000000..e86d45fda --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirVersions.java @@ -0,0 +1,45 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.hl7.fhir.instance.model.api.IBase; + +import ca.uhn.fhir.context.FhirVersionEnum; + + +public class FhirVersions { + + private FhirVersions() { + } + + /** + * Returns a FhirVersionEnum for a given BaseType + * + * @param an IBase type + * @param theBaseTypeClass the class of the resource to get the version for + * @return the FhirVersionEnum corresponding to the theBaseTypeClass + */ + public static FhirVersionEnum forClass( + final Class theBaseTypeClass) { + checkNotNull(theBaseTypeClass); + + String packageName = theBaseTypeClass.getPackage().getName(); + if (packageName.contains("r5")) { + return FhirVersionEnum.R5; + } else if (packageName.contains("r4")) { + return FhirVersionEnum.R4; + } else if (packageName.contains("dstu3")) { + return FhirVersionEnum.DSTU3; + } else if (packageName.contains("dstu2016may")) { + return FhirVersionEnum.DSTU2_1; + } else if (packageName.contains("org.hl7.fhir.dstu2")) { + return FhirVersionEnum.DSTU2_HL7ORG; + } else if (packageName.contains("ca.uhn.fhir.model.dstu2")) { + return FhirVersionEnum.DSTU2; + } else { + throw new IllegalArgumentException(String.format( + "Unable to determine FHIR version for IBaseResource type: %s", theBaseTypeClass.getName())); + } + } + +} diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/HeaderInjectionInterceptor.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/HeaderInjectionInterceptor.java similarity index 96% rename from plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/HeaderInjectionInterceptor.java rename to common/src/main/java/org/opencds/cqf/ruler/common/utility/HeaderInjectionInterceptor.java index 7b3daa21a..9ad44edf1 100644 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/HeaderInjectionInterceptor.java +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/HeaderInjectionInterceptor.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; import java.io.IOException; import java.util.HashMap; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/IdCreator.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/IdCreator.java new file mode 100644 index 000000000..153269a33 --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/IdCreator.java @@ -0,0 +1,22 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; + +import org.hl7.fhir.instance.model.api.IIdType; + + +public interface IdCreator extends FhirContextUser { + + default T newId(String theResourceName, String theResourceId) { + checkNotNull(theResourceName); + checkNotNull(theResourceId); + + return Ids.newId(getFhirContext(), theResourceName, theResourceId); + } + + default T newId(String theResourceId) { + checkNotNull(theResourceId); + + return Ids.newId(getFhirContext(), theResourceId); + } +} diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/IdUtilities.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Ids.java similarity index 65% rename from plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/IdUtilities.java rename to common/src/main/java/org/opencds/cqf/ruler/common/utility/Ids.java index cc3bd77b9..65d2aabcb 100644 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/IdUtilities.java +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Ids.java @@ -1,4 +1,6 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; @@ -7,7 +9,10 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; -public interface IdUtilities extends ReflectionUtilities { +public class Ids { + + private Ids() {} + /** * Creates the appropriate IIdType for a given ResourceTypeClass * @@ -17,10 +22,13 @@ public interface IdUtilities extends ReflectionUtilities { * @param theId the String representation of the Id to generate * @return the id */ - default IdType createId( + public static IdType newId( Class theResourceTypeClass, String theId) { - FhirVersionEnum versionEnum = this.getFhirVersion(theResourceTypeClass); - return createId(versionEnum, theResourceTypeClass.getSimpleName(), theId); + checkNotNull(theResourceTypeClass); + checkNotNull(theId); + + FhirVersionEnum versionEnum = FhirVersions.forClass(theResourceTypeClass); + return newId(versionEnum, theResourceTypeClass.getSimpleName(), theId); } /** @@ -34,10 +42,14 @@ default IdType crea * @param theId the String representation of the Id to generate * @return the id */ - default IdType createId( + public static IdType newId( Class theBaseTypeClass, String theResourceName, String theId) { - FhirVersionEnum versionEnum = this.getFhirVersion(theBaseTypeClass); - return createId(versionEnum, theResourceName, theId); + checkNotNull(theBaseTypeClass); + checkNotNull(theResourceName); + checkNotNull(theId); + + FhirVersionEnum versionEnum = FhirVersions.forClass(theBaseTypeClass); + return newId(versionEnum, theResourceName, theId); } /** @@ -49,9 +61,13 @@ default IdType createId( * @param theId the String representation of the Id to generate * @return the id */ - default IdType createId(FhirContext theFhirContext, String theResourceType, + public static IdType newId(FhirContext theFhirContext, String theResourceType, String theId) { - return createId(theFhirContext.getVersion().getVersion(), theResourceType, theId); + checkNotNull(theFhirContext); + checkNotNull(theResourceType); + checkNotNull(theId); + + return newId(theFhirContext.getVersion().getVersion(), theResourceType, theId); } /** @@ -63,9 +79,13 @@ default IdType createId(FhirContext theFhirContext, Str * @param theId the String representation of the Id to generate * @return the id */ - default IdType createId(FhirVersionEnum theFhirVersionEnum, String theResourceType, + public static IdType newId(FhirVersionEnum theFhirVersionEnum, String theResourceType, String theId) { - return createId(theFhirVersionEnum, theResourceType + "/" + theId); + checkNotNull(theFhirVersionEnum); + checkNotNull(theResourceType); + checkNotNull(theId); + + return newId(theFhirVersionEnum, theResourceType + "/" + theId); } /** @@ -76,8 +96,11 @@ default IdType createId(FhirVersionEnum theFhirVersionE * @param theId the String representation of the Id to generate * @return the id */ - default IdType createId(FhirContext theFhirContext, String theId) { - return createId(theFhirContext.getVersion().getVersion(), theId); + public static IdType newId(FhirContext theFhirContext, String theId) { + checkNotNull(theFhirContext); + checkNotNull(theId); + + return newId(theFhirContext.getVersion().getVersion(), theId); } /** @@ -89,7 +112,10 @@ default IdType createId(FhirContext theFhirContext, Str * @return the id */ @SuppressWarnings("unchecked") - default IdType createId(FhirVersionEnum theFhirVersionEnum, String theId) { + public static IdType newId(FhirVersionEnum theFhirVersionEnum, String theId) { + checkNotNull(theFhirVersionEnum); + checkNotNull(theId); + switch (theFhirVersionEnum) { case DSTU2: return (IdType) new ca.uhn.fhir.model.primitive.IdDt(theId); diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Operations.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Operations.java new file mode 100644 index 000000000..d27568f2b --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Operations.java @@ -0,0 +1,79 @@ +package org.opencds.cqf.ruler.common.utility; + +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Date; +import java.util.List; +import java.util.TimeZone; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class provides utilities for implementing FHIR operations + */ +public class Operations { + + private Operations() {} + + Logger ourLog = LoggerFactory.getLogger(Operations.class); + + /** + * This function converts a string representation of a FHIR period date to a + * java.util.Date. + * + * @param date the date to convert + * @param start whether the date is the start of a period + * @return the FHIR period date as a java.util.Date type + */ + public static Date resolveRequestDate(String date, boolean start) { + // split it up - support dashes or slashes + String[] dissect = date.contains("-") ? date.split("-") : date.split("/"); + List dateVals = new ArrayList<>(); + for (String dateElement : dissect) { + dateVals.add(Integer.parseInt(dateElement)); + } + + if (dateVals.isEmpty()) { + throw new IllegalArgumentException("Invalid date"); + } + + // for now support dates up to day precision + Calendar calendar = Calendar.getInstance(); + calendar.clear(); + calendar.setTimeZone(TimeZone.getDefault()); + calendar.set(Calendar.YEAR, dateVals.get(0)); + if (dateVals.size() > 1) { + // java.util.Date months are zero based, hence the negative 1 -- 2014-01 == + // February 2014 + calendar.set(Calendar.MONTH, dateVals.get(1) - 1); + } + if (dateVals.size() > 2) + calendar.set(Calendar.DAY_OF_MONTH, dateVals.get(2)); + else { + if (start) { + calendar.set(Calendar.DAY_OF_MONTH, 1); + } else { + // get last day of month for end period + calendar.add(Calendar.MONTH, 1); + calendar.set(Calendar.DAY_OF_MONTH, 1); + calendar.add(Calendar.DATE, -1); + } + } + return calendar.getTime(); + } + + /** + * This function returns a fullUrl for a resource. + * + * @param serverAddress the address of the server + * @param fhirType the type of the resource + * @param elementId the id of the resource + * @return the FHIR period date as a java.util.Date type + */ + public static String getFullUrl(String serverAddress, String fhirType, String elementId) { + String fullUrl = String.format("%s%s/%s", serverAddress + (serverAddress.endsWith("/") ? "" : "/"), fhirType, + elementId); + return fullUrl; + } +} diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ReflectionUtilities.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Reflections.java similarity index 57% rename from plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ReflectionUtilities.java rename to common/src/main/java/org/opencds/cqf/ruler/common/utility/Reflections.java index b1c6df118..51a0dd32f 100644 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ReflectionUtilities.java +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Reflections.java @@ -1,4 +1,6 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; import java.util.List; import java.util.Optional; @@ -11,42 +13,17 @@ import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IAccessor; import ca.uhn.fhir.context.BaseRuntimeElementDefinition; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.RuntimeResourceDefinition; /** - * This interface provides utility methods for doing reflection on FHIR + * This class provides utility methods for doing reflection on FHIR * resources. It's specifically focused on knowledge artifact resources since * there's not a common interface for those across different Resources (and FHIR * versions) */ -public interface ReflectionUtilities { - /** - * Returns a FhirVersionEnum for a given BaseType - * - * @param an IBase type - * @param theBaseTypeClass the class of the resource to get the version for - * @return the FhirVersionEnum corresponding to the theBaseTypeClass - */ - default FhirVersionEnum getFhirVersion( - final Class theBaseTypeClass) { - String packageName = theBaseTypeClass.getPackage().getName(); - if (packageName.contains("r5")) { - return FhirVersionEnum.R5; - } else if (packageName.contains("r4")) { - return FhirVersionEnum.R4; - } else if (packageName.contains("dstu3")) { - return FhirVersionEnum.DSTU3; - } else if (packageName.contains("dstu2016may")) { - return FhirVersionEnum.DSTU2_1; - } else if (packageName.contains("org.hl7.fhir.dstu2")) { - return FhirVersionEnum.DSTU2_HL7ORG; - } else if (packageName.contains("ca.uhn.fhir.model.dstu2")) { - return FhirVersionEnum.DSTU2; - } else { - throw new IllegalArgumentException(String.format( - "Unable to determine FHIR version for IBaseResource type: %s", theBaseTypeClass.getName())); - } +public class Reflections { + + private Reflections() { } /** @@ -54,13 +31,16 @@ default FhirVersionEnum getFhirVersion( * * @param an IBase type * @param theBaseTypeClass the class of a the IBase type - * @param theChildName the name of the child property of the - * BaseType to generate an accessor for + * @param theChildName the name of the child property of the + * BaseType to generate an accessor for * @return an IAccessor for the given child and the BaseType */ - default IAccessor getAccessor( + public static IAccessor getAccessor( final Class theBaseTypeClass, String theChildName) { - FhirContext fhirContext = FhirContext.forCached(this.getFhirVersion(theBaseTypeClass)); + checkNotNull(theBaseTypeClass); + checkNotNull(theChildName); + + FhirContext fhirContext = FhirContext.forCached(FhirVersions.forClass(theBaseTypeClass)); if (theBaseTypeClass.isInstance(IBaseResource.class)) { @SuppressWarnings("unchecked") RuntimeResourceDefinition resourceDefinition = fhirContext @@ -77,16 +57,19 @@ default IAccessor getAccessor( * BaseType. * * @param an IBase type - * @param a return type for the Functions + * @param a return type for the Functions * @param theBaseTypeClass the class of a the IBase type - * @param theChildName to create a function for + * @param theChildName to create a function for * @return a function for accessing the "theChildName" property of the * BaseType */ @SuppressWarnings("unchecked") - default Function getPrimitiveFunction( + public static Function getPrimitiveFunction( final Class theBaseTypeClass, String theChildName) { - IAccessor accessor = this.getAccessor(theBaseTypeClass, theChildName); + checkNotNull(theBaseTypeClass); + checkNotNull(theChildName); + + IAccessor accessor = getAccessor(theBaseTypeClass, theChildName); return r -> { Optional value = accessor.getFirstValueOrNull(r); if (!value.isPresent()) { @@ -102,16 +85,19 @@ default Function getP * BaseType. * * @param an IBase type - * @param a return type for the Functions + * @param a return type for the Functions * @param theBaseTypeClass the class of a the IBase type - * @param theChildName to create a function for + * @param theChildName to create a function for * @return a function for accessing the "theChildName" property of the * BaseType */ @SuppressWarnings("unchecked") - default > Function getFunction( + public static > Function getFunction( final Class theBaseTypeClass, String theChildName) { - IAccessor accessor = this.getAccessor(theBaseTypeClass, theChildName); + checkNotNull(theBaseTypeClass); + checkNotNull(theChildName); + + IAccessor accessor = getAccessor(theBaseTypeClass, theChildName); return r -> { return (ReturnType) accessor.getValues(r); }; @@ -125,9 +111,11 @@ default > Funct * @param theBaseTypeClass the class of a the IBase type * @return a function for accessing the "version" property of the BaseType */ - default Function getVersionFunction( + public static Function getVersionFunction( final Class theBaseTypeClass) { - return this.getPrimitiveFunction(theBaseTypeClass, "version"); + checkNotNull(theBaseTypeClass); + + return getPrimitiveFunction(theBaseTypeClass, "version"); } /** @@ -137,9 +125,11 @@ default Function getVersionFunction( * @param theBaseTypeClass the class of a the IBase type * @return a function for accessing the "url" property of the BaseType */ - default Function getUrlFunction( + public static Function getUrlFunction( final Class theBaseTypeClass) { - return this.getPrimitiveFunction(theBaseTypeClass, "url"); + checkNotNull(theBaseTypeClass); + + return getPrimitiveFunction(theBaseTypeClass, "url"); } /** @@ -149,8 +139,10 @@ default Function getUrlFunction( * @param theBaseTypeClass the class of a the IBase type * @return a function for accessing the "name" property of the BaseType */ - default Function getNameFunction( + public static Function getNameFunction( final Class theBaseTypeClass) { - return this.getPrimitiveFunction(theBaseTypeClass, "name"); + checkNotNull(theBaseTypeClass); + + return getPrimitiveFunction(theBaseTypeClass, "name"); } } diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResolutionUtilities.java similarity index 97% rename from plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java rename to common/src/main/java/org/opencds/cqf/ruler/common/utility/ResolutionUtilities.java index dc789753f..67baec05f 100644 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResolutionUtilities.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; import java.util.List; @@ -20,7 +20,7 @@ * * TODO: Eventually we need FhirDal versions of these functions. */ -public interface ResolutionUtilities extends CanonicalUtilities, VersionUtilities { +public interface ResolutionUtilities { /** * Returns the Resource with a matching Id * @@ -152,7 +152,7 @@ default ResourceType resolveById( */ default ResourceType resolveById( IFhirResourceDao theResourceDao, String theId, RequestDetails theRequestDetails) { - IIdType id = this.createId(theResourceDao.getContext(), theId); + IIdType id = Ids.newId(theResourceDao.getContext(), theId); return this.resolveById(theResourceDao, id, theRequestDetails); } @@ -303,7 +303,7 @@ default ResourceType resolveByNameAndVersio List resources = (List) theResourceDao .search(SearchParameterMap.newSynchronous().add("name", new StringParam(theName))).getAllResources(); - return this.selectFromList(resources, theVersion, this.getVersionFunction(theResourceDao.getResourceType())); + return Versions.selectByVersion(resources, theVersion, Reflections.getVersionFunction(theResourceDao.getResourceType())); } /** @@ -374,14 +374,14 @@ default ResourceType resolveByCanonicalUrl( default ResourceType resolveByCanonicalUrl( IFhirResourceDao theResourceDao, String theUrl, RequestDetails theRequestDetails) { - String url = this.getUrl(theUrl); - String version = this.getVersion(theUrl); + String url = Canonicals.getUrl(theUrl); + String version = Canonicals.getVersion(theUrl); @SuppressWarnings("unchecked") List resources = (List) theResourceDao .search(SearchParameterMap.newSynchronous().add("url", new UriParam(url))).getAllResources(); - return this.selectFromList(resources, version, this.getVersionFunction(theResourceDao.getResourceType())); + return Versions.selectByVersion(resources, version, Reflections.getVersionFunction(theResourceDao.getResourceType())); } /** diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResourceCreator.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResourceCreator.java new file mode 100644 index 000000000..6171f791c --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResourceCreator.java @@ -0,0 +1,29 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; + +public interface ResourceCreator extends FhirContextUser { + @SuppressWarnings("unchecked") + default T newResource(I theId) { + checkNotNull(theId, "theId is required"); + checkArgument(theId.getResourceType() != null, "theId must have a resourceType"); + + IBaseResource newResource = this.getFhirContext().getResourceDefinition(theId.getResourceType()).newInstance(); + newResource.setId(theId); + return (T) newResource; + } + + @SuppressWarnings("unchecked") + default T newResource(Class theResourceClass, String theIdPart) { + checkNotNull(theResourceClass, "theResourceClass is required"); + checkNotNull(theIdPart, "theIdPart is required"); + + IBaseResource newResource = this.getFhirContext().getResourceDefinition(theResourceClass).newInstance(); + newResource.setId((I) Ids.newId(theResourceClass, theIdPart)); + return (T) newResource; + } +} diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Searches.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Searches.java new file mode 100644 index 000000000..74db5c2ba --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Searches.java @@ -0,0 +1,46 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; + +import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; +import ca.uhn.fhir.model.api.IQueryParameterType; +import ca.uhn.fhir.rest.param.StringParam; +import ca.uhn.fhir.rest.param.UriParam; + +public class Searches { + private Searches() { + } + + public static SearchParameterMap all() { + return sync(); + } + + public static SearchParameterMap sync() { + return SearchParameterMap.newSynchronous(); + } + + public static SearchParameterMap async() { + return new SearchParameterMap(); + } + + public static SearchParameterMap byParam(String theParamName, IQueryParameterType theParam) { + checkNotNull(theParamName); + checkNotNull(theParam); + + return SearchParameterMap.newSynchronous(theParamName, theParam); + } + + public static SearchParameterMap byName(String theName) { + checkNotNull(theName); + + return SearchParameterMap.newSynchronous("name", new StringParam(theName)); + } + + public static SearchParameterMap byUrl(String theUrl) { + checkNotNull(theUrl); + + String url = Canonicals.getUrl(theUrl); + + return SearchParameterMap.newSynchronous("url", new UriParam(url)); + } +} diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/TypedBundleProvider.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/TypedBundleProvider.java new file mode 100644 index 000000000..767b1ef80 --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/TypedBundleProvider.java @@ -0,0 +1,70 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.stream.Collectors; + +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + +import ca.uhn.fhir.context.ConfigurationException; +import ca.uhn.fhir.rest.api.server.IBundleProvider; + +public class TypedBundleProvider implements IBundleProvider { + + private IBundleProvider myInnerProvider; + + public static TypedBundleProvider fromBundleProvider(IBundleProvider theBundleProvider) { + return new TypedBundleProvider<>(theBundleProvider); + } + + private TypedBundleProvider(IBundleProvider theInnerProvider) { + myInnerProvider = checkNotNull(theInnerProvider); + } + + @Override + public IPrimitiveType getPublished() { + return myInnerProvider.getPublished(); + } + + @Override + public List getResources(int theFromIndex, int theToIndex) { + return myInnerProvider.getResources(theFromIndex, theToIndex); + } + + @Override + public String getUuid() { + return myInnerProvider.getUuid(); + } + + @Override + public Integer preferredPageSize() { + return myInnerProvider.preferredPageSize(); + } + + @Override + public Integer size() { + return myInnerProvider.size(); + } + + @SuppressWarnings("unchecked") + public List getResourcesTyped(int theFromIndex, int theToIndex) { + return myInnerProvider.getResources(theFromIndex, theToIndex).stream().map(x -> (T)x).collect(Collectors.toList()); + } + + public List getAllResourcesTyped() { + List retval = new ArrayList<>(); + + Integer size = size(); + if (size == null) { + throw new ConfigurationException("Attempt to request all resources from an asynchronous search result. The SearchParameterMap for this search probably should have been synchronous."); + } + if (size > 0) { + retval.addAll(getResourcesTyped(0, size)); + } + return retval; + } +} diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Versions.java b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Versions.java new file mode 100644 index 000000000..6e20fe5c2 --- /dev/null +++ b/common/src/main/java/org/opencds/cqf/ruler/common/utility/Versions.java @@ -0,0 +1,102 @@ +package org.opencds.cqf.ruler.common.utility; + +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.function.Function; + +import org.hl7.fhir.instance.model.api.IBaseResource; + +/** + * This class provides utilities for handling multiple business versions of FHIR + * Resources. + */ +public class Versions { + private Versions() { + } + + /** + * This function compares two versions using semantic versioning. + * + * @param version1 the first version to compare + * @param version2 the second version to compare + * @return 0 if versions are equal, 1 if version1 is greater than version2, and + * -1 otherwise + */ + public static int compareVersions(String version1, String version2) { + // Treat null as MAX VERSION + if (version1 == null && version2 == null) { + return 0; + } + + if (version1 != null && version2 == null) { + return -1; + } + + if (version1 == null) { + return 1; + } + + String[] string1Vals = version1.split("\\."); + String[] string2Vals = version2.split("\\."); + + int length = Math.max(string1Vals.length, string2Vals.length); + + for (int i = 0; i < length; i++) { + Integer v1 = i < string1Vals.length ? Integer.parseInt(string1Vals[i]) : 0; + Integer v2 = i < string2Vals.length ? Integer.parseInt(string2Vals[i]) : 0; + + // Making sure Version1 bigger than version2 + if (v1 > v2) { + return 1; + } + // Making sure Version1 smaller than version2 + else if (v1 < v2) { + return -1; + } + } + + // Both are equal + return 0; + } + + /*** + * Given a list of FHIR Resources that have the same name, choose the one with + * the matching version. + * + * @param an IBaseResource type + * @param theResources a list of Resources to select from + * @param theVersion the version of the Resource to select + * @param theGetVersion a function to access version information for the + * ResourceType + * @return the Resource with a matching version, or the highest version + * otherwise. + */ + public static ResourceType selectByVersion(List theResources, + String theVersion, + Function theGetVersion) { + checkNotNull(theResources); + checkNotNull(theVersion); + checkNotNull(theGetVersion); + + ResourceType library = null; + ResourceType maxVersion = null; + for (ResourceType l : theResources) { + String currentVersion = theGetVersion.apply(l); + if (theVersion == null && currentVersion == null || theVersion != null && theVersion.equals(currentVersion)) { + library = l; + } + + if (maxVersion == null || compareVersions(currentVersion, theGetVersion.apply(maxVersion)) >= 0) { + maxVersion = l; + } + } + + // If we were not given a version, return the highest found + if ((theVersion == null || library == null) && maxVersion != null) { + return maxVersion; + } + + return library; + } +} diff --git a/common/src/test/java/org/opencds/cqf/ruler/common/utility/ClientsTest.java b/common/src/test/java/org/opencds/cqf/ruler/common/utility/ClientsTest.java new file mode 100644 index 000000000..56d6b3a60 --- /dev/null +++ b/common/src/test/java/org/opencds/cqf/ruler/common/utility/ClientsTest.java @@ -0,0 +1,72 @@ +package org.opencds.cqf.ruler.common.utility; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Collections; +import java.util.List; + +import org.hl7.fhir.dstu3.model.Endpoint; +import org.hl7.fhir.dstu3.model.StringType; +import org.junit.jupiter.api.Test; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; + +public class ClientsTest { + @Test + public void testCreateClient() { + IGenericClient client = Clients.forUrl(FhirContext.forR4Cached(), "http://test.com"); + + assertNotNull(client); + assertEquals("http://test.com", client.getServerBase()); + } + + @Test + public void testRegisterAuth() { + IGenericClient client = Clients.forUrl(FhirContext.forR4Cached(), "http://test.com"); + Clients.registerBasicAuth(client, "user", "password"); + + List interceptors = client.getInterceptorService().getAllRegisteredInterceptors(); + + Object authInterceptor = interceptors.get(0); + assertTrue(authInterceptor instanceof BasicAuthInterceptor); + } + + @Test + public void testRegisterHeaders() { + IGenericClient client = Clients.forUrl(FhirContext.forR4Cached(), "http://test.com"); + Clients.registerHeaders(client, "Basic: XYZ123"); + + List interceptors = client.getInterceptorService().getAllRegisteredInterceptors(); + + Object interceptor = interceptors.get(0); + assertTrue(interceptor instanceof HeaderInjectionInterceptor); + } + + @Test + public void testRejectInvalidHeaders() { + IGenericClient client = Clients.forUrl(FhirContext.forR4Cached(), "http://test.com"); + assertThrows(IllegalArgumentException.class, () -> { + Clients.registerHeaders(client, "BasicXYZ123"); + }); + } + + @Test + public void testClientForEndpoint() { + Endpoint endpoint = new Endpoint(); + endpoint.setAddress("http://test.com"); + + endpoint.setHeader(Collections.singletonList(new StringType("Basic: XYZ123"))); + IGenericClient client = Clients.forEndpoint(endpoint); + + assertEquals("http://test.com", client.getServerBase()); + List interceptors = client.getInterceptorService().getAllRegisteredInterceptors(); + + Object interceptor = interceptors.get(0); + assertTrue(interceptor instanceof HeaderInjectionInterceptor); + } +} diff --git a/common/src/test/java/org/opencds/cqf/ruler/common/utility/FhirVersionsTest.java b/common/src/test/java/org/opencds/cqf/ruler/common/utility/FhirVersionsTest.java new file mode 100644 index 000000000..eec0d4871 --- /dev/null +++ b/common/src/test/java/org/opencds/cqf/ruler/common/utility/FhirVersionsTest.java @@ -0,0 +1,27 @@ +package org.opencds.cqf.ruler.common.utility; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.hl7.fhir.dstu3.model.Library; +import org.junit.jupiter.api.Test; + +import ca.uhn.fhir.context.FhirVersionEnum; + +public class FhirVersionsTest { + + @Test + public void testGetFhirVersion() { + FhirVersionEnum fhirVersion = FhirVersions.forClass(Library.class); + + assertEquals(FhirVersionEnum.DSTU3, fhirVersion); + } + + @Test + public void testGetFhirVersionUnknownClass() { + Library library = new Library(); + FhirVersionEnum fhirVersion = FhirVersions.forClass(library.getClass()); + + assertEquals(FhirVersionEnum.DSTU3, fhirVersion); + } + +} diff --git a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/IdUtilitiesTest.java b/common/src/test/java/org/opencds/cqf/ruler/common/utility/IdsTest.java similarity index 72% rename from plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/IdUtilitiesTest.java rename to common/src/test/java/org/opencds/cqf/ruler/common/utility/IdsTest.java index 5d4437315..ce830a1f3 100644 --- a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/IdUtilitiesTest.java +++ b/common/src/test/java/org/opencds/cqf/ruler/common/utility/IdsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -9,23 +9,23 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; -public class IdUtilitiesTest implements IdUtilities { +public class IdsTest { @Test public void testAllVersionsSupported() { for (FhirVersionEnum fhirVersionEnum : FhirVersionEnum.values()) { - this.createId(fhirVersionEnum, "Patient/123"); + Ids.newId(fhirVersionEnum, "Patient/123"); } } @Test public void testContextSupported() { - IIdType id = this.createId(FhirContext.forDstu3Cached(), "Patient/123"); + IIdType id = Ids.newId(FhirContext.forDstu3Cached(), "Patient/123"); assertTrue(id instanceof org.hl7.fhir.dstu3.model.IdType); } @Test public void testPartsSupported() { - IIdType id = this.createId(FhirVersionEnum.DSTU3, "Patient","123"); + IIdType id = Ids.newId(FhirVersionEnum.DSTU3, "Patient","123"); assertTrue(id instanceof org.hl7.fhir.dstu3.model.IdType); assertEquals("Patient", id.getResourceType()); @@ -34,7 +34,7 @@ public void testPartsSupported() { @Test public void testClassSupported() { - IIdType id = this.createId(org.hl7.fhir.dstu3.model.Library.class, "123"); + IIdType id = Ids.newId(org.hl7.fhir.dstu3.model.Library.class, "123"); assertTrue(id instanceof org.hl7.fhir.dstu3.model.IdType); assertEquals("Library", id.getResourceType()); assertEquals("123", id.getIdPart()); diff --git a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ReflectionUtilitiesTest.java b/common/src/test/java/org/opencds/cqf/ruler/common/utility/ReflectionsTest.java similarity index 62% rename from plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ReflectionUtilitiesTest.java rename to common/src/test/java/org/opencds/cqf/ruler/common/utility/ReflectionsTest.java index 8c26f7304..15bc94553 100644 --- a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ReflectionUtilitiesTest.java +++ b/common/src/test/java/org/opencds/cqf/ruler/common/utility/ReflectionsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; @@ -13,30 +13,14 @@ import org.junit.jupiter.api.Test; import ca.uhn.fhir.context.BaseRuntimeChildDefinition.IAccessor; -import ca.uhn.fhir.context.FhirVersionEnum; -public class ReflectionUtilitiesTest implements ReflectionUtilities { - - @Test - public void testGetFhirVersion() { - FhirVersionEnum fhirVersion = this.getFhirVersion(Library.class); - - assertEquals(FhirVersionEnum.DSTU3, fhirVersion); - } - - @Test - public void testGetFhirVersionUnknownClass() { - Library library = new Library(); - FhirVersionEnum fhirVersion = this.getFhirVersion(library.getClass()); - - assertEquals(FhirVersionEnum.DSTU3, fhirVersion); - } +public class ReflectionsTest { @Test public void testAccessor() { Library library = new Library().setName("test"); - IAccessor accessor = this.getAccessor(library.getClass(), "name"); + IAccessor accessor = Reflections.getAccessor(library.getClass(), "name"); Optional opt = accessor.getFirstValueOrNull(library); @@ -49,7 +33,7 @@ public void testAccessor() { public void testGetName() { Library library = new Library().setName("test"); - Function getName = this.getNameFunction(library.getClass()); + Function getName = Reflections.getNameFunction(library.getClass()); String name = getName.apply(library); @@ -60,7 +44,7 @@ public void testGetName() { public void testGetNameLiteral() { Library library = new Library().setName("test"); - Function getName = this.getNameFunction(Library.class); + Function getName = Reflections.getNameFunction(Library.class); String name = getName.apply(library); @@ -70,7 +54,7 @@ public void testGetNameLiteral() { @Test public void testGetNameNotExists() { assertThrows(RuntimeException.class, () -> { - this.getNameFunction(Observation.class); + Reflections.getNameFunction(Observation.class); }); } @@ -78,7 +62,7 @@ public void testGetNameNotExists() { public void testGetVersion() { Library library = new Library().setVersion("test"); - Function getVersion = this.getVersionFunction(library.getClass()); + Function getVersion = Reflections.getVersionFunction(library.getClass()); String version = getVersion.apply(library); @@ -89,7 +73,7 @@ public void testGetVersion() { public void testGetUrl() { Library library = new Library().setUrl("http://test.com"); - Function getVersion = this.getUrlFunction(library.getClass()); + Function getVersion = Reflections.getUrlFunction(library.getClass()); String version = getVersion.apply(library); diff --git a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/VersionUtilitiesTest.java b/common/src/test/java/org/opencds/cqf/ruler/common/utility/VersionsTest.java similarity index 60% rename from plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/VersionUtilitiesTest.java rename to common/src/test/java/org/opencds/cqf/ruler/common/utility/VersionsTest.java index ed33301e6..b018d92e4 100644 --- a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/VersionUtilitiesTest.java +++ b/common/src/test/java/org/opencds/cqf/ruler/common/utility/VersionsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.common.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -10,32 +10,32 @@ import org.hl7.fhir.dstu3.model.Library; import org.junit.jupiter.api.Test; -public class VersionUtilitiesTest implements VersionUtilities { +public class VersionsTest { @Test public void testVersionCompare() { - int result = this.compareVersions("1.0.0", "0.9.9"); + int result = Versions.compareVersions("1.0.0", "0.9.9"); assertEquals(1, result); - result = this.compareVersions("0.9.9", "1.0.0"); + result = Versions.compareVersions("0.9.9", "1.0.0"); assertEquals(-1, result); - result = this.compareVersions("1.0.0", "1.0.0"); + result = Versions.compareVersions("1.0.0", "1.0.0"); assertEquals(0, result); - result = this.compareVersions(null, null); + result = Versions.compareVersions(null, null); assertEquals(0, result); - result = this.compareVersions(null, "1.0.0"); + result = Versions.compareVersions(null, "1.0.0"); assertEquals(1, result); - result = this.compareVersions("1.0.0", null); + result = Versions.compareVersions("1.0.0", null); assertEquals(-1, result); - result = this.compareVersions("1.0", "0.0.9"); + result = Versions.compareVersions("1.0", "0.0.9"); assertEquals(1, result); - result = this.compareVersions("0", "1.1.2"); + result = Versions.compareVersions("0", "1.1.2"); assertEquals(-1, result); } @@ -46,11 +46,11 @@ public void testSelectFromList() { Function getVersion = l -> l.getVersion(); // Gets matching version - Library lib = this.selectFromList(libraries, "1.0.0", getVersion); + Library lib = Versions.selectByVersion(libraries, "1.0.0", getVersion); assertEquals("1.0.0", lib.getVersion()); // Gets max version (null is considering max version) - lib = this.selectFromList(libraries, "2.0.0", getVersion); + lib = Versions.selectByVersion(libraries, "2.0.0", getVersion); assertNull(lib.getVersion()); } } diff --git a/core/pom.xml b/core/pom.xml index 878058cb9..6a52f3109 100644 --- a/core/pom.xml +++ b/core/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -22,11 +23,80 @@ 0.5.0-SNAPSHOT - - org.opencds.cqf.ruler - cqf-ruler-test - 0.5.0-SNAPSHOT + ca.uhn.hapi.fhir + hapi-fhir-test-utilities + test + + + + com.h2database + h2 + test + + + + commons-io + commons-io + test + + + commons-validator + commons-validator + test + + + + org.apache.commons + commons-dbcp2 + + + commons-logging + commons-logging + + + test + + + + org.awaitility + awaitility + test + + + org.eclipse.jetty + jetty-server + test + + + org.eclipse.jetty + jetty-servlet + test + + + + org.eclipse.jetty + jetty-servlets + test + + + org.eclipse.jetty + jetty-util + test + + + org.eclipse.jetty + jetty-webapp + test + + + org.eclipse.jetty.websocket + websocket-server + test + + + org.junit.jupiter + junit-jupiter-api test @@ -35,5 +105,12 @@ spring-boot-starter-test test + + + org.springframework.boot + spring-boot-starter-web + test + + diff --git a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java index 30441cf6f..a021b9e60 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java +++ b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java @@ -1,220 +1,63 @@ package org.opencds.cqf.ruler; -import static ca.uhn.fhir.util.TestUtil.waitForSize; import static org.junit.jupiter.api.Assertions.assertEquals; -import java.io.File; -import java.io.IOException; -import java.net.URI; -import java.util.Collection; -import java.util.List; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; - -import org.apache.commons.io.FileUtils; -import org.eclipse.jetty.websocket.api.Session; -import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; -import org.eclipse.jetty.websocket.client.WebSocketClient; -import org.hl7.fhir.dstu3.model.Bundle; -import org.hl7.fhir.dstu3.model.MeasureReport; -import org.hl7.fhir.dstu3.model.Observation; -import org.hl7.fhir.dstu3.model.Parameters; import org.hl7.fhir.dstu3.model.Patient; -import org.hl7.fhir.dstu3.model.Subscription; import org.hl7.fhir.instance.model.api.IIdType; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.opencds.cqf.ruler.test.ITestSupport; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.core.io.ClassPathResource; import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.model.primitive.IdDt; -import ca.uhn.fhir.rest.api.CacheControlDirective; -import ca.uhn.fhir.rest.api.EncodingEnum; -import ca.uhn.fhir.rest.api.MethodOutcome; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; @ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = - { - "spring.datasource.url=jdbc:h2:mem:dbr3", - "hapi.fhir.fhir_version=dstu3", - "hapi.fhir.subscription.websocket_enabled=true", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.allow_placeholder_references=true", - }) - - -public class ExampleServerDstu3IT implements ITestSupport { - - private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class); - private IGenericClient ourClient; - private FhirContext ourCtx; - - @Autowired - DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - - @BeforeEach - void beforeEach() { - ourCtx = FhirContext.forCached(FhirVersionEnum.DSTU3); - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + port + "/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); - ourClient.registerInterceptor(new LoggingInterceptor(true)); - } - - @Test - public void testCreateAndRead() { - - String methodName = "testCreateResourceConditional"; - - Patient pt = new Patient(); - pt.addName().setFamily(methodName); - IIdType id = ourClient.create().resource(pt).execute().getId(); - - Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute(); - assertEquals(methodName, pt2.getName().get(0).getFamily()); - } - - // Currently fails with: - // ca.uhn.fhir.rest.server.exceptions.InternalErrorException: HTTP 500 : Failed to call access method: java.lang.IllegalArgumentException: Could not load library source for libraries referenced in Measure/Measure/measure-EXM104-FHIR3-8.1.000/_history/1. - //@Test - public void testCQLEvaluateMeasureEXM104() throws IOException { - String measureId = "measure-EXM104-FHIR3-8.1.000"; - - int numFilesLoaded = loadDataFromDirectory("dstu3/EXM104/EXM104_FHIR3-8.1.000-files"); - //assertEquals(numFilesLoaded, 3); - ourLog.info("{} files imported successfully!", numFilesLoaded); - //loadBundle("dstu3/EXM104/EXM104_FHIR3-8.1.000-bundle.json", ourCtx, ourClient); - - // http://localhost:8080/fhir/Measure/measure-EXM104-FHIR3-8.1.000/$evaluate-measure?periodStart=2019-01-01&periodEnd=2019-12-31 - Parameters inParams = new Parameters(); -// inParams.addParameter().setName("measure").setValue(new StringType("Measure/measure-EXM104-8.2.000")); -// inParams.addParameter().setName("patient").setValue(new StringType("Patient/numer-EXM104-FHIR3")); -// inParams.addParameter().setName("periodStart").setValue(new StringType("2019-01-01")); -// inParams.addParameter().setName("periodEnd").setValue(new StringType("2019-12-31")); - - Parameters outParams = ourClient - .operation() - .onInstance(new IdDt("Measure", measureId)) - .named("$evaluate-measure") - .withParameters(inParams) - .cacheControl(new CacheControlDirective().setNoCache(true)) - .withAdditionalHeader("Content-Type", "application/json") - .useHttpGet() - .execute(); - - List response = outParams.getParameter(); - Assertions.assertTrue(!response.isEmpty()); - Parameters.ParametersParameterComponent component = response.get(0); - Assertions.assertTrue(component.getResource() instanceof MeasureReport); - MeasureReport report = (MeasureReport) component.getResource(); - Assertions.assertEquals("Measure/"+measureId, report.getMeasure()); - } - - private int loadDataFromDirectory(String theDirectoryName) throws IOException { - int count = 0; - ourLog.info("Reading files in directory: {}", theDirectoryName); - ClassPathResource dir = new ClassPathResource(theDirectoryName); - Collection files = FileUtils.listFiles(dir.getFile(), null, false); - ourLog.info("{} files found.", files.size()); - for (File file : files) { - String filename = file.getAbsolutePath(); - ourLog.info("Processing filename '{}'", filename); - if (filename.endsWith(".cql") || filename.contains("expectedresults")) { - // Ignore .cql and expectedresults files - ourLog.info("Ignoring file: '{}'", filename); - } else if (filename.endsWith(".json")) { - if (filename.contains("bundle")) { - loadBundle(filename, ourCtx, ourClient); - } else { - loadResource(filename, ourCtx, myDaoRegistry); - } - count++; - } else { - ourLog.info("Ignoring file: '{}'", filename); - } - } - return count; - } - - private Bundle loadBundle(String theLocation, FhirContext theCtx, IGenericClient theClient) throws IOException { - String json = stringFromResource(theLocation); - Bundle bundle = (Bundle) theCtx.newJsonParser().parseResource(json); - Bundle result = theClient.transaction().withBundle(bundle).execute(); - return result; - } - - @Test - public void testWebsocketSubscription() throws Exception { - /* - * Create subscription - */ - Subscription subscription = new Subscription(); - subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); - subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED); - subscription.setCriteria("Observation?status=final"); - - Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent(); - channel.setType(Subscription.SubscriptionChannelType.WEBSOCKET); - channel.setPayload("application/json"); - subscription.setChannel(channel); - - MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute(); - IIdType mySubscriptionId = methodOutcome.getId(); - - // Wait for the subscription to be activated - waitForSize(1, () -> ourClient.search().forResource(Subscription.class).where(Subscription.STATUS.exactly().code("active")).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute().getEntry().size()); - - /* - * Attach websocket - */ - - WebSocketClient myWebSocketClient = new WebSocketClient(); - SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON); - - myWebSocketClient.start(); - URI echoUri = new URI("ws://localhost:" + port + "/websocket"); - ClientUpgradeRequest request = new ClientUpgradeRequest(); - ourLog.info("Connecting to : {}", echoUri); - Future connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request); - Session session = connection.get(2, TimeUnit.SECONDS); - - ourLog.info("Connected to WS: {}", session.isOpen()); - - /* - * Create a matching resource - */ - Observation obs = new Observation(); - obs.setStatus(Observation.ObservationStatus.FINAL); - ourClient.create().resource(obs).execute(); - - // Give some time for the subscription to deliver - Thread.sleep(2000); - - /* - * Ensure that we receive a ping on the websocket - */ - waitForSize(1, () -> mySocketImplementation.myPingCount); - - /* - * Clean up - */ - ourClient.delete().resourceById(mySubscriptionId).execute(); - } - +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = { + "spring.datasource.url=jdbc:h2:mem:dbr3", + "hapi.fhir.fhir_version=dstu3", + "hapi.fhir.subscription.websocket_enabled=true", + "hapi.fhir.allow_external_references=true", + "hapi.fhir.allow_placeholder_references=true", +}) + +public class ExampleServerDstu3IT { + private IGenericClient ourClient; + + @Autowired + private FhirContext ourCtx; + + @Autowired + DaoRegistry myDaoRegistry; + + @LocalServerPort + private int port; + + @BeforeEach + void beforeEach() { + ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); + String ourServerBase = "http://localhost:" + port + "/fhir/"; + ourClient = ourCtx.newRestfulGenericClient(ourServerBase); + ourClient.registerInterceptor(new LoggingInterceptor(true)); + } + + @Test + public void testCreateAndRead() { + + String methodName = "testCreateResourceConditional"; + + Patient pt = new Patient(); + pt.addName().setFamily(methodName); + IIdType id = ourClient.create().resource(pt).execute().getId(); + + Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute(); + assertEquals(methodName, pt2.getName().get(0).getFamily()); + } } diff --git a/plugin/case-reporting/pom.xml b/plugin/case-reporting/pom.xml index 194efad0f..3194f848a 100644 --- a/plugin/case-reporting/pom.xml +++ b/plugin/case-reporting/pom.xml @@ -16,7 +16,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java b/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java index 82d0b24d0..21bb31579 100644 --- a/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java +++ b/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java @@ -1,13 +1,11 @@ package org.opencds.cqf.ruler.casereporting.r4; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.rp.r4.MeasureResourceProvider; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; -import ca.uhn.fhir.model.valueset.BundleTypeEnum; -import ca.uhn.fhir.rest.annotation.Operation; -import ca.uhn.fhir.rest.annotation.OperationParam; -import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory; -import ca.uhn.fhir.rest.api.server.RequestDetails; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Composition; @@ -16,26 +14,23 @@ import org.hl7.fhir.r4.model.ListResource; import org.hl7.fhir.r4.model.MeasureReport; import org.hl7.fhir.r4.model.Reference; -import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.OperatorUtilities; +import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; +import org.opencds.cqf.ruler.common.utility.Searches; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; +import ca.uhn.fhir.jpa.rp.r4.MeasureResourceProvider; +import ca.uhn.fhir.model.valueset.BundleTypeEnum; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory; +import ca.uhn.fhir.rest.api.server.RequestDetails; -public class MeasureDataProcessProvider implements OperationProvider, ClientUtilities, OperatorUtilities { +public class MeasureDataProcessProvider extends DaoRegistryOperationProvider { private static final Logger logger = LoggerFactory.getLogger(MeasureDataProcessProvider.class); - @Autowired - private DaoRegistry myDaoRegistry; - @Autowired private MeasureResourceProvider measureResourceProvider; @@ -61,17 +56,12 @@ public Bundle extractLineListData(RequestDetails details, private void gatherEicrs(IVersionSpecificBundleFactory bundleFactory, Map populationSubjectListReferenceMap) { Map eicrs = new HashMap(); for (Map.Entry entry : populationSubjectListReferenceMap.entrySet()) { - // IQueryParameterType compositionReferenceParam = new ReferenceParam("subject", entry.getKey()); - SearchParameterMap map = SearchParameterMap.newSynchronous();//.add("composition", compositionReferenceParam); - logger.warn(map.toNormalizedQueryString(measureResourceProvider.getContext())); - List bundles = myDaoRegistry.getResourceDao(Bundle.class).search(map).getAllResources(); - for (IBaseResource baseBundle : bundles) { - if (baseBundle instanceof Bundle) { - Bundle bundle = (Bundle) baseBundle; + List bundles = search(Bundle.class, Searches.all()).getAllResourcesTyped(); + for (Bundle bundle : bundles) { if (bundle.hasEntry() && !bundle.getEntry().isEmpty() && bundle.hasType() && bundle.getType().equals(Bundle.BundleType.DOCUMENT)) { IBaseResource firstEntry = bundle.getEntry().get(0).getResource(); if (!(firstEntry instanceof Composition)) { - logger.debug(String.format("Any bundle of type document must have the first entry of type Composition, but found: %s", firstEntry.fhirType())); + logger.debug("Any bundle of type document must have the first entry of type Composition, but found: {}", firstEntry.fhirType()); } else { Composition composition = (Composition) firstEntry; String[] referenceSplit = composition.getSubject().getReference().split("/"); @@ -82,12 +72,9 @@ private void gatherEicrs(IVersionSpecificBundleFactory bundleFactory, Map getPatientListFromGroup(String subjectGroupRef) { List patientList = new ArrayList<>(); - IBaseResource baseGroup = myDaoRegistry.getResourceDao("Group").read(new IdType(subjectGroupRef)); - if (baseGroup == null) { - throw new RuntimeException("Could not find Group/" + subjectGroupRef); - } - Group group = (Group) baseGroup; + Group group = read(new IdType(subjectGroupRef)); group.getMember().forEach(member -> { Reference reference = member.getEntity(); if (reference.getReferenceElement().getResourceType().equals("Patient")) { @@ -149,9 +132,9 @@ private List getSubjectResultsFromList(Reference subjectResults) { logger.debug("No subject results found."); return results; } - IBaseResource baseList = myDaoRegistry.getResourceDao(subjectResults.getReferenceElement().getResourceType()).read(subjectResults.getReferenceElement()); + IBaseResource baseList = read(subjectResults.getReferenceElement()); if (baseList == null) { - logger.debug(String.format("No subject results found for: %s", subjectResults.getReference())); + logger.debug("No subject results found for: {}", subjectResults.getReference()); return results; } if (!(baseList instanceof ListResource)) { diff --git a/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java b/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java index f11e2fa34..ee99fb440 100644 --- a/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java +++ b/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java @@ -12,38 +12,47 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.casereporting.CaseReportingConfig; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.ResourceLoader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, - CaseReportingConfig.class }, properties = { "hapi.fhir.fhir_version=r4", - "spring.main.allow-bean-definition-overriding=true", - "debug=true", - "spring.batch.job.enabled=false"}) -public class MeasureDataProcessProviderIT implements ITestSupport { + CaseReportingConfig.class }, properties = { "hapi.fhir.fhir_version=r4", + "spring.main.allow-bean-definition-overriding=true", + "debug=true", + "spring.batch.job.enabled=false" }) +public class MeasureDataProcessProviderIT implements ResourceLoader { private IGenericClient ourClient; + + @Autowired private FhirContext ourCtx; @Autowired - private DaoRegistry ourRegistry; + DaoRegistry myDaoRegistry; @LocalServerPort private int port; + @Override + public FhirContext getFhirContext() { + return ourCtx; + } + + @Override + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } + @BeforeEach void beforeEach() { - - ourCtx = FhirContext.forCached(FhirVersionEnum.R4); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); String ourServerBase = "http://localhost:" + port + "/fhir/"; @@ -55,15 +64,16 @@ void beforeEach() { public void testMeasureReportExtractLineListData() throws IOException { String packagePrefix = "org/opencds/cqf/ruler/casereporting/r4/"; - loadResource(packagePrefix + "Patient-ra-patient01.json", ourCtx, ourRegistry); - loadResource(packagePrefix + "Patient-ra-patient02.json", ourCtx, ourRegistry); - loadResource(packagePrefix + "Patient-ra-patient03.json", ourCtx, ourRegistry); - loadResource( packagePrefix + "Group-ra-group00.json", ourCtx, ourRegistry); - loadResource( packagePrefix + "Group-ra-group01.json", ourCtx, ourRegistry); - loadResource( packagePrefix + "Group-ra-group02.json", ourCtx, ourRegistry); - loadResource( packagePrefix + "MeasureReport-ra-measurereport01.json", ourCtx, ourRegistry); + loadResource(packagePrefix + "Patient-ra-patient01.json"); + loadResource(packagePrefix + "Patient-ra-patient02.json"); + loadResource(packagePrefix + "Patient-ra-patient03.json"); + loadResource(packagePrefix + "Group-ra-group00.json"); + loadResource(packagePrefix + "Group-ra-group01.json"); + loadResource(packagePrefix + "Group-ra-group02.json"); + loadResource(packagePrefix + "MeasureReport-ra-measurereport01.json"); - MeasureReport measureReport = ourClient.read().resource(MeasureReport.class).withId("ra-measurereport01").execute(); + MeasureReport measureReport = ourClient.read().resource(MeasureReport.class).withId("ra-measurereport01") + .execute(); assertNotNull(measureReport); @@ -71,12 +81,11 @@ public void testMeasureReportExtractLineListData() throws IOException { params.addParameter().setName("measureReport").setResource(measureReport); params.addParameter().setName("subjectList").setValue(null); - Bundle returnBundle = ourClient.operation().onType(MeasureReport.class) - .named("$extract-line-list-data") - .withParameters(params) - .returnResourceType(Bundle.class) - .execute(); + .named("$extract-line-list-data") + .withParameters(params) + .returnResourceType(Bundle.class) + .execute(); assertNotNull(returnBundle); } diff --git a/plugin/cds-hooks/pom.xml b/plugin/cds-hooks/pom.xml index 37b1fc328..e540e0f7c 100644 --- a/plugin/cds-hooks/pom.xml +++ b/plugin/cds-hooks/pom.xml @@ -26,7 +26,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java index 106a0dc1b..5af605505 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java @@ -11,7 +11,7 @@ import org.hl7.fhir.r4.model.Library; import org.hl7.fhir.r4.model.PlanDefinition; import org.hl7.fhir.r4.model.ValueSet; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java index 1ef1c41a3..3fbc25c37 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java @@ -10,7 +10,7 @@ import org.hl7.fhir.dstu3.model.PlanDefinition; import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java index 6d9dbeefa..3202ef370 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java @@ -34,7 +34,6 @@ import org.opencds.cqf.cql.engine.model.ModelResolver; import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; -import org.opencds.cqf.ruler.external.AppProperties; import org.opencds.cqf.ruler.cdshooks.discovery.DiscoveryResolutionStu3; import org.opencds.cqf.ruler.cdshooks.evaluation.EvaluationContext; import org.opencds.cqf.ruler.cdshooks.evaluation.Stu3EvaluationContext; @@ -45,14 +44,14 @@ import org.opencds.cqf.ruler.cdshooks.request.JsonHelper; import org.opencds.cqf.ruler.cdshooks.request.Request; import org.opencds.cqf.ruler.cdshooks.response.CdsCard; +import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cql.JpaDataProviderFactory; import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; import org.opencds.cqf.ruler.cql.JpaTerminologyProviderFactory; import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; import org.opencds.cqf.ruler.cr.dstu3.provider.PlanDefinitionApplyProvider; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.external.AppProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -65,7 +64,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -public class CdsHooksServlet extends HttpServlet implements ClientUtilities, ResolutionUtilities { +public class CdsHooksServlet extends HttpServlet implements ResolutionUtilities { private static final long serialVersionUID = 1L; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java index d3fe9582e..d3c2750da 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java @@ -34,7 +34,6 @@ import org.opencds.cqf.cql.engine.model.ModelResolver; import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; -import org.opencds.cqf.ruler.external.AppProperties; import org.opencds.cqf.ruler.cdshooks.discovery.DiscoveryResolutionR4; import org.opencds.cqf.ruler.cdshooks.evaluation.EvaluationContext; import org.opencds.cqf.ruler.cdshooks.evaluation.R4EvaluationContext; @@ -45,14 +44,14 @@ import org.opencds.cqf.ruler.cdshooks.request.JsonHelper; import org.opencds.cqf.ruler.cdshooks.request.Request; import org.opencds.cqf.ruler.cdshooks.response.CdsCard; +import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cql.JpaDataProviderFactory; import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; import org.opencds.cqf.ruler.cql.JpaTerminologyProviderFactory; import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; import org.opencds.cqf.ruler.cr.r4.provider.PlanDefinitionApplyProvider; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.external.AppProperties; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -65,7 +64,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -public class CdsHooksServlet extends HttpServlet implements ClientUtilities, ResolutionUtilities { +public class CdsHooksServlet extends HttpServlet implements ResolutionUtilities { private static final long serialVersionUID = 1L; diff --git a/plugin/cpg/pom.xml b/plugin/cpg/pom.xml index 11fd2a09b..8a641d01a 100644 --- a/plugin/cpg/pom.xml +++ b/plugin/cpg/pom.xml @@ -16,7 +16,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java b/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java index a1381faf3..fb120a09e 100644 --- a/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java +++ b/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java @@ -35,7 +35,9 @@ import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; import org.opencds.cqf.cql.evaluator.engine.retrieve.BundleRetrieveProvider; import org.opencds.cqf.cql.evaluator.engine.retrieve.PriorityRetrieveProvider; -import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; +import org.opencds.cqf.ruler.common.utility.Clients; +import org.opencds.cqf.ruler.common.utility.Operations; import org.opencds.cqf.ruler.cpg.r4.util.FhirMeasureBundler; import org.opencds.cqf.ruler.cpg.r4.util.R4ApelonFhirTerminologyProvider; import org.opencds.cqf.ruler.cpg.r4.util.R4BundleLibraryContentProvider; @@ -44,14 +46,10 @@ import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; import org.opencds.cqf.ruler.cql.JpaTerminologyProviderFactory; import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.OperatorUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; @@ -59,13 +57,10 @@ import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.client.api.IGenericClient; -public class LibraryEvaluationProvider implements OperationProvider, ClientUtilities, OperatorUtilities { +public class LibraryEvaluationProvider extends DaoRegistryOperationProvider { private static final Logger log = LoggerFactory.getLogger(LibraryEvaluationProvider.class); - @Autowired - private DaoRegistry myDaoRegistry; - @Autowired private CqlProperties myCqlProperties; @@ -81,9 +76,6 @@ public class LibraryEvaluationProvider implements OperationProvider, ClientUtili @Autowired ModelResolver myModelResolver; - @Autowired - FhirContext myFhirContext; - @SuppressWarnings({ "unchecked" }) @Operation(name = "$evaluate", idempotent = true, type = Library.class) public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId") String patientId, @@ -118,7 +110,7 @@ public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId" } if (theResource == null) { - theResource = this.resolveById(myDaoRegistry, Library.class, theId, theRequestDetails); + theResource = read(theId, theRequestDetails); } VersionedIdentifier libraryIdentifier = new VersionedIdentifier().withId(theResource.getName()) @@ -127,7 +119,7 @@ public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId" TerminologyProvider terminologyProvider; if (terminologyEndpoint != null) { - IGenericClient client = this.createClient(myFhirContext, terminologyEndpoint); + IGenericClient client = Clients.forEndpoint(getFhirContext(), terminologyEndpoint); if (terminologyEndpoint.getAddress().contains("apelon")) { terminologyProvider = new R4ApelonFhirTerminologyProvider(client); } else { @@ -140,8 +132,8 @@ public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId" DataProvider dataProvider; if (dataEndpoint != null) { List retrieveProviderList = new ArrayList<>(); - IGenericClient client = this.createClient(myFhirContext, dataEndpoint); - RestFhirRetrieveProvider retriever = new RestFhirRetrieveProvider(new SearchParameterResolver(myFhirContext), + IGenericClient client = Clients.forEndpoint(dataEndpoint); + RestFhirRetrieveProvider retriever = new RestFhirRetrieveProvider(new SearchParameterResolver(getFhirContext()), client); retriever.setTerminologyProvider(terminologyProvider); if (terminologyEndpoint == null || (terminologyEndpoint != null @@ -151,7 +143,7 @@ public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId" retrieveProviderList.add(retriever); if (additionalData != null) { - BundleRetrieveProvider bundleProvider = new BundleRetrieveProvider(myFhirContext, additionalData); + BundleRetrieveProvider bundleProvider = new BundleRetrieveProvider(getFhirContext(), additionalData); bundleProvider.setTerminologyProvider(terminologyProvider); retrieveProviderList.add(bundleProvider); PriorityRetrieveProvider priorityProvider = new PriorityRetrieveProvider(retrieveProviderList); @@ -162,8 +154,8 @@ public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId" } else { List retrieveProviderList = new ArrayList<>(); - JpaFhirRetrieveProvider retriever = new JpaFhirRetrieveProvider(this.myDaoRegistry, - new SearchParameterResolver(myFhirContext)); + JpaFhirRetrieveProvider retriever = new JpaFhirRetrieveProvider(getDaoRegistry(), + new SearchParameterResolver(getFhirContext())); retriever.setTerminologyProvider(terminologyProvider); // Assume it's a different server, therefore need to expand. if (terminologyEndpoint != null) { @@ -172,7 +164,7 @@ public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId" retrieveProviderList.add(retriever); if (additionalData != null) { - BundleRetrieveProvider bundleProvider = new BundleRetrieveProvider(myFhirContext, additionalData); + BundleRetrieveProvider bundleProvider = new BundleRetrieveProvider(getFhirContext(), additionalData); bundleProvider.setTerminologyProvider(terminologyProvider); retrieveProviderList.add(bundleProvider); PriorityRetrieveProvider priorityProvider = new PriorityRetrieveProvider(retrieveProviderList); @@ -203,8 +195,8 @@ public Bundle evaluate(@IdParam IdType theId, @OperationParam(name = "patientId" if (periodStart != null && periodEnd != null) { // resolve the measurement period - Interval measurementPeriod = new Interval(this.resolveRequestDate(periodStart, true), true, - this.resolveRequestDate(periodEnd, false), true); + Interval measurementPeriod = new Interval(Operations.resolveRequestDate(periodStart, true), true, + Operations.resolveRequestDate(periodEnd, false), true); resolvedParameters.put("Measurement Period", new Interval(DateTime.fromJavaDate((Date) measurementPeriod.getStart()), true, diff --git a/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/util/R4BundleLibraryContentProvider.java b/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/util/R4BundleLibraryContentProvider.java index c3758a6a2..551899718 100644 --- a/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/util/R4BundleLibraryContentProvider.java +++ b/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/util/R4BundleLibraryContentProvider.java @@ -10,11 +10,10 @@ import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent; import org.hl7.fhir.r4.model.Library; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentType; -import org.opencds.cqf.ruler.utility.VersionUtilities; // TODO: Add support for ELM -public class R4BundleLibraryContentProvider implements VersionUtilities, org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider { +public class R4BundleLibraryContentProvider implements org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider { Bundle bundle; public R4BundleLibraryContentProvider(Bundle bundle) { diff --git a/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java b/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java index de33141c1..67c881aef 100644 --- a/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java +++ b/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java @@ -15,14 +15,13 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cpg.CpgConfig; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.ResourceLoader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; @@ -34,25 +33,34 @@ "spring.main.allow-bean-definition-overriding=true", "debug=true", "spring.batch.job.enabled=false"}) -public class LibraryEvaluationProviderIT implements ITestSupport { +public class LibraryEvaluationProviderIT implements ResourceLoader { private IGenericClient ourClient; + + @Autowired private FhirContext ourCtx; @Autowired - private DaoRegistry ourRegistry; + DaoRegistry myDaoRegistry; @LocalServerPort private int port; + @Override + public FhirContext getFhirContext() { + return ourCtx; + } + + @Override + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } + @BeforeEach void beforeEach() { - - ourCtx = FhirContext.forCached(FhirVersionEnum.R4); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); String ourServerBase = "http://localhost:" + port + "/fhir/"; ourClient = ourCtx.newRestfulGenericClient(ourServerBase); - } @Test @@ -65,7 +73,7 @@ public void testLibraryEvaluationValidationThrows() throws IOException { params.addParameter().setName("context").setValue(new StringType("Patient")); String packagePrefix = "org/opencds/cqf/ruler/cpg/r4/provider/"; - loadResource(packagePrefix + "ColorectalCancerScreeningsFHIR.json", ourCtx, ourRegistry); + loadResource(packagePrefix + "ColorectalCancerScreeningsFHIR.json"); Library lib = ourClient.read().resource(Library.class).withId("ColorectalCancerScreeningsFHIR").execute(); assertNotNull(lib); @@ -82,7 +90,7 @@ public void testLibraryEvaluationValidationThrows() throws IOException { public void testLibraryEvaluationValidData() throws IOException { String packagePrefix = "org/opencds/cqf/ruler/cpg/r4/provider/"; - loadResource(packagePrefix + "ColorectalCancerScreeningsFHIR.json", ourCtx, ourRegistry); + loadResource(packagePrefix + "ColorectalCancerScreeningsFHIR.json"); String bundleTextValueSets = stringFromResource(packagePrefix + "valuesets-ColorectalCancerScreeningsFHIR-bundle.json"); FhirContext fhirContext = FhirContext.forR4(); diff --git a/plugin/cql/pom.xml b/plugin/cql/pom.xml index 6963baf46..b3094a25f 100644 --- a/plugin/cql/pom.xml +++ b/plugin/cql/pom.xml @@ -15,7 +15,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java index 3574e2324..3dfa0c793 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java @@ -9,13 +9,13 @@ import org.cqframework.cql.elm.execution.VersionedIdentifier; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; -import org.opencds.cqf.ruler.utility.ReflectionUtilities; +import org.opencds.cqf.ruler.common.utility.Reflections; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.cache.IResourceChangeEvent; import ca.uhn.fhir.jpa.cache.IResourceChangeListener; -public class ElmCacheResourceChangeListener implements IResourceChangeListener, ReflectionUtilities { +public class ElmCacheResourceChangeListener implements IResourceChangeListener { private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory .getLogger(ElmCacheResourceChangeListener.class); @@ -29,8 +29,8 @@ public ElmCacheResourceChangeListener(IFhirResourceDao theLibraryDao, Map theGlobalLibraryCache) { this.myLibraryDao = theLibraryDao; this.myGlobalLibraryCache = theGlobalLibraryCache; - this.myNameFunction = this.getNameFunction(theLibraryDao.getResourceType()); - this.myVersionFunction = this.getVersionFunction(theLibraryDao.getResourceType()); + this.myNameFunction = Reflections.getNameFunction(theLibraryDao.getResourceType()); + this.myVersionFunction = Reflections.getVersionFunction(theLibraryDao.getResourceType()); } @Override diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java index 2f57fad69..48fb26a14 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java @@ -8,13 +8,13 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentType; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.rest.api.server.RequestDetails; public class JpaLibraryContentProvider - implements LibraryContentProvider, ResolutionUtilities, LibraryUtilities { + implements LibraryContentProvider, ResolutionUtilities, Libraries { private static Map, ContentFunctions> cachedContentFunctions = new HashMap<>(); protected final IFhirResourceDao libraryDao; diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java index caea7012f..11ed530ea 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java @@ -8,7 +8,7 @@ import org.opencds.cqf.cql.engine.terminology.CodeSystemInfo; import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.engine.terminology.ValueSetInfo; -import org.opencds.cqf.ruler.utility.IdUtilities; +import org.opencds.cqf.ruler.common.utility.Ids; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; @@ -28,7 +28,7 @@ * interface, which is used for Terminology operations * in CQL */ -public class JpaTerminologyProvider implements TerminologyProvider, IdUtilities { +public class JpaTerminologyProvider implements TerminologyProvider { private final ITermReadSvc myTerminologySvc; private final DaoRegistry myDaoRegistry; @@ -99,7 +99,7 @@ public Iterable expand(ValueSetInfo valueSet) throws ResourceNotFoundExcep throw new IllegalArgumentException("Found more than 1 ValueSet with url: " + valueSet.getId()); } } else { - vs = myValueSetDao.read(this.createId(this.myTerminologySvc.getFhirContext(), valueSet.getId()), + vs = myValueSetDao.read(Ids.newId(this.myTerminologySvc.getFhirContext(), valueSet.getId()), myRequestDetails); if (vs == null) { throw new IllegalArgumentException(String.format("Could not resolve value set %s.", valueSet.getId())); diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/LibraryUtilities.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java similarity index 81% rename from plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/LibraryUtilities.java rename to plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java index ae9886fd0..dbe56e63b 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/LibraryUtilities.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java @@ -6,11 +6,11 @@ import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.utility.ReflectionUtilities; +import org.opencds.cqf.ruler.common.utility.Reflections; import ca.uhn.fhir.context.FhirContext; -public interface LibraryUtilities extends ReflectionUtilities { +public interface Libraries { default byte[] getContent(IBaseResource library, ContentFunctions contentFunctions, String contentType) { Objects.requireNonNull(library, "library can not be null"); @@ -42,12 +42,10 @@ default ContentFunctions getContentFunctions(IBaseResource library) { } default ContentFunctions getContentFunctions(FhirContext fhirContext) { - Function> attachments = this - .getFunction(fhirContext.getResourceDefinition("Library").getImplementingClass(), "content"); - Function contentType = this.getPrimitiveFunction( + Function> attachments = Reflections.getFunction(fhirContext.getResourceDefinition("Library").getImplementingClass(), "content"); + Function contentType = Reflections.getPrimitiveFunction( fhirContext.getElementDefinition("Attachment").getImplementingClass(), "contentType"); - Function content = this - .getPrimitiveFunction(fhirContext.getElementDefinition("Attachment").getImplementingClass(), "data"); + Function content = Reflections.getPrimitiveFunction(fhirContext.getElementDefinition("Attachment").getImplementingClass(), "data"); return new ContentFunctions() { @Override diff --git a/plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java b/plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java index 5fde9c6c1..3a970946c 100644 --- a/plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java +++ b/plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java @@ -8,7 +8,7 @@ import org.hl7.fhir.r4.model.Measure; import org.junit.jupiter.api.Test; -public class LibraryUtilitiesTest implements LibraryUtilities { +public class LibraryUtilitiesTest implements Libraries { @Test public void libraryNoContentReturnsNull() { diff --git a/plugin/cr/pom.xml b/plugin/cr/pom.xml index 1361cf137..6be2a48dc 100644 --- a/plugin/cr/pom.xml +++ b/plugin/cr/pom.xml @@ -25,7 +25,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java index 57fd7969e..866a3b5a4 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/CrConfig.java @@ -59,10 +59,15 @@ public org.opencds.cqf.ruler.cr.r4.provider.PlanDefinitionApplyProvider r4PlanDe return new org.opencds.cqf.ruler.cr.r4.provider.PlanDefinitionApplyProvider(); } - @Bean @Conditional(OnR4Condition.class) public org.opencds.cqf.ruler.cr.r4.provider.MeasureEvaluateProvider r4MeasureEvaluateProvider() { return new org.opencds.cqf.ruler.cr.r4.provider.MeasureEvaluateProvider(); } + + @Bean + @Conditional(OnR4Condition.class) + public org.opencds.cqf.ruler.cr.r4.provider.SubmitDataProvider r4SubmitDataProvider() { + return new org.opencds.cqf.ruler.cr.r4.provider.SubmitDataProvider(); + } } diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProvider.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProvider.java index adb3c5342..90a1f413d 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProvider.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProvider.java @@ -35,7 +35,6 @@ import org.opencds.cqf.ruler.cr.dstu3.builder.RequestGroupActionBuilder; import org.opencds.cqf.ruler.cr.dstu3.builder.RequestGroupBuilder; import org.opencds.cqf.ruler.cr.dstu3.helper.ContainedHelper; -import org.opencds.cqf.ruler.utility.CanonicalUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -47,7 +46,7 @@ import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.api.server.RequestDetails; -public class PlanDefinitionApplyProvider implements OperationProvider, CanonicalUtilities { +public class PlanDefinitionApplyProvider implements OperationProvider { @Autowired private ExpressionEvaluation expressionEvaluation; diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java index 92e301242..e97a3f55d 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java @@ -22,6 +22,7 @@ import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.InMemoryLibraryContentProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; +import org.opencds.cqf.ruler.common.utility.Canonicals; import org.opencds.cqf.ruler.cql.CqlProperties; import org.opencds.cqf.ruler.cql.JpaDataProviderFactory; import org.opencds.cqf.ruler.cql.JpaFhirDal; @@ -29,13 +30,12 @@ import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; import org.opencds.cqf.ruler.cql.JpaTerminologyProviderFactory; import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; -import org.opencds.cqf.ruler.utility.CanonicalUtilities; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.api.server.RequestDetails; -public class ExpressionEvaluation implements CanonicalUtilities { +public class ExpressionEvaluation { @Autowired private LibraryLoaderFactory libraryLoaderFactory; @@ -104,7 +104,7 @@ private Context setupContext(DomainResource instance, String cql, String patient // log error } if (executionLibrary == null) { - Library library = (Library) jpaFhirDal.read(this.getIdElement(libraries.get(0))); + Library library = (Library) jpaFhirDal.read(Canonicals.getIdElement(libraries.get(0))); vi.setId(library.getName()); if (library.getVersion() != null) { vi.setVersion(library.getVersion()); @@ -198,7 +198,7 @@ private String buildIncludes(LibraryLoader libraryLoader, JpaFhirDal jpaFhirDal, } // else check local data for Library to get name and version from else { - Library library = (Library) jpaFhirDal.read(this.getIdElement(reference)); + Library library = (Library) jpaFhirDal.read(Canonicals.getIdElement(reference)); builder.append(buildLibraryIncludeString( new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion()))); } @@ -209,7 +209,7 @@ private String buildIncludes(LibraryLoader libraryLoader, JpaFhirDal jpaFhirDal, private VersionedIdentifier getVersionedIdentifierFromCanonical(CanonicalType reference) { VersionedIdentifier vi = new VersionedIdentifier(); - String cqlLibraryName = this.getIdElement(reference).getIdPart(); + String cqlLibraryName = Canonicals.getIdElement(reference).getIdPart(); vi.withId(cqlLibraryName); String cqlLibraryVersion = null; if (reference.hasValue() && reference.getValue().split("\\|").length > 1) { diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProvider.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProvider.java index e8a2828a4..2be8995fc 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProvider.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProvider.java @@ -36,7 +36,6 @@ import org.opencds.cqf.ruler.cr.r4.builder.RequestGroupActionBuilder; import org.opencds.cqf.ruler.cr.r4.builder.RequestGroupBuilder; import org.opencds.cqf.ruler.cr.r4.helper.ContainedHelper; -import org.opencds.cqf.ruler.utility.CanonicalUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -50,7 +49,7 @@ import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.api.server.RequestDetails; -public class PlanDefinitionApplyProvider implements OperationProvider, CanonicalUtilities { +public class PlanDefinitionApplyProvider implements OperationProvider { @Autowired private ExpressionEvaluation expressionEvaluation; diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java new file mode 100644 index 000000000..26db576de --- /dev/null +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java @@ -0,0 +1,89 @@ +package org.opencds.cqf.ruler.cr.r4.provider; + +import java.util.List; + +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.r4.model.Bundle; +import org.hl7.fhir.r4.model.IdType; +import org.hl7.fhir.r4.model.Measure; +import org.hl7.fhir.r4.model.MeasureReport; +import org.hl7.fhir.r4.model.Resource; +import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; + +import ca.uhn.fhir.model.api.annotation.Description; +import ca.uhn.fhir.rest.annotation.IdParam; +import ca.uhn.fhir.rest.annotation.Operation; +import ca.uhn.fhir.rest.annotation.OperationParam; +import ca.uhn.fhir.rest.api.server.RequestDetails; + +public class SubmitDataProvider extends DaoRegistryOperationProvider { + + /** + * Implements the $submit-data operation found in the FHIR Clinical Reasoning Module. + * + * The submitted MeasureReport and Resources will be saved to the local server. + * A Bundle reporting the result of the transaction will be returned. + * + * @param theRequestDetails generally auto-populated by the HAPI server + * framework. + * @param theId the Id of the Measure to submit data for + * @param theReport the MeasureReport to be submitted + * @param theResources the resources to be submitted + * @return Bundle the transaction result + */ + @Description(shortDefinition = "$submit-data", value = "Implements the $submit-data operation found in the FHIR Clinical Reasoning Module.") + @Operation(name = "$submit-data", idempotent = true, type = Measure.class) + public Bundle submitData(RequestDetails theRequestDetails, + @IdParam IdType theId, + @OperationParam(name = "measureReport", min = 1, max = 1) MeasureReport theReport, + @OperationParam(name = "resource") List theResources) { + /* + * TODO - resource validation using $data-requirements operation (params are the + * provided id and the measurement period from the MeasureReport) + * + * TODO - profile validation ... not sure how that would work ... (get + * StructureDefinition from URL or must it be stored in Ruler?) + */ + + Bundle transactionBundle = new Bundle() + .setType(Bundle.BundleType.TRANSACTION) + .addEntry(createEntry(theReport)); + + if (theResources != null) { + for (IBaseResource res : theResources) { + // Unpack nested Bundles + if (res instanceof Bundle) { + Bundle nestedBundle = (Bundle) res; + for (Bundle.BundleEntryComponent entry : nestedBundle.getEntry()) { + transactionBundle.addEntry(createEntry(entry.getResource())); + } + } else { + transactionBundle.addEntry(createEntry(res)); + } + } + } + + return transaction(transactionBundle, theRequestDetails); + } + + private Bundle.BundleEntryComponent createEntry(IBaseResource theResource) { + return new Bundle.BundleEntryComponent() + .setResource((Resource)theResource) + .setRequest(createRequest(theResource)); + } + + private Bundle.BundleEntryRequestComponent createRequest(IBaseResource theResource) { + Bundle.BundleEntryRequestComponent request = new Bundle.BundleEntryRequestComponent(); + if (theResource.getIdElement() != null) { + request + .setMethod(Bundle.HTTPVerb.PUT) + .setUrl(theResource.getIdElement().getValue()); + } else { + request + .setMethod(Bundle.HTTPVerb.POST) + .setUrl(theResource.fhirType()); + } + + return request; + } +} diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java index 604af3ec2..5f015e9d8 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java @@ -14,14 +14,11 @@ import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.devtools.dstu3.CodeSystemUpdateProvider; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; @ExtendWith(SpringExtension.class) @@ -33,20 +30,11 @@ "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false" }) -public class ExpressionEvaluationIT implements ITestSupport { +public class ExpressionEvaluationIT extends RestIntegrationTest { @Autowired private ExpressionEvaluation expressionEvaluation; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - @Autowired private CodeSystemUpdateProvider codeSystemUpdateProvider; @@ -54,18 +42,18 @@ public class ExpressionEvaluationIT implements ITestSupport { @BeforeEach public void setup() throws Exception { - uploadTests("valueset", ourCtx, myDaoRegistry); + uploadTests("valueset"); codeSystemUpdateProvider.updateCodeSystems(); - uploadTests("library", ourCtx, myDaoRegistry); - planDefinitions = uploadTests("plandefinition", ourCtx, myDaoRegistry); + uploadTests("library"); + planDefinitions = uploadTests("plandefinition"); } @Test public void testOpioidCdsPlanDefinitionDomain() throws Exception { DomainResource plandefinition = (DomainResource) planDefinitions.get("opioidcds-10"); // Patient First - uploadTests("test/plandefinition/Rec10/Patient", ourCtx, myDaoRegistry); - Map resources = uploadTests("test/plandefinition/Rec10", ourCtx, myDaoRegistry); + uploadTests("test/plandefinition/Rec10/Patient"); + Map resources = uploadTests("test/plandefinition/Rec10"); IBaseResource patient = resources.get("example-rec-10-no-screenings"); Object isFormerSmoker = expressionEvaluation.evaluateInContext(plandefinition, "true", false, diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java index f9d6015e4..4530f93ea 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java @@ -15,14 +15,11 @@ import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; @ExtendWith(SpringExtension.class) @@ -34,32 +31,23 @@ "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false" }) -public class ActivityDefinitionApplyProviderIT implements ITestSupport { +public class ActivityDefinitionApplyProviderIT extends RestIntegrationTest { @Autowired private ActivityDefinitionApplyProvider activityDefinitionApplyProvider; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - private Map activityDefinitions; @BeforeEach public void setup() throws Exception { - activityDefinitions = uploadTests("activitydefinition", ourCtx, myDaoRegistry); + activityDefinitions = uploadTests("activitydefinition"); } @Test public void testActivityDefinitionApply() throws Exception { DomainResource activityDefinition = (DomainResource) activityDefinitions.get("opioidcds-risk-assessment-request"); // Patient First - Map resources = uploadTests("test/activitydefinition/Patient", ourCtx, myDaoRegistry); + Map resources = uploadTests("test/activitydefinition/Patient"); IBaseResource patient = resources.get("ExamplePatient"); Resource applyResult = activityDefinitionApplyProvider.apply(new SystemRequestDetails(), activityDefinition.getIdElement(), patient.getIdElement().getIdPart(), null, null, null, null, null, null, diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java index 985c049a6..4ad48edb7 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java @@ -15,14 +15,11 @@ import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.devtools.dstu3.CodeSystemUpdateProvider; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; @ExtendWith(SpringExtension.class) @@ -34,20 +31,11 @@ "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false", }) -public class PlanDefinitionApplyProviderIT implements ITestSupport { +public class PlanDefinitionApplyProviderIT extends RestIntegrationTest{ @Autowired private PlanDefinitionApplyProvider planDefinitionApplyProvider; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - @Autowired private CodeSystemUpdateProvider codeSystemUpdateProvider; @@ -55,18 +43,18 @@ public class PlanDefinitionApplyProviderIT implements ITestSupport { @BeforeEach public void setup() throws Exception { - uploadTests("valueset", ourCtx, myDaoRegistry); + uploadTests("valueset"); codeSystemUpdateProvider.updateCodeSystems(); - uploadTests("library", ourCtx, myDaoRegistry); - planDefinitions = uploadTests("plandefinition", ourCtx, myDaoRegistry); + uploadTests("library"); + planDefinitions = uploadTests("plandefinition"); } @Test public void testPlanDefinitionApplyRec10NoScreenings() throws Exception { DomainResource plandefinition = (DomainResource) planDefinitions.get("opioidcds-10"); // Patient First - uploadTests("test/plandefinition/Rec10/Patient", ourCtx, myDaoRegistry); - Map resources = uploadTests("test/plandefinition/Rec10", ourCtx, myDaoRegistry); + uploadTests("test/plandefinition/Rec10/Patient"); + Map resources = uploadTests("test/plandefinition/Rec10"); IBaseResource patient = resources.get("example-rec-10-no-screenings"); Object recommendation = planDefinitionApplyProvider.applyPlanDefinition(new SystemRequestDetails(), plandefinition.getIdElement(), patient.getIdElement().getIdPart(), null, null, null, null, null, null, null, diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java index 300da6b62..1b01fe4f7 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java @@ -14,14 +14,11 @@ import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.devtools.r4.CodeSystemUpdateProvider; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; @ExtendWith(SpringExtension.class) @@ -33,20 +30,11 @@ "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false" }) -public class ExpressionEvaluationIT implements ITestSupport { +public class ExpressionEvaluationIT extends RestIntegrationTest { @Autowired private ExpressionEvaluation expressionEvaluation; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - @Autowired private CodeSystemUpdateProvider codeSystemUpdateProvider; @@ -55,19 +43,19 @@ public class ExpressionEvaluationIT implements ITestSupport { @BeforeEach public void setup() throws Exception { - uploadTests("valueset", ourCtx, myDaoRegistry); + uploadTests("valueset"); codeSystemUpdateProvider.updateCodeSystems(); - uploadTests("library", ourCtx, myDaoRegistry); - measures = uploadTests("measure", ourCtx, myDaoRegistry); - planDefinitions = uploadTests("plandefinition", ourCtx, myDaoRegistry); + uploadTests("library"); + measures = uploadTests("measure"); + planDefinitions = uploadTests("plandefinition"); } @Test public void testExpressionEvaluationANCIND01MeasureDomain() throws Exception { DomainResource measure = (DomainResource) measures.get("ANCIND01"); // Patient First - uploadTests("test/measure/ANCIND01/charity-otala-1/Patient", ourCtx, myDaoRegistry); - Map resources = uploadTests("test/measure/ANCIND01", ourCtx, myDaoRegistry); + uploadTests("test/measure/ANCIND01/charity-otala-1/Patient"); + Map resources = uploadTests("test/measure/ANCIND01"); IBaseResource patient = resources.get("charity-otala-1"); Object ipResult = expressionEvaluation.evaluateInContext(measure, "ANCIND01.\"Initial Population\"", patient.getIdElement().getIdPart(), new SystemRequestDetails()); @@ -87,9 +75,8 @@ public void testExpressionEvaluationANCIND01MeasureDomain() throws Exception { public void testExpressionEvaluationANCDT01PlanDefinitionDomain() throws Exception { DomainResource planDefinition = (DomainResource) planDefinitions.get("lcs-cds-patient-view"); // Patient First - uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker/Patient", ourCtx, myDaoRegistry); - Map resources = uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker", - ourCtx, myDaoRegistry); + uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker/Patient"); + Map resources = uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker"); IBaseResource patient = resources.get("Former-Smoker"); Object isFormerSmoker = expressionEvaluation.evaluateInContext(planDefinition, "Is former smoker who quit within past 15 years", patient.getIdElement().getIdPart(), true, diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java index b6d0c7279..b87604a9b 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java @@ -1,5 +1,6 @@ package org.opencds.cqf.ruler.cr.r4.provider; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Map; @@ -15,14 +16,11 @@ import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; @ExtendWith(SpringExtension.class) @@ -34,35 +32,26 @@ "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false" }) -public class ActivityDefinitionApplyProviderIT implements ITestSupport{ +public class ActivityDefinitionApplyProviderIT extends RestIntegrationTest { @Autowired private ActivityDefinitionApplyProvider activityDefinitionApplyProvider; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - private Map activityDefinitions; @BeforeEach public void setup() throws Exception { - activityDefinitions = uploadTests("activitydefinition", ourCtx, myDaoRegistry); + activityDefinitions = uploadTests("activitydefinition"); } @Test public void testActivityDefinitionApply() throws Exception { DomainResource activityDefinition = (DomainResource) activityDefinitions.get("opioidcds-risk-assessment-request"); // Patient First - Map resources = uploadTests("test/activitydefinition/Patient", ourCtx, myDaoRegistry); + Map resources = uploadTests("test/activitydefinition/Patient"); IBaseResource patient = resources.get("ExamplePatient"); Resource applyResult = activityDefinitionApplyProvider.apply(new SystemRequestDetails(), activityDefinition.getIdElement(), patient.getIdElement().getIdPart(), null, null, null, null, null, null, null, null); assertTrue(applyResult instanceof ServiceRequest); - assertTrue(((ServiceRequest) applyResult).getCode().getCoding().get(0).getCode().equals("454281000124100")); + assertEquals("454281000124100", ((ServiceRequest) applyResult).getCode().getCoding().get(0).getCode()); } } diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java index 847b342ed..f5f88ddf7 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java @@ -8,15 +8,11 @@ import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.devtools.r4.CodeSystemUpdateProvider; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; - @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { @@ -26,36 +22,31 @@ "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false" }) -public class MeasureEvaluateProviderIT implements ITestSupport { +public class MeasureEvaluateProviderIT extends RestIntegrationTest { // @Autowired // private MeasureEvaluateProvider measureEvaluateProvider; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - @Autowired private CodeSystemUpdateProvider codeSystemUpdateProvider; @BeforeEach public void setup() throws Exception { - uploadTests("valueset", ourCtx, myDaoRegistry); + uploadTests("valueset"); codeSystemUpdateProvider.updateCodeSystems(); - uploadTests("library", ourCtx, myDaoRegistry); + uploadTests("library"); } @Test public void testMeasureEvaluate() throws Exception { // Patient First - uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker/Patient", ourCtx, myDaoRegistry); - // Map resources = uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker", ourCtx, myDaoRegistry); + uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker/Patient"); + // Map resources = + // uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker", ourCtx, + // myDaoRegistry); // IBaseResource patient = resources.get("Former-Smoker"); - // MeasureReport report = measureEvaluateProvider.evaluateMeasure(requestDetails, theId, periodStart, periodEnd, reportType, subject, practitioner, lastReceivedOn, productLine); + // MeasureReport report = + // measureEvaluateProvider.evaluateMeasure(requestDetails, theId, periodStart, + // periodEnd, reportType, subject, practitioner, lastReceivedOn, productLine); } } diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java index b0d3fb7ec..4635e8f2f 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java @@ -15,14 +15,11 @@ import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.devtools.r4.CodeSystemUpdateProvider; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; @ExtendWith(SpringExtension.class) @@ -34,20 +31,11 @@ "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false" }) -public class PlanDefinitionApplyProviderIT implements ITestSupport { +public class PlanDefinitionApplyProviderIT extends RestIntegrationTest { @Autowired private PlanDefinitionApplyProvider planDefinitionApplyProvider; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - @Autowired private CodeSystemUpdateProvider codeSystemUpdateProvider; @@ -55,18 +43,18 @@ public class PlanDefinitionApplyProviderIT implements ITestSupport { @BeforeEach public void setup() throws Exception { - uploadTests("valueset", ourCtx, myDaoRegistry); + uploadTests("valueset"); codeSystemUpdateProvider.updateCodeSystems(); - uploadTests("library", ourCtx, myDaoRegistry); - planDefinitions = uploadTests("plandefinition", ourCtx, myDaoRegistry); + uploadTests("library"); + planDefinitions = uploadTests("plandefinition"); } @Test public void testPlanDefinitionApplyFormerSmoker() throws Exception { DomainResource plandefinition = (DomainResource) planDefinitions.get("lcs-cds-patient-view"); // Patient First - uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker/Patient", ourCtx, myDaoRegistry); - Map resources = uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker", ourCtx, myDaoRegistry); + uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker/Patient"); + Map resources = uploadTests("test/plandefinition/LungCancerScreening/Former-Smoker"); IBaseResource patient = resources.get("Former-Smoker"); Object isFormerSmoker = planDefinitionApplyProvider.applyPlanDefinition(new SystemRequestDetails(), plandefinition.getIdElement(), patient.getIdElement().getIdPart(), null, null, null, null, null, null, null, diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java new file mode 100644 index 000000000..057c1eb17 --- /dev/null +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java @@ -0,0 +1,75 @@ +package org.opencds.cqf.ruler.cr.r4.provider; + +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import com.google.common.collect.Lists; + +import org.hl7.fhir.r4.model.MeasureReport; +import org.hl7.fhir.r4.model.Observation; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.opencds.cqf.ruler.common.utility.IdCreator; +import org.opencds.cqf.ruler.common.utility.ResourceCreator; +import org.opencds.cqf.ruler.test.DaoIntegrationTest; +import org.opencds.cqf.ruler.test.DaoOnlyConfig; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.test.context.junit.jupiter.SpringExtension; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.jpa.partition.SystemRequestDetails; + + + +@ExtendWith(SpringExtension.class) +@SpringBootTest(classes = { DaoOnlyConfig.class }, properties = { + "scheduling_disabled=true", + "spring.main.allow-bean-definition-overriding=true", + "spring.batch.job.enabled=false", + "hapi.fhir.fhir_version=r4", + "hapi.fhir.allow_external_references=true", + "hapi.fhir.enforce_referential_integrity_on_write=false", +}) +@EnableAutoConfiguration(exclude=QuartzAutoConfiguration.class) +public class SubmitDataProviderIT extends DaoIntegrationTest implements IdCreator, ResourceCreator { + + @Autowired + DaoRegistry myDaoRegistry; + + @Autowired + FhirContext myFhirContext; + + @Autowired + SubmitDataProvider mySubmitDataProvider; + + @Override + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } + + @Override + public FhirContext getFhirContext() { + return myFhirContext; + } + + @Test + public void testSubmitData() { + // Create a MR and a few resources + MeasureReport mr = newResource(newId("MeasureReport/test-mr")); + Observation obs = newResource(newId("Observation/test-obs")); + + // Submit it + mySubmitDataProvider.submitData(new SystemRequestDetails(), newId("Measure/test-m"), mr, Lists.newArrayList(obs)); + + // Check if they made it to the db + Observation savedObs = read(obs.getIdElement()); + assertNotNull(savedObs); + + MeasureReport savedMr = read(mr.getIdElement()); + assertNotNull(savedMr); + } + +} diff --git a/plugin/dev-tools/pom.xml b/plugin/dev-tools/pom.xml index 99bb66489..009f32345 100644 --- a/plugin/dev-tools/pom.xml +++ b/plugin/dev-tools/pom.xml @@ -11,7 +11,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java index b7c4c4c50..01d1910b7 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java @@ -14,7 +14,7 @@ import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.ValueSet; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.utility.ClientUtilities; +import org.opencds.cqf.ruler.common.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; @@ -37,7 +37,7 @@ * that supports caching {@link ValueSet ValueSets } and ensuring expansion of * those {@link ValueSet ValueSets } */ -public class CacheValueSetsProvider implements OperationProvider, ClientUtilities { +public class CacheValueSetsProvider implements OperationProvider { @Autowired private IFhirSystemDao systemDao; @@ -77,7 +77,7 @@ public Resource cacheValuesets(RequestDetails details, @IdParam IdType endpointI return createErrorOutcome("Could not find Endpoint/" + endpointId + "\n" + e); } - IGenericClient client = this.createClient(ourCtx, endpoint); + IGenericClient client = Clients.forEndpoint(ourCtx, endpoint); if (userName != null || password != null) { if (userName == null) { diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java index 993535580..78c8c483c 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java @@ -19,7 +19,7 @@ import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.instance.model.api.IIdType; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.utility.IdUtilities; +import org.opencds.cqf.ruler.common.utility.Ids; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; @@ -37,7 +37,7 @@ * to enable {@link ValueSet ValueSet} expansion and validation without complete * {@link CodeSystem CodeSystems}. */ -public class CodeSystemUpdateProvider implements OperationProvider, IdUtilities { +public class CodeSystemUpdateProvider implements OperationProvider { @Autowired private IFhirResourceDaoValueSet myValueSetDaoDSTU3; @Autowired @@ -166,7 +166,7 @@ private CodeSystem getCodeSystemByUrl(String url) { } return (CodeSystem) new CodeSystem().setUrl(url) - .setId((IIdType) this.createId(CodeSystem.class, UUID.randomUUID().toString())); + .setId((IIdType) Ids.newId(CodeSystem.class, UUID.randomUUID().toString())); } /*** diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java index 52eb9f986..3c6f7a004 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java @@ -14,7 +14,7 @@ import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.ValueSet; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.utility.ClientUtilities; +import org.opencds.cqf.ruler.common.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; @@ -37,7 +37,7 @@ * that supports caching {@link ValueSet ValueSets } and ensuring expansion of * those {@link ValueSet ValueSets } */ -public class CacheValueSetsProvider implements OperationProvider, ClientUtilities { +public class CacheValueSetsProvider implements OperationProvider { @Autowired private IFhirSystemDao systemDao; @@ -77,7 +77,7 @@ public Resource cacheValuesets(RequestDetails details, @IdParam IdType endpointI return createErrorOutcome("Could not find Endpoint/" + endpointId + "\n" + e); } - IGenericClient client = this.createClient(ourCtx, endpoint); + IGenericClient client = Clients.forEndpoint(ourCtx, endpoint); if (userName != null || password != null) { if (userName == null) { diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java index 950cbe852..fb88f9153 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java @@ -19,7 +19,7 @@ import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.ValueSet; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.utility.IdUtilities; +import org.opencds.cqf.ruler.common.utility.Ids; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; @@ -37,7 +37,7 @@ * to enable {@link ValueSet ValueSet} expansion and validation without complete * {@link CodeSystem CodeSystems}. */ -public class CodeSystemUpdateProvider implements OperationProvider, IdUtilities { +public class CodeSystemUpdateProvider implements OperationProvider { @Autowired private IFhirResourceDaoValueSet myValueSetDaoR4; @Autowired @@ -166,7 +166,7 @@ private CodeSystem getCodeSystemByUrl(String url) { } return (CodeSystem) new CodeSystem().setUrl(url) - .setId((IIdType) this.createId(CodeSystem.class, UUID.randomUUID().toString())); + .setId((IIdType) Ids.newId(CodeSystem.class, UUID.randomUUID().toString())); } /*** diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java index 27b5f33e5..db2acf118 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java @@ -1,5 +1,6 @@ package org.opencds.cqf.ruler.devtools.dstu3; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.BufferedReader; @@ -21,16 +22,11 @@ import org.mockito.Mockito; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.IdUtilities; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.StringAndListParam; @@ -38,19 +34,10 @@ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=dstu3", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) -public class CacheValueSetsProviderIT implements ITestSupport, IdUtilities, ClientUtilities { +public class CacheValueSetsProviderIT extends RestIntegrationTest { @Autowired private CacheValueSetsProvider cacheValueSetsProvider; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - @Test public void testCacheValueSetsEndpointDNE() throws Exception { Endpoint endpoint = new Endpoint(); @@ -94,7 +81,7 @@ public void testCacheValueSetsAuthenticationErrorPassword() throws Exception { public void testCacheValueSetsValueSetDNE() throws Exception { Endpoint endpoint = uploadLocalServerEndpoint(); StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(ourCtx, "valueset", Arrays.asList(QualifiedParamList.singleton("dne"))); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton("dne"))); RequestDetails details = Mockito.mock(RequestDetails.class); Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); validateOutcome(outcomeResource, "HTTP 404 : Resource ValueSet/" + "dne" + " is not known"); @@ -104,7 +91,7 @@ public void testCacheValueSetsValueSetDNE() throws Exception { public void testCacheValueSetsValueSetNull() throws Exception { Endpoint endpoint = uploadLocalServerEndpoint(); StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(ourCtx, "valueset", Arrays.asList(QualifiedParamList.singleton(new ValueSet().getId()))); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton(new ValueSet().getId()))); RequestDetails details = Mockito.mock(RequestDetails.class); Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); validateOutcome(outcomeResource, "HTTP 404 : Resource ValueSet/" + new ValueSet().getIdElement().getIdPart() + " is not known"); @@ -120,10 +107,10 @@ public void testCacheValueSetsNoCompose() throws Exception { Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); assertTrue(outcomeResource instanceof Bundle); Bundle resultBundle = (Bundle) outcomeResource; - assertTrue(resultBundle.getEntry().size() == 1); + assertEquals(1, resultBundle.getEntry().size()); BundleEntryComponent entry = resultBundle.getEntry().get(0); assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); - assertTrue(entry.getResponse().getStatus().equals("200 OK")); + assertEquals("200 OK", entry.getResponse().getStatus()); // ValueSet resultingValueSet = createClient(ourCtx, endpoint).read().resource(ValueSet.class).withId(vs.getIdElement()).execute(); // resultingValueSet not returning with a version // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); @@ -164,10 +151,10 @@ public void testCacheValueSetsAlreadyExpanded() throws Exception { Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); assertTrue(outcomeResource instanceof Bundle); Bundle resultBundle = (Bundle) outcomeResource; - assertTrue(resultBundle.getEntry().size() == 1); + assertEquals(1, resultBundle.getEntry().size()); BundleEntryComponent entry = resultBundle.getEntry().get(0); assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); - assertTrue(entry.getResponse().getStatus().equals("200 OK")); + assertEquals("200 OK", entry.getResponse().getStatus()); // ValueSet resultingValueSet = myDaoRegistry.getResourceDao(ValueSet.class).read(vs.getIdElement()); // resultingValueSet not returning with a version // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); @@ -180,7 +167,7 @@ private StringAndListParam getStringAndListParamFromValueSet(String location) th private StringAndListParam getStringAndListParamFromValueSet(ValueSet vs) throws IOException { StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(ourCtx, "valueset", Arrays.asList(QualifiedParamList.singleton(vs.getIdElement().getIdPart()))); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton(vs.getIdElement().getIdPart()))); return stringAndListParam; } @@ -188,7 +175,7 @@ private void validateOutcome(Resource outcomeResource, String detailMessage) { assertTrue(outcomeResource instanceof OperationOutcome); OperationOutcome outcome = (OperationOutcome) outcomeResource; for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.ERROR)); + assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); assertTrue(issue.getDetails().getCodingFirstRep().getDisplay().startsWith(detailMessage)); } } @@ -197,7 +184,7 @@ private ValueSet uploadValueSet(String location) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(CacheValueSetsProvider.class.getResourceAsStream(location))); String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); - return (ValueSet) loadResource("json", resourceString, ourCtx, myDaoRegistry); + return (ValueSet) loadResource("json", resourceString); } private Endpoint uploadLocalServerEndpoint() throws IOException { @@ -205,9 +192,9 @@ private Endpoint uploadLocalServerEndpoint() throws IOException { String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); // Don't want to update during loading because need to setAddress first - Endpoint endpoint = (Endpoint) loadResource("json", resourceString, ourCtx, null); - endpoint.setAddress("http://localhost:" + port + "/fhir/"); - myDaoRegistry.getResourceDao(Endpoint.class).update(endpoint); - return endpoint; + Endpoint endpoint = (Endpoint) loadResource("json", resourceString); + endpoint.setAddress("http://localhost:" + getPort() + "/fhir/"); + create(endpoint); + return endpoint; } } diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java index b813a0573..5146d3680 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java @@ -17,179 +17,155 @@ import org.hl7.fhir.dstu3.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.dstu3.model.ValueSet; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; +import org.opencds.cqf.ruler.common.utility.Searches; import org.opencds.cqf.ruler.devtools.DevToolsConfig; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.IdUtilities; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.rest.api.server.IBundleProvider; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.param.UriParam; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, -DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=dstu3", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) + DevToolsConfig.class }, properties = { "hapi.fhir.fhir_version=dstu3", "spring.batch.job.enabled=false", + "spring.main.allow-bean-definition-overriding=true" }) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class CodeSystemProviderIT implements ITestSupport, IdUtilities, ClientUtilities { - private Logger log = LoggerFactory.getLogger(CodeSystemProviderIT.class); - - @Autowired - private FhirContext ourCtx; +public class CodeSystemProviderIT extends RestIntegrationTest { + private Logger log = LoggerFactory.getLogger(CodeSystemProviderIT.class); + + @Autowired + CodeSystemUpdateProvider codeSystemUpdateProvider; + + private String icd10 = "http://hl7.org/fhir/sid/icd-10"; + private String rxNormUrl = "http://www.nlm.nih.gov/research/umls/rxnorm"; + private String snomedSctUrl = "http://snomed.info/sct"; + private String cptUrl = "http://www.ama-assn.org/go/cpt"; + + @AfterEach + void tearDown() { + // These are not actually doing anything right now + getClient().delete().resourceConditionalByType(CodeSystem.class); + getClient().delete().resourceConditionalByType(ValueSet.class); + } - @LocalServerPort - private int port; + @Test + @Order(1) + public void testCodeSystemUpdateValueSetDNE() throws IOException { + ValueSet vs = (ValueSet) readResource("org/opencds/cqf/ruler/devtools/dstu3/valueset/AntithromboticTherapy.json"); + OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); + assertEquals(1, outcome.getIssue().size()); + OperationOutcomeIssueComponent issue = outcome.getIssue().get(0); + assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); + assertTrue(issue.getDetails().getText().startsWith("Unable to find Resource: " + vs.getIdElement().getIdPart())); + } - @Autowired - CodeSystemUpdateProvider codeSystemUpdateProvider; - - @Autowired - private DaoRegistry myDaoRegistry; + @Test + @Order(2) + public void testCodeSystemUpdateValueSetIdNull() { + OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(new ValueSet().getIdElement()); + assertEquals(1, outcome.getIssue().size()); + OperationOutcomeIssueComponent issue = outcome.getIssue().get(0); + assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); + assertTrue(issue.getDetails().getText().startsWith("Unable to find Resource: null")); + } - private IGenericClient ourClient; + @Test + @Order(3) + public void testDSTU3RxNormCodeSystemUpdateById() throws IOException { + log.info("Beginning Test DSTU3 RxNorm CodeSystemUpdate"); + ValueSet vs = (ValueSet) loadResource("org/opencds/cqf/ruler/devtools/dstu3/valueset/AntithromboticTherapy.json"); + + assertEquals(0, performCodeSystemSearchByUrl(rxNormUrl).size()); + OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); + for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { + assertEquals(OperationOutcome.IssueSeverity.INFORMATION, issue.getSeverity()); + assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); + assertTrue(issue.getDetails().getText().contains("rxnorm")); + } + assertEquals(1, performCodeSystemSearchByUrl(rxNormUrl).size()); + + log.info("Finished Test DSTU3 RxNorm CodeSystemUpdate"); + } - private String icd10 = "http://hl7.org/fhir/sid/icd-10"; - private String rxNormUrl = "http://www.nlm.nih.gov/research/umls/rxnorm"; - private String snomedSctUrl = "http://snomed.info/sct"; - private String cptUrl = "http://www.ama-assn.org/go/cpt"; + @Test + @Order(4) + public void testDSTU3ICD10PerformCodeSystemUpdateByList() throws IOException { + log.info("Beginning Test DSTU3 ICD10 CodeSystemUpdate"); + + BufferedReader reader = new BufferedReader(new InputStreamReader( + CodeSystemProviderIT.class.getResourceAsStream("valueset" + "/" + "AllPrimaryandSecondaryCancer.json"))); + String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); + reader.close(); + ValueSet vs = (ValueSet) loadResource("json", resourceString); + + assertEquals(0, performCodeSystemSearchByUrl(icd10).size()); + codeSystemUpdateProvider.performCodeSystemUpdate(Arrays.asList(vs)); + OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); + for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { + assertEquals(OperationOutcome.IssueSeverity.INFORMATION, issue.getSeverity()); + assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); + assertTrue(issue.getDetails().getText().contains("icd-10")); + } + assertEquals(1, performCodeSystemSearchByUrl(icd10).size()); + + log.info("Finished Test DSTU3 ICD10 CodeSystemUpdate"); + } - @BeforeEach - void beforeEach() throws IOException { - ourClient = createClient(FhirVersionEnum.DSTU3, "http://localhost:" + port + "/fhir/"); + @Test + @Order(5) + public void testDSTU3UpdateCodeSystems() throws IOException { + log.info("Beginning Test DSTU3 Update Code Systems"); + + assertEquals(0, performCodeSystemSearchByUrl(cptUrl).size()); + + File[] valuesets = new File(CodeSystemProviderIT.class.getResource("valueset").getPath()).listFiles(); + for (File file : valuesets) { + if (file.isFile() && FilenameUtils.getExtension(file.getPath()).equals("json")) { + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); + reader.close(); + loadResource("json", resourceString); + } else if (file.isFile() && FilenameUtils.getExtension(file.getPath()).equals("xml")) { + BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); + String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); + reader.close(); + loadResource("xml", resourceString); + } + } + OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(); + for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { + assertEquals(OperationOutcome.IssueSeverity.INFORMATION, issue.getSeverity()); + assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); + assertTrue(issue.getDetails().getText().contains("cpt")); + assertTrue(issue.getDetails().getText().contains("icd-10")); + assertTrue(issue.getDetails().getText().contains("sct")); + assertTrue(issue.getDetails().getText().contains("rxnorm")); + } + assertEquals(1, performCodeSystemSearchByUrl(icd10).size()); + assertEquals(1, performCodeSystemSearchByUrl(rxNormUrl).size()); + assertEquals(1, performCodeSystemSearchByUrl(snomedSctUrl).size()); + assertEquals(1, performCodeSystemSearchByUrl(cptUrl).size()); + + log.info("Finished Test DSTU3 Update Code Systems"); } - @AfterEach - void tearDown() { - // These are not actually doing anything right now - ourClient.delete().resourceConditionalByType(CodeSystem.class); - ourClient.delete().resourceConditionalByType(ValueSet.class); - } - - @Test - @Order(1) - public void testCodeSystemUpdateValueSetDNE() throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(CodeSystemProviderIT.class.getResourceAsStream("valueset" + "/" + "AntithromboticTherapy.json"))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - ValueSet vs = (ValueSet) loadResource("json", resourceString, ourCtx, null); - OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); - assertTrue(outcome.getIssue().size() == 1); - OperationOutcomeIssueComponent issue = outcome.getIssue().get(0); - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.ERROR)); - assertTrue(issue.getDetails().getText().startsWith("Unable to find Resource: " + vs.getIdElement().getIdPart())); - } - - @Test - @Order(2) - public void testCodeSystemUpdateValueSetIdNull() { - OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(new ValueSet().getIdElement()); - assertTrue(outcome.getIssue().size() == 1); - OperationOutcomeIssueComponent issue = outcome.getIssue().get(0); - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.ERROR)); - assertTrue(issue.getDetails().getText().startsWith("Unable to find Resource: null")); - } - - @Test - @Order(3) - public void testDSTU3RxNormCodeSystemUpdateById() throws IOException { - log.info("Beginning Test DSTU3 RxNorm CodeSystemUpdate"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(CodeSystemProviderIT.class.getResourceAsStream("valueset" + "/" + "AntithromboticTherapy.json"))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - ValueSet vs = (ValueSet) loadResource("json", resourceString, ourCtx, myDaoRegistry); - - assertEquals(0, performCodeSystemSearchByUrl(rxNormUrl).size()); - OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); - for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.INFORMATION)); - assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); - assertTrue(issue.getDetails().getText().contains("rxnorm")); - } - assertEquals(1, performCodeSystemSearchByUrl(rxNormUrl).size()); - - log.info("Finished Test DSTU3 RxNorm CodeSystemUpdate"); - } - - @Test - @Order(4) - public void testDSTU3ICD10PerformCodeSystemUpdateByList() throws IOException { - log.info("Beginning Test DSTU3 ICD10 CodeSystemUpdate"); - - BufferedReader reader = new BufferedReader(new InputStreamReader(CodeSystemProviderIT.class.getResourceAsStream("valueset" + "/" + "AllPrimaryandSecondaryCancer.json"))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - ValueSet vs = (ValueSet) loadResource("json", resourceString, ourCtx, myDaoRegistry); - - assertEquals(0, performCodeSystemSearchByUrl(icd10).size()); - codeSystemUpdateProvider.performCodeSystemUpdate(Arrays.asList(vs)); - OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); - for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.INFORMATION)); - assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); - assertTrue(issue.getDetails().getText().contains("icd-10")); - } - assertEquals(1,performCodeSystemSearchByUrl(icd10).size()); - - log.info("Finished Test DSTU3 ICD10 CodeSystemUpdate"); - } - - @Test - @Order(5) - public void testDSTU3UpdateCodeSystems() throws IOException { - log.info("Beginning Test DSTU3 Update Code Systems"); - - assertEquals(0, performCodeSystemSearchByUrl(cptUrl).size()); - - File[] valuesets = new File(CodeSystemProviderIT.class.getResource("valueset").getPath()).listFiles(); - for (File file : valuesets) { - if (file.isFile() && FilenameUtils.getExtension(file.getPath()).equals("json")) { - BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - loadResource("json", resourceString, ourCtx, myDaoRegistry); - } else if (file.isFile() && FilenameUtils.getExtension(file.getPath()).equals("xml")) { - BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - loadResource("xml", resourceString, ourCtx, myDaoRegistry); - } - } - OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(); - for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.INFORMATION)); - assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); - assertTrue(issue.getDetails().getText().contains("cpt")); - assertTrue(issue.getDetails().getText().contains("icd-10")); - assertTrue(issue.getDetails().getText().contains("sct")); - assertTrue(issue.getDetails().getText().contains("rxnorm")); - } - assertEquals(1, performCodeSystemSearchByUrl(icd10).size()); - assertEquals(1, performCodeSystemSearchByUrl(rxNormUrl).size()); - assertEquals(1, performCodeSystemSearchByUrl(snomedSctUrl).size()); - assertEquals(1, performCodeSystemSearchByUrl(cptUrl).size()); - - log.info("Finished Test DSTU3 Update Code Systems"); - } - - private IBundleProvider performCodeSystemSearchByUrl(String rxNormUrl) { - return this.myDaoRegistry.getResourceDao(CodeSystem.class) - .search(SearchParameterMap.newSynchronous().add(CodeSystem.SP_URL, new UriParam(rxNormUrl))); - } + // Old way + // private IBundleProvider performCodeSystemSearchByUrl(String rxNormUrl) { + // return this.myDaoRegistry.getResourceDao(CodeSystem.class) + // .search(SearchParameterMap.newSynchronous().add(CodeSystem.SP_URL, new UriParam(rxNormUrl))); + // } + + // New way + private IBundleProvider performCodeSystemSearchByUrl(String rxNormUrl) { + return search(CodeSystem.class, Searches.byUrl(rxNormUrl)); + } } diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java index 041cdd329..cfb678bb2 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java @@ -1,5 +1,6 @@ package org.opencds.cqf.ruler.devtools.r4; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.BufferedReader; @@ -21,16 +22,11 @@ import org.mockito.Mockito; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.IdUtilities; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.StringAndListParam; @@ -38,19 +34,10 @@ @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) -public class CacheValueSetsProviderIT implements ITestSupport, IdUtilities, ClientUtilities { +public class CacheValueSetsProviderIT extends RestIntegrationTest { @Autowired private CacheValueSetsProvider cacheValueSetsProvider; - @Autowired - private FhirContext ourCtx; - - @Autowired - private DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - @Test public void testCacheValueSetsEndpointDNE() throws Exception { Endpoint endpoint = new Endpoint(); @@ -94,7 +81,7 @@ public void testCacheValueSetsAuthenticationErrorPassword() throws Exception { public void testCacheValueSetsValueSetDNE() throws Exception { Endpoint endpoint = uploadLocalServerEndpoint(); StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(ourCtx, "valueset", Arrays.asList(QualifiedParamList.singleton("dne"))); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton("dne"))); RequestDetails details = Mockito.mock(RequestDetails.class); Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); validateOutcome(outcomeResource, "HTTP 404 : Resource ValueSet/" + "dne" + " is not known"); @@ -104,7 +91,7 @@ public void testCacheValueSetsValueSetDNE() throws Exception { public void testCacheValueSetsValueSetNull() throws Exception { Endpoint endpoint = uploadLocalServerEndpoint(); StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(ourCtx, "valueset", Arrays.asList(QualifiedParamList.singleton(new ValueSet().getId()))); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton(new ValueSet().getId()))); RequestDetails details = Mockito.mock(RequestDetails.class); Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); validateOutcome(outcomeResource, "HTTP 404 : Resource ValueSet/" + new ValueSet().getIdElement().getIdPart() + " is not known"); @@ -120,10 +107,10 @@ public void testCacheValueSetsNoCompose() throws Exception { Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); assertTrue(outcomeResource instanceof Bundle); Bundle resultBundle = (Bundle) outcomeResource; - assertTrue(resultBundle.getEntry().size() == 1); + assertEquals(1, resultBundle.getEntry().size()); BundleEntryComponent entry = resultBundle.getEntry().get(0); assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); - assertTrue(entry.getResponse().getStatus().equals("200 OK")); + assertEquals("200 OK", entry.getResponse().getStatus()); // ValueSet resultingValueSet = createClient(ourCtx, endpoint).read().resource(ValueSet.class).withId(vs.getIdElement()).execute(); // resultingValueSet not returning with a version // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); @@ -164,10 +151,10 @@ public void testCacheValueSetsAlreadyExpanded() throws Exception { Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); assertTrue(outcomeResource instanceof Bundle); Bundle resultBundle = (Bundle) outcomeResource; - assertTrue(resultBundle.getEntry().size() == 1); + assertEquals(1, resultBundle.getEntry().size()); BundleEntryComponent entry = resultBundle.getEntry().get(0); assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); - assertTrue(entry.getResponse().getStatus().equals("200 OK")); + assertEquals("200 OK", entry.getResponse().getStatus()); // ValueSet resultingValueSet = myDaoRegistry.getResourceDao(ValueSet.class).read(vs.getIdElement()); // resultingValueSet not returning with a version // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); @@ -180,7 +167,7 @@ private StringAndListParam getStringAndListParamFromValueSet(String location) th private StringAndListParam getStringAndListParamFromValueSet(ValueSet vs) throws IOException { StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(ourCtx, "valueset", Arrays.asList(QualifiedParamList.singleton(vs.getIdElement().getIdPart()))); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton(vs.getIdElement().getIdPart()))); return stringAndListParam; } @@ -188,7 +175,7 @@ private void validateOutcome(Resource outcomeResource, String detailMessage) { assertTrue(outcomeResource instanceof OperationOutcome); OperationOutcome outcome = (OperationOutcome) outcomeResource; for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.ERROR)); + assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); assertTrue(issue.getDetails().getCodingFirstRep().getDisplay().startsWith(detailMessage)); } } @@ -197,7 +184,7 @@ private ValueSet uploadValueSet(String location) throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(CacheValueSetsProvider.class.getResourceAsStream(location))); String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); - return (ValueSet) loadResource("json", resourceString, ourCtx, myDaoRegistry); + return (ValueSet) loadResource("json", resourceString); } private Endpoint uploadLocalServerEndpoint() throws IOException { @@ -205,9 +192,9 @@ private Endpoint uploadLocalServerEndpoint() throws IOException { String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); // Don't want to update during loading because need to setAddress first - Endpoint endpoint = (Endpoint) loadResource("json", resourceString, ourCtx, null); - endpoint.setAddress("http://localhost:" + port + "/fhir/"); - myDaoRegistry.getResourceDao(Endpoint.class).update(endpoint); + Endpoint endpoint = (Endpoint) loadResource("json", resourceString); + endpoint.setAddress("http://localhost:" + getPort() + "/fhir/"); + update(endpoint); return endpoint; } } diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java index 682693e45..b66ec4237 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java @@ -17,81 +17,52 @@ import org.hl7.fhir.r4.model.OperationOutcome.OperationOutcomeIssueComponent; import org.hl7.fhir.r4.model.ValueSet; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.MethodOrderer; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; +import org.opencds.cqf.ruler.common.utility.Searches; import org.opencds.cqf.ruler.devtools.DevToolsConfig; -import org.opencds.cqf.ruler.test.ITestSupport; -import org.opencds.cqf.ruler.utility.ClientUtilities; -import org.opencds.cqf.ruler.utility.IdUtilities; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.rest.api.server.IBundleProvider; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.param.UriParam; @ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class CodeSystemProviderIT implements ITestSupport, IdUtilities, ClientUtilities { +public class CodeSystemProviderIT extends RestIntegrationTest { private Logger log = LoggerFactory.getLogger(CodeSystemProviderIT.class); - @Autowired - private FhirContext ourCtx; - - @LocalServerPort - private int port; - @Autowired CodeSystemUpdateProvider codeSystemUpdateProvider; - - @Autowired - private DaoRegistry myDaoRegistry; - - private IGenericClient ourClient; private String loincUrl = "http://loinc.org"; private String snomedSctUrl = "http://snomed.info/sct"; private String cptUrl = "http://www.ama-assn.org/go/cpt"; - @BeforeEach - void beforeEach() throws IOException { - ourClient = createClient(FhirVersionEnum.R4, "http://localhost:" + port + "/fhir/"); - } - @AfterEach void tearDown() { // These are not actually doing anything right now - ourClient.delete().resourceConditionalByType(CodeSystem.class); - ourClient.delete().resourceConditionalByType(ValueSet.class); + getClient().delete().resourceConditionalByType(CodeSystem.class); + getClient().delete().resourceConditionalByType(ValueSet.class); } @Test @Order(1) public void testCodeSystemUpdateValueSetDNE() throws IOException { - //TODO add line separator based on system - BufferedReader reader = new BufferedReader(new InputStreamReader(CodeSystemProviderIT.class.getResourceAsStream("valueset" + "/" + "valueset-pain-treatment-plan.json"))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - ValueSet vs = (ValueSet) loadResource("json", resourceString, ourCtx, null); + ValueSet vs = (ValueSet) readResource("org/opencds/cqf/ruler/devtools/r4/valueset/valueset-pain-treatment-plan.json"); OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); - assertTrue(outcome.getIssue().size() == 1); + assertEquals(1, outcome.getIssue().size()); OperationOutcomeIssueComponent issue = outcome.getIssue().get(0); - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.ERROR)); + assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); assertTrue(issue.getDetails().getText().startsWith("Unable to find Resource: " + vs.getIdElement().getIdPart())); } @@ -99,9 +70,9 @@ public void testCodeSystemUpdateValueSetDNE() throws IOException { @Order(2) public void testCodeSystemUpdateValueSetIdNull() { OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(new ValueSet().getIdElement()); - assertTrue(outcome.getIssue().size() == 1); + assertEquals(1, outcome.getIssue().size()); OperationOutcomeIssueComponent issue = outcome.getIssue().get(0); - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.ERROR)); + assertEquals(OperationOutcome.IssueSeverity.ERROR,issue.getSeverity()); assertTrue(issue.getDetails().getText().startsWith("Unable to find Resource: null")); } @@ -109,16 +80,12 @@ public void testCodeSystemUpdateValueSetIdNull() { @Order(3) public void testR4RxNormCodeSystemUpdateById() throws IOException { log.info("Beginning Test R4 LOINC CodeSystemUpdate"); - //TODO add line separator based on system - BufferedReader reader = new BufferedReader(new InputStreamReader(CodeSystemProviderIT.class.getResourceAsStream("valueset" + "/" + "valueset-pain-treatment-plan.json"))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - ValueSet vs = (ValueSet) loadResource("json", resourceString, ourCtx, myDaoRegistry); + ValueSet vs = (ValueSet) loadResource("org/opencds/cqf/ruler/devtools/r4/valueset/valueset-pain-treatment-plan.json"); assertEquals(0, performCodeSystemSearchByUrl(loincUrl).size()); OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.INFORMATION)); + assertEquals(OperationOutcome.IssueSeverity.INFORMATION, issue.getSeverity()); assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); assertTrue(issue.getDetails().getText().contains("loinc")); } @@ -135,13 +102,13 @@ public void testR4ICD10PerformCodeSystemUpdateByList() throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(CodeSystemProviderIT.class.getResourceAsStream("valueset" + "/" + "valueset-pdmp-review-procedure.json"))); String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); - ValueSet vs = (ValueSet) loadResource("json", resourceString, ourCtx, myDaoRegistry); + ValueSet vs = (ValueSet) loadResource("json", resourceString); assertEquals(0, performCodeSystemSearchByUrl(snomedSctUrl).size()); codeSystemUpdateProvider.performCodeSystemUpdate(Arrays.asList(vs)); OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(vs.getIdElement()); for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.INFORMATION)); + assertEquals(OperationOutcome.IssueSeverity.INFORMATION, issue.getSeverity()); assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); assertTrue(issue.getDetails().getText().contains("sct")); } @@ -163,17 +130,17 @@ public void testR4UpdateCodeSystems() throws IOException { BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); - loadResource("json", resourceString, ourCtx, myDaoRegistry); + loadResource("json", resourceString); } else if (file.isFile() && FilenameUtils.getExtension(file.getPath()).equals("xml")) { BufferedReader reader = new BufferedReader(new InputStreamReader(new FileInputStream(file))); String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); - loadResource("xml", resourceString, ourCtx, myDaoRegistry); + loadResource("xml", resourceString); } } OperationOutcome outcome = codeSystemUpdateProvider.updateCodeSystems(); for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertTrue(issue.getSeverity().equals(OperationOutcome.IssueSeverity.INFORMATION)); + assertEquals(OperationOutcome.IssueSeverity.INFORMATION,issue.getSeverity()); assertTrue(issue.getDetails().getText().startsWith("Successfully updated the following CodeSystems: ")); assertTrue(issue.getDetails().getText().contains("cpt")); assertTrue(issue.getDetails().getText().contains("sct")); @@ -187,7 +154,6 @@ public void testR4UpdateCodeSystems() throws IOException { } private IBundleProvider performCodeSystemSearchByUrl(String rxNormUrl) { - return this.myDaoRegistry.getResourceDao(CodeSystem.class) - .search(SearchParameterMap.newSynchronous().add(CodeSystem.SP_URL, new UriParam(rxNormUrl))); + return search(CodeSystem.class, Searches.byUrl(rxNormUrl)); } } diff --git a/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java b/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java index 33ed4fe6f..aff23080c 100644 --- a/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java +++ b/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -31,15 +32,15 @@ }) public class HelloWorldProviderIT { private IGenericClient ourClient; - private FhirContext ourCtx; + + @Autowired + FhirContext ourCtx; @LocalServerPort private int port; @BeforeEach void beforeEach() { - - ourCtx = FhirContext.forR4Cached(); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); String ourServerBase = "http://localhost:" + port + "/fhir/"; diff --git a/plugin/pom.xml b/plugin/pom.xml index e96b73c80..f233fbeaa 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -22,7 +23,6 @@ ra sdc security - utility @@ -35,6 +35,11 @@ cqf-ruler-external 0.5.0-SNAPSHOT + + org.opencds.cqf.ruler + cqf-ruler-common + 0.5.0-SNAPSHOT + org.springframework.boot spring-boot-autoconfigure @@ -50,14 +55,14 @@ test - org.opencds.cqf.ruler - cqf-ruler-test - 0.5.0-SNAPSHOT + org.springframework.boot + spring-boot-starter-test test - org.springframework.boot - spring-boot-starter-test + org.opencds.cqf.ruler + cqf-ruler-test + 0.5.0-SNAPSHOT test diff --git a/plugin/ra/pom.xml b/plugin/ra/pom.xml index 69147d645..fcb30ca1f 100644 --- a/plugin/ra/pom.xml +++ b/plugin/ra/pom.xml @@ -11,7 +11,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java b/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java index f6c54e3de..d1f7ea4b1 100644 --- a/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java +++ b/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java @@ -1,6 +1,7 @@ package org.opencds.cqf.ruler.ra.r4; import java.util.ArrayList; +import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; @@ -21,28 +22,21 @@ import org.hl7.fhir.r4.model.Period; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; -import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.utility.OperatorUtilities; +import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; +import org.opencds.cqf.ruler.common.utility.IdCreator; +import org.opencds.cqf.ruler.common.utility.Operations; +import org.opencds.cqf.ruler.common.utility.Searches; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.springframework.beans.factory.annotation.Autowired; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.ReferenceParam; -public class ReportProvider implements OperationProvider, OperatorUtilities { - - @Autowired - private DaoRegistry myDaoRegistry; - +public class ReportProvider extends DaoRegistryOperationProvider implements IdCreator { private static final Logger ourLog = LoggerFactory.getLogger(ReportProvider.class); - /** * Implements the $report @@ -50,10 +44,12 @@ public class ReportProvider implements OperationProvider, OperatorUtilities { * Da Vinci Risk * Adjustment IG. * - * @param requestDetails metadata about the current request being processed. Generally auto-populated by the HAPI FHIR server framework. - * @param periodStart the start of the clinical evaluation period - * @param periodEnd the end of the clinical evaluation period - * @param subject a Patient or Patient Group + * @param requestDetails metadata about the current request being processed. + * Generally auto-populated by the HAPI FHIR server + * framework. + * @param periodStart the start of the clinical evaluation period + * @param periodEnd the end of the clinical evaluation period + * @param subject a Patient or Patient Group * @return a Parameters with Bundles of MeasureReports and evaluatedResource * Resources */ @@ -66,7 +62,7 @@ public Parameters report( @OperationParam(name = "periodEnd", min = 1, max = 1) String periodEnd, @OperationParam(name = "subject", min = 1, max = 1) String subject) throws FHIRException { - Period period = validateParamaters(periodStart, periodEnd, subject); + Period period = validateParameters(periodStart, periodEnd, subject); Parameters result = initializeParametersResult(subject); List patients = getPatientListFromSubject(subject); @@ -81,15 +77,15 @@ public Parameters report( return result; } - private Period validateParamaters(String periodStart, String periodEnd, String subject) { + private Period validateParameters(String periodStart, String periodEnd, String subject) { if (periodStart == null) { throw new IllegalArgumentException("Parameter 'periodStart' is required."); } if (periodEnd == null) { throw new IllegalArgumentException("Parameter 'periodEnd' is required."); } - Date periodStartDate = resolveRequestDate(periodStart, true); - Date periodEndDate = resolveRequestDate(periodEnd, false); + Date periodStartDate = Operations.resolveRequestDate(periodStart, true); + Date periodEndDate = Operations.resolveRequestDate(periodEnd, false); if (periodStartDate.after(periodEndDate)) { throw new IllegalArgumentException("Parameter 'periodStart' must be before 'periodEnd'."); } @@ -112,7 +108,7 @@ private Parameters initializeParametersResult(String subject) { return result; } - private static String PATIENT_REPORT_PROFILE_URL = "http://hl7.org/fhir/us/davinci-ra/StructureDefinition/ra-measurereport-bundle"; + private static final String PATIENT_REPORT_PROFILE_URL = "http://hl7.org/fhir/us/davinci-ra/StructureDefinition/ra-measurereport-bundle"; private Parameters.ParametersParameterComponent patientReport(Patient thePatient, Period thePeriod, String serverBase) { @@ -121,24 +117,20 @@ private Parameters.ParametersParameterComponent patientReport(Patient thePatient final Map bundleEntries = new HashMap<>(); bundleEntries.put(thePatient.getIdElement(), thePatient); - SearchParameterMap theParams = SearchParameterMap.newSynchronous(); ReferenceParam subjectParam = new ReferenceParam(patientId); - theParams.add("subject", subjectParam); - IFhirResourceDao measureReportDao = myDaoRegistry.getResourceDao(MeasureReport.class); - measureReportDao.search(theParams).getAllResources().forEach(baseResource -> { - MeasureReport measureReport = (MeasureReport) baseResource; - - if (measureReport.getPeriod().getEnd().before(thePeriod.getStart()) - || measureReport.getPeriod().getStart().after(thePeriod.getEnd())) { - return; - } + search(MeasureReport.class, Searches.byParam("subject", subjectParam)).getAllResourcesTyped() + .forEach(measureReport -> { - bundleEntries.putIfAbsent(measureReport.getIdElement(), measureReport); + if (measureReport.getPeriod().getEnd().before(thePeriod.getStart()) + || measureReport.getPeriod().getStart().after(thePeriod.getEnd())) { + return; + } - getEvaluatedResources(measureReport).forEach(resource -> { - bundleEntries.putIfAbsent(resource.getIdElement(), resource); - }); - }); + bundleEntries.putIfAbsent(measureReport.getIdElement(), measureReport); + + getEvaluatedResources(measureReport).forEach(resource -> + bundleEntries.putIfAbsent(resource.getIdElement(), resource)); + }); Bundle patientReportBundle = new Bundle(); patientReportBundle.setMeta(new Meta().addProfile(PATIENT_REPORT_PROFILE_URL)); @@ -148,13 +140,12 @@ private Parameters.ParametersParameterComponent patientReport(Patient thePatient patientReportBundle.setIdentifier( new Identifier().setSystem("urn:ietf:rfc:3986").setValue("urn:uuid:" + UUID.randomUUID().toString())); - bundleEntries.entrySet().forEach(resource -> { + bundleEntries.entrySet().forEach(resource -> patientReportBundle.addEntry( new Bundle.BundleEntryComponent() .setResource((Resource) resource.getValue()) - .setFullUrl(getFullUrl(serverBase, resource.getValue().fhirType(), - resource.getValue().getIdElement().getIdPart()))); - }); + .setFullUrl(Operations.getFullUrl(serverBase, resource.getValue().fhirType(), + resource.getValue().getIdElement().getIdPart())))); Parameters.ParametersParameterComponent patientParameter = new Parameters.ParametersParameterComponent(); patientParameter.setResource(patientReportBundle); @@ -169,8 +160,8 @@ private List getEvaluatedResources(MeasureReport report) { List resources = new ArrayList<>(); for (Reference evaluatedResource : report.getEvaluatedResource()) { IIdType theEvaluatedId = evaluatedResource.getReferenceElement(); - IBaseResource resourceBase = this.resolveById(myDaoRegistry, theEvaluatedId); - if (resourceBase != null && resourceBase instanceof Resource) { + IBaseResource resourceBase = read(theEvaluatedId); + if (resourceBase instanceof Resource) { Resource resource = (Resource) resourceBase; resources.add(resource); } @@ -181,40 +172,35 @@ private List getEvaluatedResources(MeasureReport report) { // TODO: replace this with version from the evaluator? private Patient ensurePatient(String patientRef) { - IBaseResource patient = resolveById(myDaoRegistry, Patient.class, patientRef); + Patient patient = read(newId(patientRef)); if (patient == null) { throw new RuntimeException("Could not find Patient: " + patientRef); } - return (Patient) patient; + return patient; } // TODO: replace this with version from the evaluator? private List getPatientListFromSubject(String subject) { - List patientList = null; - if (subject.startsWith("Patient/")) { Patient patient = ensurePatient(subject); - patientList = new ArrayList(); - patientList.add(patient); + return Collections.singletonList(patient); } else if (subject.startsWith("Group/")) { - patientList = getPatientListFromGroup(subject); - } else { - ourLog.info(String.format("Subject member was not a Patient or a Group, so skipping. \n%s", subject)); + return getPatientListFromGroup(subject); } - return patientList; + ourLog.info("Subject member was not a Patient or a Group, so skipping. \n{}", subject); + return Collections.emptyList(); } // TODO: replace this with version from the evaluator? private List getPatientListFromGroup(String subjectGroupId) { List patientList = new ArrayList<>(); - IBaseResource baseGroup = resolveById(myDaoRegistry, Group.class, subjectGroupId); - if (baseGroup == null) { + Group group = read(newId(subjectGroupId)); + if (group == null) { throw new RuntimeException("Could not find Group: " + subjectGroupId); } - Group group = (Group) baseGroup; group.getMember().forEach(member -> { Reference reference = member.getEntity(); if (reference.getReferenceElement().getResourceType().equals("Patient")) { @@ -223,9 +209,8 @@ private List getPatientListFromGroup(String subjectGroupId) { } else if (reference.getReferenceElement().getResourceType().equals("Group")) { patientList.addAll(getPatientListFromGroup(reference.getReference())); } else { - ourLog.info( - String.format("Group member was not a Patient or a Group, so skipping. \n%s", - reference.getReference())); + ourLog.info("Group member was not a Patient or a Group, so skipping. \n{}", + reference.getReference()); } }); diff --git a/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java b/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java index 3a6be060b..8804f770e 100644 --- a/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java +++ b/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java @@ -16,9 +16,11 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; +import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.ra.RAConfig; import org.opencds.cqf.ruler.ra.RAProperties; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.ResourceLoader; +import org.opencds.cqf.ruler.test.Urls; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; @@ -26,7 +28,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; @@ -37,29 +38,39 @@ @ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, RAConfig.class }, properties = { "hapi.fhir.fhir_version=r4" }) -public class ReportProviderIT implements org.opencds.cqf.ruler.test.ClientUtilities, - org.opencds.cqf.ruler.utility.ClientUtilities, ITestSupport { +public class ReportProviderIT implements ResourceLoader { private IGenericClient ourClient; - private FhirContext ourCtx; @Autowired - private DaoRegistry ourRegistry; + private FhirContext ourCtx; @Autowired - private RAProperties myRaProperties; + DaoRegistry myDaoRegistry; @LocalServerPort private int port; + @Override + public FhirContext getFhirContext() { + return ourCtx; + } + + @Override + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } + + @Autowired + private RAProperties myRaProperties; + + @BeforeEach void beforeEach() { - - ourCtx = FhirContext.forCached(FhirVersionEnum.R4); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = getClientUrl(myRaProperties.getReport().getEndpoint(), port); - ourClient = createClient(ourCtx, ourServerBase); + String ourServerBase = Urls.getUrl(myRaProperties.getReport().getEndpoint(), port); + ourClient = Clients.forUrl(ourCtx, ourServerBase); myRaProperties.getReport().setEndpoint(ourServerBase); } @@ -131,7 +142,7 @@ public void testSubjectPatient() throws IOException { params.addParameter().setName("periodStart").setValue(new StringType("2021-01-01")); params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); params.addParameter().setName("subject").setValue(new StringType("Patient/ra-patient01")); - loadResource("Patient-ra-patient01.json", ourCtx,ourRegistry); + loadResource("Patient-ra-patient01.json"); assertDoesNotThrow(() -> { ourClient.operation().onType(MeasureReport.class).named("$report") @@ -149,8 +160,8 @@ public void testSubjectGroup() throws IOException { params.addParameter().setName("periodStart").setValue(new StringType("2021-01-01")); params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); params.addParameter().setName("subject").setValue(new StringType("Group/ra-group01")); - loadResource("Patient-ra-patient01.json", ourCtx, ourRegistry); - loadResource("Group-ra-group01.json", ourCtx, ourRegistry); + loadResource("Patient-ra-patient01.json"); + loadResource("Group-ra-group01.json"); assertDoesNotThrow(() -> { ourClient.operation().onType(MeasureReport.class).named("$report") @@ -217,7 +228,7 @@ public void testSubjectPatientNotFoundInGroup() throws IOException { params.addParameter().setName("periodStart").setValue(new StringType("2021-01-01")); params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); params.addParameter().setName("subject").setValue(new StringType("Group/ra-group00")); - loadResource("Group-ra-group00.json", ourCtx, ourRegistry); + loadResource("Group-ra-group00.json"); Group group = ourClient.read().resource(Group.class).withId("ra-group00").execute(); assertNotNull(group); @@ -237,9 +248,9 @@ public void testSubjectMultiplePatientGroup() throws IOException { params.addParameter().setName("periodStart").setValue(new StringType("2021-01-01")); params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); params.addParameter().setName("subject").setValue(new StringType("Group/ra-group02")); - loadResource("Patient-ra-patient02.json", ourCtx,ourRegistry); - loadResource("Patient-ra-patient03.json", ourCtx, ourRegistry); - loadResource("Group-ra-group02.json", ourCtx, ourRegistry); + loadResource("Patient-ra-patient02.json"); + loadResource("Patient-ra-patient03.json"); + loadResource("Group-ra-group02.json"); assertDoesNotThrow(() -> { ourClient.operation().onType(MeasureReport.class).named("$report") @@ -256,27 +267,27 @@ public void testSingleSubjectSingleReport() throws IOException { params.addParameter().setName("periodStart").setValue(new StringType("2021-01-01")); params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); params.addParameter().setName("subject").setValue(new StringType("Patient/ra-patient01")); - loadResource("Patient-ra-patient01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition02pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition03pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition08pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition09pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition10pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition11pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition17pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition18pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition33pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition43pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition44pat01.json", ourCtx, ourRegistry); - loadResource("Observation-ra-obs21pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter02pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter03pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter08pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter09pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter11pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter43pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter44pat01.json", ourCtx, ourRegistry); - loadResource("MeasureReport-ra-measurereport01.json", ourCtx, ourRegistry); + loadResource("Patient-ra-patient01.json"); + loadResource("Condition-ra-condition02pat01.json"); + loadResource("Condition-ra-condition03pat01.json"); + loadResource("Condition-ra-condition08pat01.json"); + loadResource("Condition-ra-condition09pat01.json"); + loadResource("Condition-ra-condition10pat01.json"); + loadResource("Condition-ra-condition11pat01.json"); + loadResource("Condition-ra-condition17pat01.json"); + loadResource("Condition-ra-condition18pat01.json"); + loadResource("Condition-ra-condition33pat01.json"); + loadResource("Condition-ra-condition43pat01.json"); + loadResource("Condition-ra-condition44pat01.json"); + loadResource("Observation-ra-obs21pat01.json"); + loadResource("Encounter-ra-encounter02pat01.json"); + loadResource("Encounter-ra-encounter03pat01.json"); + loadResource("Encounter-ra-encounter08pat01.json"); + loadResource("Encounter-ra-encounter09pat01.json"); + loadResource("Encounter-ra-encounter11pat01.json"); + loadResource("Encounter-ra-encounter43pat01.json"); + loadResource("Encounter-ra-encounter44pat01.json"); + loadResource("MeasureReport-ra-measurereport01.json"); Parameters actual = ourClient.operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) @@ -298,29 +309,29 @@ public void testReportDoesNotIncludeNonEvaluatedResources() throws IOException { params.addParameter().setName("periodStart").setValue(new StringType("2021-01-01")); params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); params.addParameter().setName("subject").setValue(new StringType("Patient/ra-patient01")); - loadResource("Patient-ra-patient01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition02pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition03pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition08pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition09pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition10pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition11pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition17pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition18pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition33pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition43pat01.json", ourCtx, ourRegistry); - loadResource("Condition-ra-condition44pat01.json", ourCtx, ourRegistry); - loadResource("Observation-ra-obs21pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter02pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter03pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter08pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter09pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter11pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter43pat01.json", ourCtx, ourRegistry); - loadResource("Encounter-ra-encounter44pat01.json", ourCtx, ourRegistry); - loadResource("MeasureReport-ra-measurereport01.json", ourCtx, ourRegistry); + loadResource("Patient-ra-patient01.json"); + loadResource("Condition-ra-condition02pat01.json"); + loadResource("Condition-ra-condition03pat01.json"); + loadResource("Condition-ra-condition08pat01.json"); + loadResource("Condition-ra-condition09pat01.json"); + loadResource("Condition-ra-condition10pat01.json"); + loadResource("Condition-ra-condition11pat01.json"); + loadResource("Condition-ra-condition17pat01.json"); + loadResource("Condition-ra-condition18pat01.json"); + loadResource("Condition-ra-condition33pat01.json"); + loadResource("Condition-ra-condition43pat01.json"); + loadResource("Condition-ra-condition44pat01.json"); + loadResource("Observation-ra-obs21pat01.json"); + loadResource("Encounter-ra-encounter02pat01.json"); + loadResource("Encounter-ra-encounter03pat01.json"); + loadResource("Encounter-ra-encounter08pat01.json"); + loadResource("Encounter-ra-encounter09pat01.json"); + loadResource("Encounter-ra-encounter11pat01.json"); + loadResource("Encounter-ra-encounter43pat01.json"); + loadResource("Encounter-ra-encounter44pat01.json"); + loadResource("MeasureReport-ra-measurereport01.json"); // this is not an evaluatedResource of the report - loadResource("Encounter-ra-encounter45pat01.json", ourCtx, ourRegistry); + loadResource("Encounter-ra-encounter45pat01.json"); Parameters actual = ourClient.operation().onType(MeasureReport.class).named("$report") .withParameters(params) diff --git a/plugin/sdc/pom.xml b/plugin/sdc/pom.xml index c9e3e74a4..2a2178d8d 100644 --- a/plugin/sdc/pom.xml +++ b/plugin/sdc/pom.xml @@ -11,7 +11,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java index bfdcaa06c..f96d74463 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java @@ -18,8 +18,8 @@ import org.hl7.fhir.dstu3.model.Reference; import org.hl7.fhir.dstu3.model.StringType; import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; -import org.opencds.cqf.ruler.utility.ClientUtilities; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; @@ -27,7 +27,7 @@ import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.client.api.IGenericClient; -public class ExtractProvider implements OperationProvider, ClientUtilities { +public class ExtractProvider implements OperationProvider { @Autowired private FhirContext myFhirContext; @@ -139,8 +139,8 @@ private Bundle sendObservationBundle(Bundle observationsBundle) throws IllegalAr String user = mySdcProperties.getExtract().getUsername(); String password = mySdcProperties.getExtract().getPassword(); - IGenericClient client = this.createClient(myFhirContext, url); - this.registerBasicAuth(client, user, password); + IGenericClient client = Clients.forUrl(myFhirContext, url); + Clients.registerBasicAuth(client, user, password); Bundle outcomeBundle = client.transaction() .withBundle(observationsBundle) .execute(); @@ -155,8 +155,8 @@ private Map getQuestionnaireCodeMap(String questionnaireUrl){ String user = mySdcProperties.getExtract().getUsername(); String password = mySdcProperties.getExtract().getPassword(); - IGenericClient client = this.createClient(myFhirContext, url); - this.registerBasicAuth(client, user, password); + IGenericClient client = Clients.forUrl(myFhirContext, url); + Clients.registerBasicAuth(client, user, password); Questionnaire questionnaire = client.read().resource(Questionnaire.class).withUrl (questionnaireUrl).execute(); return createCodeMap(questionnaire); diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java index 645b90624..80accdcae 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java @@ -9,8 +9,8 @@ import org.hl7.fhir.dstu3.model.ConceptMap; import org.hl7.fhir.dstu3.model.Observation; import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; -import org.opencds.cqf.ruler.utility.ClientUtilities; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; @@ -19,7 +19,7 @@ import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.util.BundleUtil; -public class TransformProvider implements OperationProvider, ClientUtilities { +public class TransformProvider implements OperationProvider { @Autowired private FhirContext fhirContext; @@ -50,7 +50,7 @@ public Bundle transformObservations( this.password = mySdcProperties.getTransform().getPassword(); this.endpoint = mySdcProperties.getTransform().getEndpoint(); - IGenericClient client = this.createClient(fhirContext, this.endpoint); + IGenericClient client = Clients.forUrl(fhirContext, this.endpoint); ConceptMap transformConceptMap = client.read().resource(ConceptMap.class).withUrl(conceptMapURL).execute(); if (null == transformConceptMap) { throw new IllegalArgumentException( diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java index 3339f737d..f60f9ac26 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java @@ -18,8 +18,8 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.StringType; import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; -import org.opencds.cqf.ruler.utility.ClientUtilities; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; @@ -27,7 +27,7 @@ import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.client.api.IGenericClient; -public class ExtractProvider implements OperationProvider, ClientUtilities { +public class ExtractProvider implements OperationProvider { /* * https://build.fhir.org/ig/HL7/sdc/OperationDefinition-QuestionnaireResponse- @@ -189,8 +189,8 @@ private Bundle sendObservationBundle(Bundle observationsBundle) String user = mySdcProperties.getExtract().getUsername(); String password = mySdcProperties.getExtract().getPassword(); - IGenericClient client = this.createClient(myFhirContext, url); - this.registerBasicAuth(client, user, password); + IGenericClient client = Clients.forUrl(myFhirContext, url); + Clients.registerBasicAuth(client, user, password); return client.transaction().withBundle(observationsBundle).execute(); } @@ -203,8 +203,8 @@ private Map getQuestionnaireCodeMap(String questionnaireUrl) { String user = mySdcProperties.getExtract().getUsername(); String password = mySdcProperties.getExtract().getPassword(); - IGenericClient client = this.createClient(myFhirContext, url); - this.registerBasicAuth(client, user, password); + IGenericClient client = Clients.forUrl(myFhirContext, url); + Clients.registerBasicAuth(client, user, password); Questionnaire questionnaire = client.read().resource(Questionnaire.class).withUrl(questionnaireUrl).execute(); diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java index 9df077e80..0249bb73f 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java @@ -9,8 +9,8 @@ import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.Observation; import org.opencds.cqf.ruler.api.OperationProvider; +import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; -import org.opencds.cqf.ruler.utility.ClientUtilities; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; @@ -19,7 +19,7 @@ import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.util.BundleUtil; -public class TransformProvider implements OperationProvider, ClientUtilities { +public class TransformProvider implements OperationProvider { @Autowired private FhirContext fhirContext; @@ -50,7 +50,7 @@ public Bundle transformObservations( this.password = mySdcProperties.getTransform().getPassword(); this.endpoint = mySdcProperties.getTransform().getEndpoint(); - IGenericClient client = this.createClient(fhirContext, this.endpoint); + IGenericClient client = Clients.forUrl(fhirContext, this.endpoint); ConceptMap transformConceptMap = client.read().resource(ConceptMap.class).withUrl(conceptMapURL).execute(); if (null == transformConceptMap) { throw new IllegalArgumentException( diff --git a/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java b/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java index a76005479..5bfac8c2c 100644 --- a/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java +++ b/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java @@ -16,7 +16,7 @@ import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.sdc.SDCConfig; import org.opencds.cqf.ruler.sdc.SDCProperties; -import org.opencds.cqf.ruler.test.ITestSupport; +import org.opencds.cqf.ruler.test.ResourceLoader; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; @@ -24,7 +24,6 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; @@ -34,23 +33,33 @@ @ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, SDCConfig.class }, properties = { "hapi.fhir.fhir_version=r4" }) -public class ExtractProviderIT implements ITestSupport { +public class ExtractProviderIT implements ResourceLoader { private IGenericClient ourClient; - private FhirContext ourCtx; @Autowired - private DaoRegistry daoRegistry; + private FhirContext ourCtx; @Autowired - private SDCProperties mySdcProperties; + DaoRegistry myDaoRegistry; @LocalServerPort private int port; + @Override + public FhirContext getFhirContext() { + return ourCtx; + } + + @Override + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } + + @Autowired + private SDCProperties mySdcProperties; + @BeforeEach void beforeEach() { - - ourCtx = FhirContext.forCached(FhirVersionEnum.R4); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); String ourServerBase = "http://localhost:" + port + "/fhir/"; @@ -65,9 +74,9 @@ public void testExtract() throws IOException, URISyntaxException { String exampleQuestionnaire = "questionnaire_1559.json"; String exampleQR = "questionnaire_response_1558.json"; - loadResource(examplePatient, ourCtx, daoRegistry); - loadResource(exampleQuestionnaire, ourCtx, daoRegistry); - QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) loadResource(exampleQR, ourCtx, daoRegistry); + loadResource(examplePatient); + loadResource(exampleQuestionnaire); + QuestionnaireResponse questionnaireResponse = (QuestionnaireResponse) loadResource(exampleQR); Parameters params = new Parameters(); params.addParameter().setName("questionnaireResponse").setResource(questionnaireResponse); diff --git a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java index 0081edd17..1f33a3fb1 100644 --- a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java +++ b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.security.SecurityConfig; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -30,6 +31,8 @@ }) public class OAuthProviderIT { private IGenericClient ourClient; + + @Autowired private FhirContext ourCtx; @LocalServerPort @@ -37,8 +40,6 @@ public class OAuthProviderIT { @BeforeEach void beforeEach() { - - ourCtx = FhirContext.forDstu3Cached(); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); String ourServerBase = "http://localhost:" + port + "/fhir/"; diff --git a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java index bbdf434ff..b37a2795f 100644 --- a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java +++ b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java @@ -9,6 +9,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.security.SecurityConfig; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.junit.jupiter.SpringExtension; @@ -30,6 +31,8 @@ }) public class OAuthProviderIT { private IGenericClient ourClient; + + @Autowired private FhirContext ourCtx; @LocalServerPort @@ -37,8 +40,6 @@ public class OAuthProviderIT { @BeforeEach void beforeEach() { - - ourCtx = FhirContext.forR4Cached(); ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); String ourServerBase = "http://localhost:" + port + "/fhir/"; diff --git a/plugin/utility/README.md b/plugin/utility/README.md deleted file mode 100644 index 7f5e355fc..000000000 --- a/plugin/utility/README.md +++ /dev/null @@ -1,3 +0,0 @@ -# Utility Plugin - -This plugin provides cross-cutting utility functions for other plugins diff --git a/plugin/utility/pom.xml b/plugin/utility/pom.xml deleted file mode 100644 index c7057c75d..000000000 --- a/plugin/utility/pom.xml +++ /dev/null @@ -1,11 +0,0 @@ - - - 4.0.0 - - org.opencds.cqf.ruler - cqf-ruler-plugin - 0.5.0-SNAPSHOT - - - cqf-ruler-utility - diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/CanonicalUtilities.java b/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/CanonicalUtilities.java deleted file mode 100644 index 37193b258..000000000 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/CanonicalUtilities.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import java.util.Objects; - -import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.instance.model.api.IPrimitiveType; - -import ca.uhn.fhir.context.FhirVersionEnum; - -public interface CanonicalUtilities extends IdUtilities { - - interface CanonicalParts { - String getVersion(); - - String getUrl(); - - IdType getId(); - } - - default > String getId(CanonicalType canonicalType) { - if (canonicalType == null || !canonicalType.hasValue()) { - throw new IllegalArgumentException("CanonicalType must have a value for id extraction"); - } - - return this.getId(canonicalType.getValue()); - } - - @SuppressWarnings("unchecked") - default , IdType extends IIdType> IdType getIdElement( - CanonicalType canonicalType) { - if (canonicalType == null || !canonicalType.hasValue()) { - throw new IllegalArgumentException("CanonicalType must have a value for id extraction"); - } - - String id = this.getId(canonicalType.getValue()); - String resourceName = this.getResourceName(canonicalType.getValue()); - - return (IdType) this.createId(canonicalType.getClass(), resourceName, id); - } - - default > String getResourceName(CanonicalType canonicalType) { - if (canonicalType == null || !canonicalType.hasValue()) { - throw new IllegalArgumentException("CanonicalType must have a value for id extraction"); - } - - return this.getResourceName(canonicalType.getValue()); - } - - default String getResourceName(String theCanonical) { - Objects.requireNonNull("theCanonical must not be null"); - if (!theCanonical.contains("/")) { - return null; - } - - theCanonical = theCanonical.replace(theCanonical.substring(theCanonical.lastIndexOf("/")), ""); - return theCanonical.contains("/") ? theCanonical.substring(theCanonical.lastIndexOf("/") + 1) : theCanonical; - } - - default String getId(String theCanonical) { - if (!theCanonical.contains("/")) { - return null; - } - - return theCanonical.contains("/") ? theCanonical.substring(theCanonical.lastIndexOf("/") + 1) : theCanonical; - } - - default String getVersion(String theCanonical) { - if (!theCanonical.contains("|")) { - return null; - } - - String[] urlParts = theCanonical.split("\\|"); - if (urlParts.length <= 1) { - return null; - } - - return urlParts[1]; - } - - default String getUrl(String theCanonical) { - if (!theCanonical.contains("|")) { - return theCanonical; - } - - String[] urlParts = theCanonical.split("\\|"); - return urlParts[0]; - } - - default , IdType extends IIdType> CanonicalParts getCanonicalParts( - CanonicalType theCanonicalType) { - Objects.requireNonNull("canonicalUrl must not be null"); - - String version = this.getVersion(theCanonicalType.getValue()); - String url = this.getUrl(theCanonicalType.getValue()); - IdType id = this.getIdElement(theCanonicalType); - return new CanonicalParts() { - @Override - public String getVersion() { - return version; - } - - @Override - public IdType getId() { - return id; - } - - @Override - public String getUrl() { - return url; - } - }; - } - - default CanonicalParts getCanonicalParts(FhirVersionEnum theFhirVersionEnum, - String theCanonical) { - Objects.requireNonNull("canonicalUrl must not be null"); - - String version = this.getVersion(theCanonical); - String url = this.getUrl(theCanonical); - String resourceType = this.getResourceName(theCanonical); - String id = this.getId(theCanonical); - IdType idElement = this.createId(theFhirVersionEnum, resourceType, id); - return new CanonicalParts() { - @Override - public String getVersion() { - return version; - } - - @Override - public IdType getId() { - return idElement; - } - - @Override - public String getUrl() { - return url; - } - }; - } -} diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ExecutionUtilities.java b/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ExecutionUtilities.java deleted file mode 100644 index 0454b6ceb..000000000 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/ExecutionUtilities.java +++ /dev/null @@ -1,43 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import java.util.ArrayList; -import java.util.List; - -import org.apache.commons.collections4.IterableUtils; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.cql.engine.execution.Context; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.model.valueset.BundleTypeEnum; -import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory; - -public interface ExecutionUtilities { - // Adds the resources returned from the given expressions to a bundle - default IBaseResource bundle(FhirContext fhirContext, Context executionContext, String... expressionNames) { - return bundle(fhirContext, executionContext, null, expressionNames); - } - // Adds the resources returned from the given expressions to a bundle - @SuppressWarnings("unchecked") - default IBaseResource bundle(FhirContext fhirContext, Context executionContext, String theServerBase, String... expressionNames) { - IVersionSpecificBundleFactory bundleFactory = fhirContext.newBundleFactory(); - List resources = new ArrayList(); - for (String expressionName : expressionNames) { - Object result = executionContext.resolveExpressionRef(expressionName).evaluate(executionContext); - for (Object element : (Iterable) result) { - resources.add((IBaseResource) element); - } - } - bundleFactory.addResourcesToBundle(resources, BundleTypeEnum.COLLECTION, theServerBase, null, null); - return bundleFactory.getResourceBundle(); - } - - default IBaseResource bundle(Iterable resources, FhirContext fhirContext) { - return bundle(resources, fhirContext, null); - } - - default IBaseResource bundle(Iterable resources, FhirContext fhirContext, String theServerBase) { - IVersionSpecificBundleFactory bundleFactory = fhirContext.newBundleFactory(); - bundleFactory.addResourcesToBundle(IterableUtils.toList(resources), BundleTypeEnum.COLLECTION, theServerBase, null, null); - return bundleFactory.getResourceBundle(); - } -} diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/OperatorUtilities.java b/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/OperatorUtilities.java deleted file mode 100644 index a502a427c..000000000 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/OperatorUtilities.java +++ /dev/null @@ -1,140 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Date; -import java.util.List; -import java.util.TimeZone; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * This interface provides utilities for implementing FHIR operators. - */ -public interface OperatorUtilities extends ResolutionUtilities { - - Logger ourLog = LoggerFactory.getLogger(OperatorUtilities.class); - - /** - * This function converts a string representation of a FHIR period date to a - * java.util.Date. - * - * @param date the date to convert - * @param start whether the date is the start of a period - * @return the FHIR period date as a java.util.Date type - */ - default Date resolveRequestDate(String date, boolean start) { - // split it up - support dashes or slashes - String[] dissect = date.contains("-") ? date.split("-") : date.split("/"); - List dateVals = new ArrayList<>(); - for (String dateElement : dissect) { - dateVals.add(Integer.parseInt(dateElement)); - } - - if (dateVals.isEmpty()) { - throw new IllegalArgumentException("Invalid date"); - } - - // for now support dates up to day precision - Calendar calendar = Calendar.getInstance(); - calendar.clear(); - calendar.setTimeZone(TimeZone.getDefault()); - calendar.set(Calendar.YEAR, dateVals.get(0)); - if (dateVals.size() > 1) { - // java.util.Date months are zero based, hence the negative 1 -- 2014-01 == - // February 2014 - calendar.set(Calendar.MONTH, dateVals.get(1) - 1); - } - if (dateVals.size() > 2) - calendar.set(Calendar.DAY_OF_MONTH, dateVals.get(2)); - else { - if (start) { - calendar.set(Calendar.DAY_OF_MONTH, 1); - } else { - // get last day of month for end period - calendar.add(Calendar.MONTH, 1); - calendar.set(Calendar.DAY_OF_MONTH, 1); - calendar.add(Calendar.DATE, -1); - } - } - return calendar.getTime(); - } - - /** - * This function returns a fullUrl for a resource. - * - * @param serverAddress the address of the server - * @param fhirType the type of the resource - * @param elementId the id of the resource - * @return the FHIR period date as a java.util.Date type - */ - default String getFullUrl(String serverAddress, String fhirType, String elementId) { - String fullUrl = String.format("%s%s/%s", serverAddress + (serverAddress.endsWith("/") ? "" : "/"), fhirType, - elementId); - return fullUrl; - } - - // This has some issues - // default void ensurePatient(String - // patientRef, DaoRegistry theRegistry, Class theResourceType) { - // IBaseResource patient = resolveById(theRegistry, theResourceType, - // patientRef); - // if (patient == null) { - // throw new RuntimeException("Could not find Patient: " + patientRef); - // } - // } - - // //TODO: replace this with version from base structures - // default List - // getPatientListFromSubject(String theSubject, DaoRegistry theRegistry, - // Class thePatientType, Class theGroupType) { - // List patientList = null; - - // if (theSubject.startsWith("Patient/")) { - // ensurePatient(theSubject, theRegistry, thePatientType); - // patientList = new ArrayList(); - // Reference patientReference = new Reference().setReference(theSubject); - // patientList.add(patientReference); - // } else if (theSubject.startsWith("Group/")) { - // patientList = getPatientListFromGroup(theSubject, theRegistry, - // thePatientType, theGroupType); - // } else { - // ourLog.info(String.format("Subject member was not a Patient or a Group, so - // skipping. \n%s", theSubject)); - // } - - // return patientList; - // } - - // //TODO: replace this with version from base structures - // default List - // getPatientListFromGroup(String subjectGroupId, DaoRegistry theRegistry, - // Class thePatientType, Class theGroupType){ - // List patientList = new ArrayList<>(); - - // IBaseResource baseGroup = resolveById(theRegistry, theGroupType, - // subjectGroupId); - // if (baseGroup == null) { - // throw new RuntimeException("Could not find Group: " + subjectGroupId); - // } - - // Group group = (Group)baseGroup; - // group.getMember().forEach(member -> { - // Reference reference = member.getEntity(); - // if (reference.getReference().getValue().startsWith("/Patient")) { - // ensurePatient(reference.getReference().getValue(), theRegistry, - // thePatientType); - // patientList.add(reference); - // } else if (reference.getReference().getValue().startsWith("/Group")) { - // patientList.addAll(getPatientListFromGroup(reference.getReference().getValue(), - // theRegistry, thePatientType, theGroupType)); - // } else { - // ourLog.info(String.format("Group member was not a Patient or a Group, so - // skipping. \n%s", reference.getReference())); - // } - // }); - - // return patientList; - // } -} diff --git a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/VersionUtilities.java b/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/VersionUtilities.java deleted file mode 100644 index 10ae86684..000000000 --- a/plugin/utility/src/main/java/org/opencds/cqf/ruler/utility/VersionUtilities.java +++ /dev/null @@ -1,89 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import java.util.List; -import java.util.function.Function; - -import org.hl7.fhir.instance.model.api.IBaseResource; - -/** - * This interface provides utilities for handling multiple business versions of FHIR Resources. - */ -public interface VersionUtilities { - /** - * This function compares two versions using semantic versioning. - * - * @param version1 the first version to compare - * @param version2 the second version to compare - * @return 0 if versions are equal, 1 if version1 is greater than version2, and -1 otherwise - */ - default int compareVersions(String version1, String version2) { - // Treat null as MAX VERSION - if (version1 == null && version2 == null) { - return 0; - } - - if (version1 != null && version2 == null) { - return -1; - } - - if (version1 == null && version2 != null) { - return 1; - } - - String[] string1Vals = version1.split("\\."); - String[] string2Vals = version2.split("\\."); - - int length = Math.max(string1Vals.length, string2Vals.length); - - for (int i = 0; i < length; i++) { - Integer v1 = i < string1Vals.length ? Integer.parseInt(string1Vals[i]) : 0; - Integer v2 = i < string2Vals.length ? Integer.parseInt(string2Vals[i]) : 0; - - // Making sure Version1 bigger than version2 - if (v1 > v2) { - return 1; - } - // Making sure Version1 smaller than version2 - else if (v1 < v2) { - return -1; - } - } - - // Both are equal - return 0; - } - - /*** - * Given a list of FHIR Resources that have the same name, choose the one with - * the matching version. - * - * @param an IBaseResource type - * @param theResources a list of Resources to select from - * @param theVersion the version of the Resource to select - * @param theGetVersion a function to access version information for the ResourceType - * @return the Resource with a matching version, or the highest version - * otherwise. - */ - default ResourceType selectFromList(List theResources, String theVersion, - Function theGetVersion) { - ResourceType library = null; - ResourceType maxVersion = null; - for (ResourceType l : theResources) { - String currentVersion = theGetVersion.apply(l); - if (theVersion == null && currentVersion == null || theVersion != null && theVersion.equals(currentVersion)) { - library = l; - } - - if (maxVersion == null || compareVersions(currentVersion, theGetVersion.apply(maxVersion)) >= 0) { - maxVersion = l; - } - } - - // If we were not given a version, return the highest found - if ((theVersion == null || library == null) && maxVersion != null) { - return maxVersion; - } - - return library; - } -} diff --git a/plugin/utility/src/main/resources/META-INF/spring.factories b/plugin/utility/src/main/resources/META-INF/spring.factories deleted file mode 100644 index e69de29bb..000000000 diff --git a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ClientUtilitiesTest.java b/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ClientUtilitiesTest.java deleted file mode 100644 index 2671da3d2..000000000 --- a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ClientUtilitiesTest.java +++ /dev/null @@ -1,72 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - -import java.util.Collections; -import java.util.List; - -import org.hl7.fhir.dstu3.model.Endpoint; -import org.hl7.fhir.dstu3.model.StringType; -import org.junit.jupiter.api.Test; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.interceptor.BasicAuthInterceptor; - -public class ClientUtilitiesTest implements ClientUtilities { - @Test - public void testCreateClient() { - IGenericClient client = this.createClient(FhirContext.forR4Cached(), "http://test.com"); - - assertNotNull(client); - assertEquals("http://test.com", client.getServerBase()); - } - - @Test - public void testRegisterAuth() { - IGenericClient client = this.createClient(FhirContext.forR4Cached(), "http://test.com"); - this.registerBasicAuth(client, "user", "password"); - - List interceptors = client.getInterceptorService().getAllRegisteredInterceptors(); - - Object authInterceptor = interceptors.get(0); - assertTrue(authInterceptor instanceof BasicAuthInterceptor); - } - - @Test - public void testRegisterHeaders() { - IGenericClient client = this.createClient(FhirContext.forR4Cached(), "http://test.com"); - this.registerHeaders(client, "Basic: XYZ123"); - - List interceptors = client.getInterceptorService().getAllRegisteredInterceptors(); - - Object interceptor = interceptors.get(0); - assertTrue(interceptor instanceof HeaderInjectionInterceptor); - } - - @Test - public void testRejectInvalidHeaders() { - assertThrows(IllegalArgumentException.class, () -> { - IGenericClient client = this.createClient(FhirContext.forR4Cached(), "http://test.com"); - this.registerHeaders(client, "BasicXYZ123"); - }); - } - - @Test - public void testClientForEndpoint() { - Endpoint endpoint = new Endpoint(); - endpoint.setAddress("http://test.com"); - - endpoint.setHeader(Collections.singletonList(new StringType("Basic: XYZ123"))); - IGenericClient client = this.createClient(endpoint); - - assertEquals("http://test.com", client.getServerBase()); - List interceptors = client.getInterceptorService().getAllRegisteredInterceptors(); - - Object interceptor = interceptors.get(0); - assertTrue(interceptor instanceof HeaderInjectionInterceptor); - } -} diff --git a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/MultiTenantResolutionUtilitiesIT.java b/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/MultiTenantResolutionUtilitiesIT.java deleted file mode 100644 index 5ff65fc39..000000000 --- a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/MultiTenantResolutionUtilitiesIT.java +++ /dev/null @@ -1,74 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; - -import org.hl7.fhir.r4.model.IntegerType; -import org.hl7.fhir.r4.model.Patient; -import org.hl7.fhir.r4.model.StringType; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.jupiter.api.extension.ExtendWith; -import org.opencds.cqf.ruler.Application; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import ca.uhn.fhir.interceptor.model.RequestPartitionId; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.model.config.PartitionSettings; -import ca.uhn.fhir.jpa.partition.PartitionManagementProvider; -import ca.uhn.fhir.jpa.partition.SystemRequestDetails; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { - Application.class }, properties = { - // Override is currently required when using MDM as the construction of the MDM - // beans are ambiguous as they are constructed multiple places. This is evident - // when running in a spring boot environment - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", - "spring.datasource.url=jdbc:h2:mem:dbr4-mt", - "hapi.fhir.fhir_version=r4" - -}) -@TestInstance(Lifecycle.PER_CLASS) -public class MultiTenantResolutionUtilitiesIT implements ResolutionUtilities { - - @Autowired - private DaoRegistry ourRegistry; - - @Autowired - private PartitionManagementProvider ourPartitionManagementProvider; - - @Autowired - protected PartitionSettings myPartitionSettings; - - @LocalServerPort - private int port; - - @BeforeAll - void beforeAll() { - myPartitionSettings.setPartitioningEnabled(true); - ourPartitionManagementProvider.addPartition(null, new IntegerType(1), new StringType("test"), new StringType("test partition")); - - SystemRequestDetails details = new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.fromPartitionId(1)); - - Patient patient2 = new Patient(); - patient2.setId("patienttwo"); - - ourRegistry.getResourceDao(Patient.class).update(patient2, details); - } - - @Test - public void testResolveById() { - // Resolve on tenant succeeds - SystemRequestDetails details = new SystemRequestDetails().setRequestPartitionId(RequestPartitionId.fromPartitionId(1)); - Patient patient = this.resolveById(ourRegistry, Patient.class, "patienttwo", details); - assertNotNull(patient); - assertEquals("patienttwo", patient.getIdElement().getIdPart()); - } -} diff --git a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ResolutionUtilitiesIT.java b/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ResolutionUtilitiesIT.java deleted file mode 100644 index 1a25dd381..000000000 --- a/plugin/utility/src/test/java/org/opencds/cqf/ruler/utility/ResolutionUtilitiesIT.java +++ /dev/null @@ -1,160 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertThrows; - -import org.hl7.fhir.r4.model.Library; -import org.hl7.fhir.r4.model.Observation; -import org.hl7.fhir.r4.model.Patient; -import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.TestInstance; -import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.junit.jupiter.api.extension.ExtendWith; -import org.opencds.cqf.ruler.Application; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; - -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.model.config.PartitionSettings; - -@ExtendWith(SpringExtension.class) -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { - Application.class }, properties = { - // Override is currently required when using MDM as the construction of the MDM - // beans are ambiguous as they are constructed multiple places. This is evident - // when running in a spring boot environment - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", - "spring.datasource.url=jdbc:h2:mem:dbr4-mt", - "hapi.fhir.fhir_version=r4" - -}) -@TestInstance(Lifecycle.PER_CLASS) -public class ResolutionUtilitiesIT implements ResolutionUtilities { - - @Autowired - private DaoRegistry ourRegistry; - - @LocalServerPort - private int port; - - @Autowired - protected PartitionSettings myPartitionSettings; - - @BeforeAll - void beforeAll() { - // Spring reusues application context, so need to set this because there are multi-tenant tests - myPartitionSettings.setPartitioningEnabled(false); - - Library library1 = new Library().setName("TestLibrary").setVersion("1.0.0") - .setUrl("http://test.com/Library/TestLibrary"); - library1.setId("libraryone"); - ourRegistry.getResourceDao(Library.class).update(library1); - - Library library2 = new Library().setName("TestLibrary").setVersion("2.0.0") - .setUrl("http://test.com/Library/TestLibrary"); - library2.setId("librarytwo"); - ourRegistry.getResourceDao(Library.class).update(library2); - - Patient patient = new Patient(); - patient.setId("patientone"); - ourRegistry.getResourceDao(Patient.class).update(patient); - - Observation obs = new Observation(); - patient.setId("observationone"); - ourRegistry.getResourceDao(Observation.class).create(obs); - } - - @Test - public void testResolveByCanonicalUrl() { - // Versionless resolves latest version - Library lib = this.resolveByCanonicalUrl(ourRegistry, Library.class, "http://test.com/Library/TestLibrary"); - assertNotNull(lib); - assertEquals("2.0.0", lib.getVersion()); - - // Versioned resolves correct version - lib = this.resolveByCanonicalUrl(ourRegistry, Library.class, "http://test.com/Library/TestLibrary|1.0.0"); - assertNotNull(lib); - assertEquals("1.0.0", lib.getVersion()); - - // Non-url Resource type explodes - assertThrows(RuntimeException.class, () -> { - this.resolveByCanonicalUrl(ourRegistry, Patient.class, "http://test.com/Patient"); - }); - } - - @Test - @SuppressWarnings("unchecked") - public void testResolveByName() { - // Name only resolves latest version - Library lib = this.resolveByName(ourRegistry, Library.class, "TestLibrary"); - assertNotNull(lib); - assertEquals("2.0.0", lib.getVersion()); - - // Name only on resource dao resolves latest version - lib = (Library) this.resolveByName(ourRegistry.getResourceDao("Library"), "TestLibrary"); - assertNotNull(lib); - assertEquals("2.0.0", lib.getVersion()); - - // Non-name Resource type explodes - assertThrows(RuntimeException.class, () -> { - this.resolveByName(ourRegistry, Observation.class, "NotAName"); - }); - } - - @Test - public void testResolveByNameAndVersion() { - // Name only resolves latest version - Library lib = this.resolveByNameAndVersion(ourRegistry, Library.class, "TestLibrary", null); - assertNotNull(lib); - assertEquals("2.0.0", lib.getVersion()); - - // Version resolves correct version - lib = this.resolveByNameAndVersion(ourRegistry, Library.class, "TestLibrary", "1.0.0"); - assertNotNull(lib); - assertEquals("1.0.0", lib.getVersion()); - - // Non-name Resource type explodes - assertThrows(RuntimeException.class, () -> { - this.resolveByNameAndVersion(ourRegistry, Observation.class, "NotAName", null); - }); - } - - @Test - @SuppressWarnings("unchecked") - public void testResolveById() { - // Full Id resolves - Library lib = this.resolveById(ourRegistry, Library.class, "Library/librarytwo"); - assertNotNull(lib); - assertEquals("librarytwo", lib.getIdElement().getIdPart()); - - // Partial Id resolves - lib = this.resolveById(ourRegistry, Library.class, "libraryone"); - assertNotNull(lib); - assertEquals("libraryone", lib.getIdElement().getIdPart()); - - // FhirDao resolves - lib = (Library) this.resolveById(ourRegistry.getResourceDao("Library"), "Library/librarytwo"); - assertNotNull(lib); - assertEquals("librarytwo", lib.getIdElement().getIdPart()); - - // Doesn't exist explodes - assertThrows(RuntimeException.class, () -> { - this.resolveById(ourRegistry, Library.class, "librarythree"); - }); - - // Doesn't exist on partition explodes - assertThrows(RuntimeException.class, () -> { - this.resolveById(ourRegistry, Patient.class, "patientblahblah"); - }); - - // Mismatched Id types explodes - assertThrows(RuntimeException.class, () -> { - this.resolveById(ourRegistry, Library.class, "Patient/patientone"); - }); - } -} diff --git a/pom.xml b/pom.xml index 82f8f8c3d..992d54544 100644 --- a/pom.xml +++ b/pom.xml @@ -35,6 +35,7 @@ external test core + common plugin server diff --git a/server/pom.xml b/server/pom.xml index 3b692decb..772f57446 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -297,7 +298,7 @@ org.opencds.cqf.ruler - cqf-ruler-utility + cqf-ruler-common 0.5.0-SNAPSHOT runtime diff --git a/test/pom.xml b/test/pom.xml index 58f5d2657..6fc16fb35 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -9,6 +10,17 @@ cqf-ruler-test + + org.opencds.cqf.ruler + cqf-ruler-external + 0.5.0-SNAPSHOT + + + + org.opencds.cqf.ruler + cqf-ruler-common + 0.5.0-SNAPSHOT + ca.uhn.hapi.fhir @@ -72,15 +84,7 @@ org.junit.jupiter junit-jupiter-api - - - org.junit.jupiter - junit-jupiter-engine - - - org.opencds.cqf.ruler - cqf-ruler-external - 0.5.0-SNAPSHOT + compile diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java new file mode 100644 index 000000000..e3ab3fec6 --- /dev/null +++ b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java @@ -0,0 +1,26 @@ +package org.opencds.cqf.ruler.test; + +import org.springframework.beans.factory.annotation.Autowired; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; + +public class DaoIntegrationTest implements ResourceLoader { + + @Autowired + private FhirContext myCtx; + + @Autowired + DaoRegistry myDaoRegistry; + + @Override + public FhirContext getFhirContext() { + return myCtx; + } + + @Override + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } + +} diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java b/test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java new file mode 100644 index 000000000..db608bbb8 --- /dev/null +++ b/test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java @@ -0,0 +1,8 @@ +package org.opencds.cqf.ruler.test; + +import org.springframework.context.annotation.ComponentScan; + +@ComponentScan("org.opencds.cqf.ruler.external") +public class DaoOnlyConfig { + +} diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/ITestSupport.java b/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java similarity index 52% rename from test/src/main/java/org/opencds/cqf/ruler/test/ITestSupport.java rename to test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java index 6d325795a..26117f8c7 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/ITestSupport.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java @@ -8,67 +8,78 @@ import java.io.InputStreamReader; import java.net.URISyntaxException; import java.net.URL; +import java.nio.charset.StandardCharsets; import java.util.HashMap; import java.util.Map; import java.util.stream.Collectors; -import com.google.common.base.Charsets; - import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseResource; +import org.opencds.cqf.ruler.common.utility.DaoRegistryUser; +import org.opencds.cqf.ruler.common.utility.FhirContextUser; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; import ca.uhn.fhir.parser.IParser; -public interface ITestSupport { - @SuppressWarnings("unchecked") - default Object loadTransaction(String theLocation, FhirContext theFhirContext, DaoRegistry theDaoRegistry) +public interface ResourceLoader extends FhirContextUser, DaoRegistryUser { + + default Object loadTransaction(String theLocation) throws IOException { - String json = stringFromResource(theLocation); - IBaseBundle resource = (IBaseBundle) theFhirContext.newJsonParser().parseResource(json); - Object result = theDaoRegistry.getSystemDao().transaction(new SystemRequestDetails(), resource); - return result; + IBaseBundle resource = (IBaseBundle)readResource(theLocation); + return transaction(resource, new SystemRequestDetails()); } - default IBaseResource loadResource(String theLocation, FhirContext theFhirContext, DaoRegistry theDaoRegistry) + default IBaseResource readResource(String theLocation) throws IOException { - String json = stringFromResource(theLocation); - return loadResource("json", json, theFhirContext, theDaoRegistry); + String resourceString = stringFromResource(theLocation); + if (theLocation.endsWith("json")) { + return parseResource("json", resourceString); + } + else { + return parseResource("xml", resourceString); + } } - @SuppressWarnings("unchecked") - default IBaseResource loadResource(String encoding, String resourceString, FhirContext theFhirContext, - DaoRegistry theDaoRegistry) throws IOException { + public default IBaseResource parseResource(String encoding, String resourceString) { IParser parser; switch (encoding.toLowerCase()) { case "json": - parser = theFhirContext.newJsonParser(); + parser = getFhirContext().newJsonParser(); break; case "xml": - parser = theFhirContext.newXmlParser(); + parser = getFhirContext().newXmlParser(); break; default: - throw new RuntimeException( + throw new IllegalArgumentException( String.format("Expected encoding xml, or json. %s is not a valid encoding", encoding)); } - IBaseResource resource = parser.parseResource(resourceString); - if (theDaoRegistry == null) { - return resource; + + return parser.parseResource(resourceString); + } + + default IBaseResource loadResource(String theLocation) + throws IOException { + String resourceString = stringFromResource(theLocation); + if (theLocation.endsWith("json")) { + return loadResource("json", resourceString); } - IFhirResourceDao dao = theDaoRegistry.getResourceDao(resource.getIdElement().getResourceType()); - if (dao == null) { - return null; - } else { - dao.update(resource); + else { + return loadResource("xml", resourceString); + } + } + + default IBaseResource loadResource(String encoding, String resourceString) throws IOException { + IBaseResource resource = parseResource(encoding, resourceString); + if (getDaoRegistry() == null) { return resource; } + + update(resource); + return resource; } default String stringFromResource(String theLocation) throws IOException { @@ -80,33 +91,34 @@ default String stringFromResource(String theLocation) throws IOException { Resource resource = resourceLoader.getResource(theLocation); is = resource.getInputStream(); } - return IOUtils.toString(is, Charsets.UTF_8); + return IOUtils.toString(is, StandardCharsets.UTF_8); } - default Map uploadTests(String testDirectory, FhirContext fhirContext, - DaoRegistry daoRegistry) throws URISyntaxException, IOException { + default Map uploadTests(String testDirectory) throws URISyntaxException, IOException { URL url = this.getClass().getResource(testDirectory); File testDir = new File(url.toURI()); - return uploadTests(testDir.listFiles(), fhirContext, daoRegistry); + if(!testDir.exists()) { + throw new IllegalArgumentException(String.format("test directory %s does not exist.", testDirectory)); + } + return uploadTests(testDir.listFiles()); } - default Map uploadTests(File[] files, FhirContext fhirContext, DaoRegistry daoRegistry) + default Map uploadTests(File[] files) throws IOException { - Map resources = new HashMap(); + Map resources = new HashMap<>(); for (File file : files) { // depth first if (file.isDirectory()) { - resources.putAll(uploadTests(file.listFiles(), fhirContext, daoRegistry)); + resources.putAll(uploadTests(file.listFiles())); } } for (File file : files) { if (file.isFile()) { BufferedReader reader = new BufferedReader( - new InputStreamReader(new FileInputStream(file.getAbsolutePath()), "UTF-8")); + new InputStreamReader(new FileInputStream(file.getAbsolutePath()), StandardCharsets.UTF_8)); String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); reader.close(); - IBaseResource resource = loadResource(FilenameUtils.getExtension(file.getAbsolutePath()), resourceString, - fhirContext, daoRegistry); + IBaseResource resource = loadResource(FilenameUtils.getExtension(file.getAbsolutePath()), resourceString); resources.put(resource.getIdElement().getIdPart(), resource); } } diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java new file mode 100644 index 000000000..845577283 --- /dev/null +++ b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java @@ -0,0 +1,50 @@ +package org.opencds.cqf.ruler.test; + +import org.junit.jupiter.api.BeforeEach; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.web.server.LocalServerPort; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.rest.client.api.IGenericClient; +import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; + +public class RestIntegrationTest implements ResourceLoader { + + @Autowired + private FhirContext myCtx; + + @Autowired + DaoRegistry myDaoRegistry; + + @LocalServerPort + private int myPort; + + private IGenericClient myClient; + + @Override + public FhirContext getFhirContext() { + return myCtx; + } + + @Override + public DaoRegistry getDaoRegistry() { + return myDaoRegistry; + } + + protected IGenericClient getClient() { + return myClient; + } + + protected int getPort() { + return myPort; + } + + @BeforeEach + void baseBeforeEach() { + myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); + myCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); + String ourServerBase = "http://localhost:" + myPort + "/fhir/"; + myClient = myCtx.newRestfulGenericClient(ourServerBase); + } +} diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/ClientUtilities.java b/test/src/main/java/org/opencds/cqf/ruler/test/Urls.java similarity index 68% rename from test/src/main/java/org/opencds/cqf/ruler/test/ClientUtilities.java rename to test/src/main/java/org/opencds/cqf/ruler/test/Urls.java index 49a380d89..dbb4fe404 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/ClientUtilities.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/Urls.java @@ -5,8 +5,10 @@ * and * setting up authentication */ -public interface ClientUtilities { - String SERVER_URL = "http://localhost:%d/fhir"; +public class Urls { + private Urls() {} + + public static final String SERVER_URL = "http://localhost:%d/fhir"; /** * Creates an client url given a url template and port @@ -15,7 +17,7 @@ public interface ClientUtilities { * @param thePort the port to use * @return String for the client url */ - default String getClientUrl(String theUrlTemplate, Integer thePort) { + public static String getUrl(String theUrlTemplate, Integer thePort) { return String.format(theUrlTemplate, thePort); } @@ -25,7 +27,7 @@ default String getClientUrl(String theUrlTemplate, Integer thePort) { * @param thePort the port to use * @return String for the client url */ - default String getClientUrl(Integer thePort) { - return getClientUrl(SERVER_URL, thePort); + public static String getUrl(Integer thePort) { + return getUrl(SERVER_URL, thePort); } } diff --git a/test/src/test/java/org/opencds/cqf/ruler/test/ClientUtilitiesTest.java b/test/src/test/java/org/opencds/cqf/ruler/test/UrlsTest.java similarity index 86% rename from test/src/test/java/org/opencds/cqf/ruler/test/ClientUtilitiesTest.java rename to test/src/test/java/org/opencds/cqf/ruler/test/UrlsTest.java index fee97d010..ac760205f 100644 --- a/test/src/test/java/org/opencds/cqf/ruler/test/ClientUtilitiesTest.java +++ b/test/src/test/java/org/opencds/cqf/ruler/test/UrlsTest.java @@ -6,13 +6,13 @@ import org.apache.commons.validator.routines.UrlValidator; import org.junit.jupiter.api.Test; -public class ClientUtilitiesTest implements ClientUtilities { +public class UrlsTest { @Test public void testClientUrlWithTemplate() { String template = "http://localhost:%d/fhir"; Integer port = 8084; - String url = getClientUrl(template, port); + String url = Urls.getUrl(template, port); String[] schemes = {"http","https"}; UrlValidator urlValidator = new UrlValidator(schemes, UrlValidator.ALLOW_LOCAL_URLS); @@ -26,7 +26,7 @@ public void testClientUrlWithTemplate() { public void testClientUrlWithoutTemplate() { Integer port = 8084; - String url = getClientUrl(port); + String url = Urls.getUrl(port); String[] schemes = {"http","https"}; UrlValidator urlValidator = new UrlValidator(schemes, UrlValidator.ALLOW_LOCAL_URLS); From 9105b7e703e5f0c181bc11ebbe39e3f2f8fc59c2 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Sun, 23 Jan 2022 22:51:14 -0700 Subject: [PATCH 02/12] WIP Submit Data Provider --- .../cr/r4/provider/SubmitDataProviderIT.java | 22 +------------------ .../devtools/dstu3/CodeSystemProviderIT.java | 7 ------ 2 files changed, 1 insertion(+), 28 deletions(-) diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java index 057c1eb17..0580fc039 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java @@ -18,12 +18,8 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; - - @ExtendWith(SpringExtension.class) @SpringBootTest(classes = { DaoOnlyConfig.class }, properties = { "scheduling_disabled=true", @@ -35,26 +31,10 @@ }) @EnableAutoConfiguration(exclude=QuartzAutoConfiguration.class) public class SubmitDataProviderIT extends DaoIntegrationTest implements IdCreator, ResourceCreator { - - @Autowired - DaoRegistry myDaoRegistry; - - @Autowired - FhirContext myFhirContext; - + @Autowired SubmitDataProvider mySubmitDataProvider; - @Override - public DaoRegistry getDaoRegistry() { - return myDaoRegistry; - } - - @Override - public FhirContext getFhirContext() { - return myFhirContext; - } - @Test public void testSubmitData() { // Create a MR and a few resources diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java index 5146d3680..e5b11b454 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java @@ -158,13 +158,6 @@ public void testDSTU3UpdateCodeSystems() throws IOException { log.info("Finished Test DSTU3 Update Code Systems"); } - // Old way - // private IBundleProvider performCodeSystemSearchByUrl(String rxNormUrl) { - // return this.myDaoRegistry.getResourceDao(CodeSystem.class) - // .search(SearchParameterMap.newSynchronous().add(CodeSystem.SP_URL, new UriParam(rxNormUrl))); - // } - - // New way private IBundleProvider performCodeSystemSearchByUrl(String rxNormUrl) { return search(CodeSystem.class, Searches.byUrl(rxNormUrl)); } From 630c86efedcfca785b2f34a39135f3feba097fff Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 24 Jan 2022 08:18:17 -0700 Subject: [PATCH 03/12] Adds docs, more cleanup --- README.md | 62 +++++ common/README.md | 60 ----- common/pom.xml | 44 ---- .../DaoRegistryOperationProvider.java | 6 +- .../cqf/ruler}/utility/Canonicals.java | 2 +- .../opencds/cqf/ruler}/utility/Clients.java | 2 +- .../cqf/ruler}/utility/DaoRegistryUser.java | 2 +- .../cqf/ruler}/utility/FhirContextUser.java | 2 +- .../cqf/ruler}/utility/FhirVersions.java | 2 +- .../utility/HeaderInjectionInterceptor.java | 2 +- .../opencds/cqf/ruler}/utility/IdCreator.java | 2 +- .../org/opencds/cqf/ruler}/utility/Ids.java | 2 +- .../cqf/ruler}/utility/Operations.java | 2 +- .../cqf/ruler}/utility/Reflections.java | 2 +- .../ruler}/utility/ResolutionUtilities.java | 2 +- .../cqf/ruler}/utility/ResourceCreator.java | 2 +- .../opencds/cqf/ruler}/utility/Searches.java | 2 +- .../ruler}/utility/TypedBundleProvider.java | 2 +- .../opencds/cqf/ruler}/utility/Versions.java | 2 +- .../cqf/ruler/ElasticsearchLastNR4IT.java | 2 +- .../cqf/ruler/ExampleServerDstu2IT.java | 17 +- .../cqf/ruler/ExampleServerDstu3IT.java | 4 +- .../opencds/cqf/ruler/ExampleServerR4IT.java | 4 +- .../opencds/cqf/ruler/ExampleServerR5IT.java | 4 +- .../cqf/ruler/MultitenantServerR4IT.java | 4 +- .../cqf/ruler}/utility/ClientsTest.java | 2 +- .../cqf/ruler}/utility/FhirVersionsTest.java | 2 +- .../opencds/cqf/ruler}/utility/IdsTest.java | 2 +- .../cqf/ruler}/utility/ReflectionsTest.java | 2 +- .../cqf/ruler}/utility/VersionsTest.java | 2 +- docs/diagrams/modules.drawio.svg | 224 ++++++++++++++++++ plugin/case-reporting/pom.xml | 6 +- .../r4/MeasureDataProcessProvider.java | 4 +- .../r4/MeasureDataProcessProviderIT.java | 49 +--- plugin/cds-hooks/pom.xml | 6 +- .../discovery/DiscoveryResolutionR4.java | 2 +- .../discovery/DiscoveryResolutionStu3.java | 2 +- .../ruler/cdshooks/dstu3/CdsHooksServlet.java | 2 +- .../ruler/cdshooks/r4/CdsHooksServlet.java | 2 +- plugin/cpg/pom.xml | 8 +- .../provider/LibraryEvaluationProvider.java | 6 +- .../provider/LibraryEvaluationProviderIT.java | 84 ++----- plugin/cql/pom.xml | 6 +- .../cql/ElmCacheResourceChangeListener.java | 2 +- .../ruler/cql/JpaLibraryContentProvider.java | 2 +- .../cqf/ruler/cql/JpaTerminologyProvider.java | 2 +- .../org/opencds/cqf/ruler/cql/Libraries.java | 2 +- plugin/cr/pom.xml | 6 +- .../cqf/ruler/cr/r4/ExpressionEvaluation.java | 2 +- .../cr/r4/provider/SubmitDataProvider.java | 2 +- .../cr/dstu3/ExpressionEvaluationIT.java | 4 +- .../ActivityDefinitionApplyProviderIT.java | 4 +- .../PlanDefinitionApplyProviderIT.java | 4 +- .../ruler/cr/r4/ExpressionEvaluationIT.java | 4 +- .../ActivityDefinitionApplyProviderIT.java | 4 +- .../provider/MeasureEvaluateProviderIT.java | 4 +- .../PlanDefinitionApplyProviderIT.java | 4 +- .../cr/r4/provider/SubmitDataProviderIT.java | 8 +- plugin/dev-tools/pom.xml | 6 +- .../dstu3/CacheValueSetsProvider.java | 2 +- .../dstu3/CodeSystemUpdateProvider.java | 2 +- .../devtools/r4/CacheValueSetsProvider.java | 2 +- .../devtools/r4/CodeSystemUpdateProvider.java | 2 +- .../dstu3/CacheValueSetsProviderIT.java | 4 +- .../devtools/dstu3/CodeSystemProviderIT.java | 6 +- .../devtools/r4/CacheValueSetsProviderIT.java | 4 +- .../devtools/r4/CodeSystemProviderIT.java | 6 +- .../cqf/ruler/hello/HelloWorldProviderIT.java | 4 +- plugin/pom.xml | 11 +- plugin/ra/pom.xml | 6 +- .../cqf/ruler/ra/r4/ReportProvider.java | 8 +- .../cqf/ruler/ra/r4/ReportProviderIT.java | 70 ++---- plugin/sdc/pom.xml | 6 +- .../cqf/ruler/sdc/dstu3/ExtractProvider.java | 2 +- .../ruler/sdc/dstu3/TransformProvider.java | 2 +- .../cqf/ruler/sdc/r4/ExtractProvider.java | 2 +- .../cqf/ruler/sdc/r4/TransformProvider.java | 2 +- .../cqf/ruler/sdc/r4/ExtractProviderIT.java | 46 +--- .../ruler/security/dstu3/OAuthProviderIT.java | 4 +- .../ruler/security/r4/OAuthProviderIT.java | 4 +- pom.xml | 1 - server/pom.xml | 6 - test/pom.xml | 4 +- .../cqf/ruler/test/ResourceLoader.java | 4 +- 84 files changed, 441 insertions(+), 477 deletions(-) delete mode 100644 common/README.md delete mode 100644 common/pom.xml rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/provider/DaoRegistryOperationProvider.java (75%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/Canonicals.java (98%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/Clients.java (99%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/DaoRegistryUser.java (98%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/FhirContextUser.java (70%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/FhirVersions.java (96%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/HeaderInjectionInterceptor.java (96%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/IdCreator.java (92%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/Ids.java (99%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/Operations.java (98%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/Reflections.java (99%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/ResolutionUtilities.java (99%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/ResourceCreator.java (96%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/Searches.java (96%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/TypedBundleProvider.java (97%) rename {common/src/main/java/org/opencds/cqf/ruler/common => core/src/main/java/org/opencds/cqf/ruler}/utility/Versions.java (98%) rename {common/src/test/java/org/opencds/cqf/ruler/common => core/src/test/java/org/opencds/cqf/ruler}/utility/ClientsTest.java (98%) rename {common/src/test/java/org/opencds/cqf/ruler/common => core/src/test/java/org/opencds/cqf/ruler}/utility/FhirVersionsTest.java (93%) rename {common/src/test/java/org/opencds/cqf/ruler/common => core/src/test/java/org/opencds/cqf/ruler}/utility/IdsTest.java (96%) rename {common/src/test/java/org/opencds/cqf/ruler/common => core/src/test/java/org/opencds/cqf/ruler}/utility/ReflectionsTest.java (98%) rename {common/src/test/java/org/opencds/cqf/ruler/common => core/src/test/java/org/opencds/cqf/ruler}/utility/VersionsTest.java (97%) create mode 100644 docs/diagrams/modules.drawio.svg diff --git a/README.md b/README.md index 7ed811dc3..c7353928d 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,12 @@ To run the cqf-ruler directory from this project use: `java -jar server/target/cqf-ruler-server-*.war` +### Module Structure + +The cqf-ruler uses the hapi-fhir-jpaserver-starter project as a base. On top of that, it adds an extensible API and utility functions to allow creating plugins which contain functionality for a specific IG. This diagram shows how it's structured + +![Module Diagram](docs/diagrams/modules.drawio.svg) + ### Plugins Plugins use Spring Boot [autoconfiguration](https://docs.spring.io/spring-boot/docs/2.0.0.M3/reference/html/boot-features-developing-auto-configuration.html) to be loaded at runtime. Spring searches for a `spring.factories` file in the meta-data of the jars on the classpath, and the `spring.factories` file points to the root Spring config for the plugin. For example, the content of the `resources/META-INF/spring.factories` file might be: @@ -104,6 +110,62 @@ To this end: * The CQF Ruler project has adopted the HAPI Coding Conventions: * Plugins should generally use the "hapi.fhir" prefix for configuration properties +## Utility Guidelines + +### Types of Utilities + +In general, reusable utilities are separated along two different dimensions, Classes and Behaviors. + +Class specific utilities are functions that are associated with specific class or interface, and add functionality to that class. + +Behavior specific utilities allow the reuse of behavior across many different classes. + +### Class Specific Utilities + +Utility or Helper methods that are associated with a single class should go into a class that has the pluralized name of the associated class. For example, utilities for `Client` should go into the `Clients` class. The ensures that the utility class is focused on one aspect and allows for more readable code: + +`Clients.forUrl("test.com")` + +as opposed to: + +`ClientUtilities.createClient("test.com")` + +or, if you put unrelated code into the class, you might end up with something like: + +`Clients.parseRegex()` + +If the code doesn't read clearly after you've added an utility, consider that it may not be in the right place. + +In general, all the functions for this type of utility should be `static`. No internal state should be maintained (`static final`, or immutable, state is ok). If you final that your utility class contains mutable state, consider an alternate design. + +Examples + +* Factory functions +* Adding behavior to a class you can't extend + +### Behavior Specific Utilities + +If there is behavior you'd like to share across many classes, model that as an interface and use a name that follows the pattern `"ThingDoer"`. For example, all the classes that access a database might be `DatabaseUser`. Use `default` interface implementations to write logic that can be shared many places. The interfaces themselves shouldn't have mutable state (again `static final` is ok). If it's necessary for the for shared logic to have access to state, model that as an method without a default implementation. For example: + +```java +interface DatabaseUser { + Database getDb(); + default Entity read(Id id) { + return getDb().connect().find(id); + } +} +``` + +In the above example any class that has access to a `Database` can inherit the `read` behavior. + +Examples + +* Cross-cutting concerns + +### Discovery + +Following conventions such as these make it easier for the next developer to find code that's already been implemented as opposed to reinventing the wheel. + ## Commit Policy All new development takes place on `` branches off `master`. Once feature development on the branch is complete, the feature branch is submitted to `master` as a PR. The PR is reviewed by maintainers and regression testing by the CI build occurs. diff --git a/common/README.md b/common/README.md deleted file mode 100644 index eb10079ea..000000000 --- a/common/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# Common - -This modules provides cross-cutting utility functions and base classes for cqf-ruler plugins. - -## Guidelines - -### Types of Utilities - -In general, reusable utilities are separated along two different dimensions, Classes and Behaviors. - -Class specific utilities are functions that are associated with specific class or interface, and add functionality to that class. - -Behavior specific utilities allow the reuse of behavior across many different classes. - -### Class Specific Utilities - -Utility or Helper methods that are associated with a single class should go into a class that has the pluralized name of the associated class. For example, utilities for `Client` should go into the `Clients` class. The ensures that the utility class is focused on one aspect and allows for more readable code: - -`Clients.forUrl("test.com")` - -as opposed to: - -`ClientUtilities.createClient("test.com")` - -or, if you put unrelated code into the class, you might end up with something like: - -`Clients.parseRegex()` - -If the code doesn't read clearly after you've added an utility, consider that it may not be in the right place. - -In general, all the functions for this type of utility should be `static`. No internal state should be maintained (`static final`, or immutable, state is ok). If you final that your utility class contains mutable state, consider an alternate design. - -Examples - -* Factory functions -* Adding behavior to a class you can't extend - -### Behavior Specific Utilities - -If there is behavior you'd like to share across many classes, model that as an interface and use a name that follows the pattern `"ThingDoer"`. For example, all the classes that access a database might be `DatabaseUser`. Use `default` interface implementations to write logic that can be shared many places. The interfaces themselves shouldn't have mutable state (again `static final` is ok). If it's necessary for the for shared logic to have access to state, model that as an method without a default implementation. For example: - -```java -interface DatabaseUser { - Database getDb(); - - default Entity read(Id id) { - return getDb().connect().find(id); - } -} -``` - -In the above example any class that has access to a `Database` can inherit the `read` behavior. - -Examples - -* Cross-cutting concerns - -### Discovery - -Following conventions such as these make it easier for the next developer to find code that's already been implemented as opposed to reinventing the wheel. diff --git a/common/pom.xml b/common/pom.xml deleted file mode 100644 index 3c5825681..000000000 --- a/common/pom.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - 4.0.0 - - org.opencds.cqf.ruler - cqf-ruler - 0.5.0-SNAPSHOT - - - cqf-ruler-common - - - - org.opencds.cqf.ruler - cqf-ruler-external - 0.5.0-SNAPSHOT - - - org.opencds.cqf.ruler - cqf-ruler-core - 0.5.0-SNAPSHOT - - - javax.servlet - javax.servlet-api - - - - org.springframework.boot - spring-boot-starter-test - test - - - - - - - org.apache.maven.plugins - maven-checkstyle-plugin - - - - diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/provider/DaoRegistryOperationProvider.java b/core/src/main/java/org/opencds/cqf/ruler/provider/DaoRegistryOperationProvider.java similarity index 75% rename from common/src/main/java/org/opencds/cqf/ruler/common/provider/DaoRegistryOperationProvider.java rename to core/src/main/java/org/opencds/cqf/ruler/provider/DaoRegistryOperationProvider.java index bc8170dbf..efdb43d75 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/provider/DaoRegistryOperationProvider.java +++ b/core/src/main/java/org/opencds/cqf/ruler/provider/DaoRegistryOperationProvider.java @@ -1,8 +1,8 @@ -package org.opencds.cqf.ruler.common.provider; +package org.opencds.cqf.ruler.provider; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.DaoRegistryUser; -import org.opencds.cqf.ruler.common.utility.FhirContextUser; +import org.opencds.cqf.ruler.utility.DaoRegistryUser; +import org.opencds.cqf.ruler.utility.FhirContextUser; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Canonicals.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java similarity index 98% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/Canonicals.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java index d76a97b1a..41a839f7c 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Canonicals.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Clients.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Clients.java similarity index 99% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/Clients.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/Clients.java index fd514319c..cdfec2a67 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Clients.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Clients.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/DaoRegistryUser.java b/core/src/main/java/org/opencds/cqf/ruler/utility/DaoRegistryUser.java similarity index 98% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/DaoRegistryUser.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/DaoRegistryUser.java index f8c93a830..39a320f9b 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/DaoRegistryUser.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/DaoRegistryUser.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirContextUser.java b/core/src/main/java/org/opencds/cqf/ruler/utility/FhirContextUser.java similarity index 70% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirContextUser.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/FhirContextUser.java index 372fa7016..15a5ec101 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirContextUser.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/FhirContextUser.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import ca.uhn.fhir.context.FhirContext; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirVersions.java b/core/src/main/java/org/opencds/cqf/ruler/utility/FhirVersions.java similarity index 96% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirVersions.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/FhirVersions.java index e86d45fda..058cf6073 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/FhirVersions.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/FhirVersions.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/HeaderInjectionInterceptor.java b/core/src/main/java/org/opencds/cqf/ruler/utility/HeaderInjectionInterceptor.java similarity index 96% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/HeaderInjectionInterceptor.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/HeaderInjectionInterceptor.java index 9ad44edf1..7b3daa21a 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/HeaderInjectionInterceptor.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/HeaderInjectionInterceptor.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import java.io.IOException; import java.util.HashMap; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/IdCreator.java b/core/src/main/java/org/opencds/cqf/ruler/utility/IdCreator.java similarity index 92% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/IdCreator.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/IdCreator.java index 153269a33..4908343f7 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/IdCreator.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/IdCreator.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Ids.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java similarity index 99% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/Ids.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java index 65d2aabcb..4c3731c28 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Ids.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Operations.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Operations.java similarity index 98% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/Operations.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/Operations.java index d27568f2b..c16ec014c 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Operations.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Operations.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import java.util.ArrayList; import java.util.Calendar; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Reflections.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Reflections.java similarity index 99% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/Reflections.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/Reflections.java index 51a0dd32f..2eb93efd7 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Reflections.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Reflections.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResolutionUtilities.java b/core/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java similarity index 99% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/ResolutionUtilities.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java index 67baec05f..1cd0fcac1 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResolutionUtilities.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import java.util.List; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResourceCreator.java b/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java similarity index 96% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/ResourceCreator.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java index 6171f791c..407047767 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/ResourceCreator.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Searches.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java similarity index 96% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/Searches.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java index 74db5c2ba..e88f5b92c 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Searches.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/TypedBundleProvider.java b/core/src/main/java/org/opencds/cqf/ruler/utility/TypedBundleProvider.java similarity index 97% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/TypedBundleProvider.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/TypedBundleProvider.java index 767b1ef80..f7d3aa204 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/TypedBundleProvider.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/TypedBundleProvider.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Versions.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Versions.java similarity index 98% rename from common/src/main/java/org/opencds/cqf/ruler/common/utility/Versions.java rename to core/src/main/java/org/opencds/cqf/ruler/utility/Versions.java index 6e20fe5c2..e4990677d 100644 --- a/common/src/main/java/org/opencds/cqf/ruler/common/utility/Versions.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Versions.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; diff --git a/core/src/test/java/org/opencds/cqf/ruler/ElasticsearchLastNR4IT.java b/core/src/test/java/org/opencds/cqf/ruler/ElasticsearchLastNR4IT.java index 59e29920d..edd85f4ea 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/ElasticsearchLastNR4IT.java +++ b/core/src/test/java/org/opencds/cqf/ruler/ElasticsearchLastNR4IT.java @@ -39,7 +39,7 @@ // import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; // import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -// @ExtendWith(SpringExtension.class) +// // @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = // { // "spring.batch.job.enabled=false", diff --git a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu2IT.java b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu2IT.java index 791b22049..36456e863 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu2IT.java +++ b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu2IT.java @@ -1,22 +1,21 @@ package org.opencds.cqf.ruler; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.hl7.fhir.instance.model.api.IIdType; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.web.server.LocalServerPort; + import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.model.dstu2.resource.Patient; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -import org.hl7.fhir.instance.model.api.IIdType; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import static org.junit.jupiter.api.Assertions.assertEquals; -@ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = { "spring.batch.job.enabled=false", diff --git a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java index a021b9e60..0bb2fd483 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java +++ b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerDstu3IT.java @@ -6,11 +6,9 @@ import org.hl7.fhir.instance.model.api.IIdType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; @@ -18,7 +16,7 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = { "spring.datasource.url=jdbc:h2:mem:dbr3", "hapi.fhir.fhir_version=dstu3", diff --git a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR4IT.java b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR4IT.java index 80bf9bf4a..3c60fe8c8 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR4IT.java +++ b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR4IT.java @@ -14,10 +14,8 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; @@ -26,7 +24,7 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.util.BundleUtil; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = { "spring.batch.job.enabled=false", diff --git a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR5IT.java b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR5IT.java index 997bf42ca..f93c883d0 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR5IT.java +++ b/core/src/test/java/org/opencds/cqf/ruler/ExampleServerR5IT.java @@ -10,10 +10,8 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.context.FhirVersionEnum; @@ -21,7 +19,7 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = { "spring.batch.job.enabled=false", diff --git a/core/src/test/java/org/opencds/cqf/ruler/MultitenantServerR4IT.java b/core/src/test/java/org/opencds/cqf/ruler/MultitenantServerR4IT.java index 50ab227bd..85c04ecfe 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/MultitenantServerR4IT.java +++ b/core/src/test/java/org/opencds/cqf/ruler/MultitenantServerR4IT.java @@ -9,10 +9,8 @@ import org.hl7.fhir.r4.model.Patient; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.api.CacheControlDirective; @@ -22,7 +20,7 @@ import ca.uhn.fhir.rest.client.interceptor.UrlTenantSelectionInterceptor; import ca.uhn.fhir.rest.server.provider.ProviderConstants; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties = { "spring.batch.job.enabled=false", diff --git a/common/src/test/java/org/opencds/cqf/ruler/common/utility/ClientsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/ClientsTest.java similarity index 98% rename from common/src/test/java/org/opencds/cqf/ruler/common/utility/ClientsTest.java rename to core/src/test/java/org/opencds/cqf/ruler/utility/ClientsTest.java index 56d6b3a60..ece2c72b9 100644 --- a/common/src/test/java/org/opencds/cqf/ruler/common/utility/ClientsTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/ClientsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNotNull; diff --git a/common/src/test/java/org/opencds/cqf/ruler/common/utility/FhirVersionsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/FhirVersionsTest.java similarity index 93% rename from common/src/test/java/org/opencds/cqf/ruler/common/utility/FhirVersionsTest.java rename to core/src/test/java/org/opencds/cqf/ruler/utility/FhirVersionsTest.java index eec0d4871..c78e18782 100644 --- a/common/src/test/java/org/opencds/cqf/ruler/common/utility/FhirVersionsTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/FhirVersionsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/common/src/test/java/org/opencds/cqf/ruler/common/utility/IdsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/IdsTest.java similarity index 96% rename from common/src/test/java/org/opencds/cqf/ruler/common/utility/IdsTest.java rename to core/src/test/java/org/opencds/cqf/ruler/utility/IdsTest.java index ce830a1f3..4e632ea96 100644 --- a/common/src/test/java/org/opencds/cqf/ruler/common/utility/IdsTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/IdsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; diff --git a/common/src/test/java/org/opencds/cqf/ruler/common/utility/ReflectionsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/ReflectionsTest.java similarity index 98% rename from common/src/test/java/org/opencds/cqf/ruler/common/utility/ReflectionsTest.java rename to core/src/test/java/org/opencds/cqf/ruler/utility/ReflectionsTest.java index 15bc94553..6289345b6 100644 --- a/common/src/test/java/org/opencds/cqf/ruler/common/utility/ReflectionsTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/ReflectionsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; diff --git a/common/src/test/java/org/opencds/cqf/ruler/common/utility/VersionsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/VersionsTest.java similarity index 97% rename from common/src/test/java/org/opencds/cqf/ruler/common/utility/VersionsTest.java rename to core/src/test/java/org/opencds/cqf/ruler/utility/VersionsTest.java index b018d92e4..dd6547721 100644 --- a/common/src/test/java/org/opencds/cqf/ruler/common/utility/VersionsTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/VersionsTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.common.utility; +package org.opencds.cqf.ruler.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; diff --git a/docs/diagrams/modules.drawio.svg b/docs/diagrams/modules.drawio.svg new file mode 100644 index 000000000..13e8493c2 --- /dev/null +++ b/docs/diagrams/modules.drawio.svg @@ -0,0 +1,224 @@ + + + + + + + +
+
+
+ + cqf-ruler-externa + + l +
+ (hapi-fhir-jpaserver-starter) +
+
+
+
+ + cqf-ruler-external... + +
+
+ + + + +
+
+
+ + cqf-ruler-core + +
+ apis, utilities, base server +
+
+
+
+ + cqf-ruler-core... + +
+
+ + + + + + +
+
+
+ + cqf-ruler-server + +
+ webapp war with UIs, plugins, default configuration, etc. +
+
+
+
+ + cqf-ruler-server... + +
+
+ + + + +
+
+
+ + cqf-ruler-test + +
+ utitilies and framework for testing plugins +
+
+
+
+ + cqf-ruler-test... + +
+
+ + + + +
+
+
+ + plugins + +
+ IG specific implmentation +
+
+
+
+ + plugins... + +
+
+ + + + +
+
+
+ + cqf-ruler-cpg +
+
+ Clinical Practice Guidelines +
+
+
+
+ + cqf-ruler-cpg... + +
+
+ + + + +
+
+
+ + cqf-ruler-cr +
+
+ FHIR Clinical Reasoning Module +
+
+
+
+ + cqf-ruler-cr... + +
+
+ + + + +
+
+
+ + additional plugins + +
+
+
+
+ + additional plugins + +
+
+ + + + + +
+
+
+ Runtime only dependencies +
+
+
+
+ + Runtime only dependencies + +
+
+ + + + + +
+
+
+ Test only dependency +
+
+
+
+ + Test only dependency + +
+
+ + + + + + +
+ + + + + Viewer does not support full SVG 1.1 + + + +
diff --git a/plugin/case-reporting/pom.xml b/plugin/case-reporting/pom.xml index 3194f848a..344031f28 100644 --- a/plugin/case-reporting/pom.xml +++ b/plugin/case-reporting/pom.xml @@ -14,10 +14,6 @@ cqf-ruler-cql 0.5.0-SNAPSHOT
- - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - +
diff --git a/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java b/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java index 21bb31579..6d925c949 100644 --- a/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java +++ b/plugin/case-reporting/src/main/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProvider.java @@ -14,8 +14,8 @@ import org.hl7.fhir.r4.model.ListResource; import org.hl7.fhir.r4.model.MeasureReport; import org.hl7.fhir.r4.model.Reference; -import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; -import org.opencds.cqf.ruler.common.utility.Searches; +import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; +import org.opencds.cqf.ruler.utility.Searches; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java b/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java index ee99fb440..cdcd5d817 100644 --- a/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java +++ b/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java @@ -7,59 +7,19 @@ import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.MeasureReport; import org.hl7.fhir.r4.model.Parameters; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.casereporting.CaseReportingConfig; -import org.opencds.cqf.ruler.test.ResourceLoader; -import org.springframework.beans.factory.annotation.Autowired; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; -@ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CaseReportingConfig.class }, properties = { "hapi.fhir.fhir_version=r4", "spring.main.allow-bean-definition-overriding=true", "debug=true", "spring.batch.job.enabled=false" }) -public class MeasureDataProcessProviderIT implements ResourceLoader { - private IGenericClient ourClient; - - @Autowired - private FhirContext ourCtx; - - @Autowired - DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - - @Override - public FhirContext getFhirContext() { - return ourCtx; - } - - @Override - public DaoRegistry getDaoRegistry() { - return myDaoRegistry; - } - - @BeforeEach - void beforeEach() { - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + port + "/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); - - } - +public class MeasureDataProcessProviderIT extends RestIntegrationTest { @Test public void testMeasureReportExtractLineListData() throws IOException { @@ -72,7 +32,7 @@ public void testMeasureReportExtractLineListData() throws IOException { loadResource(packagePrefix + "Group-ra-group02.json"); loadResource(packagePrefix + "MeasureReport-ra-measurereport01.json"); - MeasureReport measureReport = ourClient.read().resource(MeasureReport.class).withId("ra-measurereport01") + MeasureReport measureReport = getClient().read().resource(MeasureReport.class).withId("ra-measurereport01") .execute(); assertNotNull(measureReport); @@ -81,7 +41,7 @@ public void testMeasureReportExtractLineListData() throws IOException { params.addParameter().setName("measureReport").setResource(measureReport); params.addParameter().setName("subjectList").setValue(null); - Bundle returnBundle = ourClient.operation().onType(MeasureReport.class) + Bundle returnBundle = getClient().operation().onType(MeasureReport.class) .named("$extract-line-list-data") .withParameters(params) .returnResourceType(Bundle.class) @@ -89,5 +49,4 @@ public void testMeasureReportExtractLineListData() throws IOException { assertNotNull(returnBundle); } - } diff --git a/plugin/cds-hooks/pom.xml b/plugin/cds-hooks/pom.xml index e540e0f7c..b6812db01 100644 --- a/plugin/cds-hooks/pom.xml +++ b/plugin/cds-hooks/pom.xml @@ -24,10 +24,6 @@ cqf-ruler-security 0.5.0-SNAPSHOT - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - +
diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java index 5af605505..106a0dc1b 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java @@ -11,7 +11,7 @@ import org.hl7.fhir.r4.model.Library; import org.hl7.fhir.r4.model.PlanDefinition; import org.hl7.fhir.r4.model.ValueSet; -import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.utility.ResolutionUtilities; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java index 3fbc25c37..1ef1c41a3 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java @@ -10,7 +10,7 @@ import org.hl7.fhir.dstu3.model.PlanDefinition; import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.utility.ResolutionUtilities; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java index 3202ef370..8981f42a6 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java @@ -44,7 +44,6 @@ import org.opencds.cqf.ruler.cdshooks.request.JsonHelper; import org.opencds.cqf.ruler.cdshooks.request.Request; import org.opencds.cqf.ruler.cdshooks.response.CdsCard; -import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cql.JpaDataProviderFactory; import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; @@ -52,6 +51,7 @@ import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; import org.opencds.cqf.ruler.cr.dstu3.provider.PlanDefinitionApplyProvider; import org.opencds.cqf.ruler.external.AppProperties; +import org.opencds.cqf.ruler.utility.ResolutionUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java index d3c2750da..385c30467 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java @@ -44,7 +44,6 @@ import org.opencds.cqf.ruler.cdshooks.request.JsonHelper; import org.opencds.cqf.ruler.cdshooks.request.Request; import org.opencds.cqf.ruler.cdshooks.response.CdsCard; -import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cql.JpaDataProviderFactory; import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; @@ -52,6 +51,7 @@ import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; import org.opencds.cqf.ruler.cr.r4.provider.PlanDefinitionApplyProvider; import org.opencds.cqf.ruler.external.AppProperties; +import org.opencds.cqf.ruler.utility.ResolutionUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/plugin/cpg/pom.xml b/plugin/cpg/pom.xml index 8a641d01a..daac918b2 100644 --- a/plugin/cpg/pom.xml +++ b/plugin/cpg/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -14,10 +15,13 @@ cqf-ruler-cql 0.5.0-SNAPSHOT + org.opencds.cqf.ruler - cqf-ruler-common + cqf-ruler-test 0.5.0-SNAPSHOT + test + diff --git a/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java b/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java index fb120a09e..32cbfcf6f 100644 --- a/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java +++ b/plugin/cpg/src/main/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProvider.java @@ -35,9 +35,6 @@ import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; import org.opencds.cqf.cql.evaluator.engine.retrieve.BundleRetrieveProvider; import org.opencds.cqf.cql.evaluator.engine.retrieve.PriorityRetrieveProvider; -import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; -import org.opencds.cqf.ruler.common.utility.Clients; -import org.opencds.cqf.ruler.common.utility.Operations; import org.opencds.cqf.ruler.cpg.r4.util.FhirMeasureBundler; import org.opencds.cqf.ruler.cpg.r4.util.R4ApelonFhirTerminologyProvider; import org.opencds.cqf.ruler.cpg.r4.util.R4BundleLibraryContentProvider; @@ -46,6 +43,9 @@ import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; import org.opencds.cqf.ruler.cql.JpaTerminologyProviderFactory; import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; +import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; +import org.opencds.cqf.ruler.utility.Clients; +import org.opencds.cqf.ruler.utility.Operations; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; diff --git a/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java b/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java index 67c881aef..be1f89ac7 100644 --- a/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java +++ b/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java @@ -10,59 +10,21 @@ import org.hl7.fhir.r4.model.Library; import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.StringType; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cpg.CpgConfig; -import org.opencds.cqf.ruler.test.ResourceLoader; -import org.springframework.beans.factory.annotation.Autowired; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -@ExtendWith(SpringExtension.class) @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, - CpgConfig.class }, properties = { "hapi.fhir.fhir_version=r4", - "spring.main.allow-bean-definition-overriding=true", - "debug=true", - "spring.batch.job.enabled=false"}) -public class LibraryEvaluationProviderIT implements ResourceLoader { - private IGenericClient ourClient; - - @Autowired - private FhirContext ourCtx; - - @Autowired - DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - - @Override - public FhirContext getFhirContext() { - return ourCtx; - } - - @Override - public DaoRegistry getDaoRegistry() { - return myDaoRegistry; - } - - @BeforeEach - void beforeEach() { - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + port + "/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); - } - + CpgConfig.class }, properties = { "hapi.fhir.fhir_version=r4", + "spring.main.allow-bean-definition-overriding=true", + "debug=true", + "spring.batch.job.enabled=false" }) +public class LibraryEvaluationProviderIT extends RestIntegrationTest { @Test public void testLibraryEvaluationValidationThrows() throws IOException { @@ -74,15 +36,15 @@ public void testLibraryEvaluationValidationThrows() throws IOException { String packagePrefix = "org/opencds/cqf/ruler/cpg/r4/provider/"; loadResource(packagePrefix + "ColorectalCancerScreeningsFHIR.json"); - Library lib = ourClient.read().resource(Library.class).withId("ColorectalCancerScreeningsFHIR").execute(); + Library lib = getClient().read().resource(Library.class).withId("ColorectalCancerScreeningsFHIR").execute(); assertNotNull(lib); assertThrows(InternalErrorException.class, () -> { - ourClient.operation().onInstance(new IdType("Library", "ColorectalCancerScreeningsFHIR")) - .named("$evaluate") - .withParameters(params) - .returnResourceType(Bundle.class) - .execute(); + getClient().operation().onInstance(new IdType("Library", "ColorectalCancerScreeningsFHIR")) + .named("$evaluate") + .withParameters(params) + .returnResourceType(Bundle.class) + .execute(); }); } @@ -92,14 +54,15 @@ public void testLibraryEvaluationValidData() throws IOException { String packagePrefix = "org/opencds/cqf/ruler/cpg/r4/provider/"; loadResource(packagePrefix + "ColorectalCancerScreeningsFHIR.json"); - String bundleTextValueSets = stringFromResource(packagePrefix + "valuesets-ColorectalCancerScreeningsFHIR-bundle.json"); + String bundleTextValueSets = stringFromResource( + packagePrefix + "valuesets-ColorectalCancerScreeningsFHIR-bundle.json"); FhirContext fhirContext = FhirContext.forR4(); - Bundle bundleValueSet = (Bundle)fhirContext.newJsonParser().parseResource(bundleTextValueSets); - ourClient.transaction().withBundle(bundleValueSet).execute(); + Bundle bundleValueSet = (Bundle) fhirContext.newJsonParser().parseResource(bundleTextValueSets); + getClient().transaction().withBundle(bundleValueSet).execute(); String bundleText = stringFromResource(packagePrefix + "additionalData.json"); - Bundle bundle = (Bundle)fhirContext.newJsonParser().parseResource(bundleText); - Library lib = ourClient.read().resource(Library.class).withId("ColorectalCancerScreeningsFHIR").execute(); + Bundle bundle = (Bundle) fhirContext.newJsonParser().parseResource(bundleText); + Library lib = getClient().read().resource(Library.class).withId("ColorectalCancerScreeningsFHIR").execute(); assertNotNull(bundle); assertNotNull(lib); @@ -111,12 +74,11 @@ public void testLibraryEvaluationValidData() throws IOException { params.addParameter().setName("context").setValue(new StringType("Patient")); params.addParameter().setName("additionalData").setResource(bundle); - - Bundle returnBundle = ourClient.operation().onInstance(new IdType("Library", "ColorectalCancerScreeningsFHIR")) - .named("$evaluate") - .withParameters(params) - .returnResourceType(Bundle.class) - .execute(); + Bundle returnBundle = getClient().operation().onInstance(new IdType("Library", "ColorectalCancerScreeningsFHIR")) + .named("$evaluate") + .withParameters(params) + .returnResourceType(Bundle.class) + .execute(); assertNotNull(returnBundle); } diff --git a/plugin/cql/pom.xml b/plugin/cql/pom.xml index b3094a25f..9288f8b29 100644 --- a/plugin/cql/pom.xml +++ b/plugin/cql/pom.xml @@ -13,10 +13,6 @@ javax.servlet javax.servlet-api - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - + diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java index 3dfa0c793..a66d1bea5 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/ElmCacheResourceChangeListener.java @@ -9,7 +9,7 @@ import org.cqframework.cql.elm.execution.VersionedIdentifier; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; -import org.opencds.cqf.ruler.common.utility.Reflections; +import org.opencds.cqf.ruler.utility.Reflections; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.jpa.cache.IResourceChangeEvent; diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java index 48fb26a14..65cd30cc2 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java @@ -8,7 +8,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentType; -import org.opencds.cqf.ruler.common.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.utility.ResolutionUtilities; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.rest.api.server.RequestDetails; diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java index 11ed530ea..fc86a5475 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java @@ -8,7 +8,7 @@ import org.opencds.cqf.cql.engine.terminology.CodeSystemInfo; import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.engine.terminology.ValueSetInfo; -import org.opencds.cqf.ruler.common.utility.Ids; +import org.opencds.cqf.ruler.utility.Ids; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java index dbe56e63b..482d84984 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java @@ -6,7 +6,7 @@ import org.hl7.fhir.instance.model.api.IBase; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.common.utility.Reflections; +import org.opencds.cqf.ruler.utility.Reflections; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/cr/pom.xml b/plugin/cr/pom.xml index 6be2a48dc..70e97e23a 100644 --- a/plugin/cr/pom.xml +++ b/plugin/cr/pom.xml @@ -23,11 +23,7 @@ cqf-ruler-cql 0.5.0-SNAPSHOT - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - + org.opencds.cqf.ruler cqf-ruler-dev-tools diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java index e97a3f55d..e7fb58195 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java @@ -22,7 +22,6 @@ import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.InMemoryLibraryContentProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; -import org.opencds.cqf.ruler.common.utility.Canonicals; import org.opencds.cqf.ruler.cql.CqlProperties; import org.opencds.cqf.ruler.cql.JpaDataProviderFactory; import org.opencds.cqf.ruler.cql.JpaFhirDal; @@ -30,6 +29,7 @@ import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; import org.opencds.cqf.ruler.cql.JpaTerminologyProviderFactory; import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; +import org.opencds.cqf.ruler.utility.Canonicals; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java index 26db576de..7995166c4 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProvider.java @@ -8,7 +8,7 @@ import org.hl7.fhir.r4.model.Measure; import org.hl7.fhir.r4.model.MeasureReport; import org.hl7.fhir.r4.model.Resource; -import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; +import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.rest.annotation.IdParam; diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java index 5f015e9d8..184215831 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java @@ -8,7 +8,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; @@ -17,11 +16,10 @@ import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java index 4530f93ea..30b987b7e 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java @@ -10,7 +10,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; @@ -18,11 +17,10 @@ import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java index 4ad48edb7..4f494a458 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java @@ -9,7 +9,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; @@ -18,11 +17,10 @@ import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java index 1b01fe4f7..875ec5260 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java @@ -8,7 +8,6 @@ import org.hl7.fhir.r4.model.DomainResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; @@ -17,11 +16,10 @@ import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java index b87604a9b..ae97022d6 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java @@ -11,7 +11,6 @@ import org.hl7.fhir.r4.model.ServiceRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; @@ -19,11 +18,10 @@ import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java index f5f88ddf7..d99267f88 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; @@ -11,9 +10,8 @@ import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java index 4635e8f2f..d7a252d2e 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java @@ -9,7 +9,6 @@ import org.hl7.fhir.r4.model.DomainResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; @@ -18,11 +17,10 @@ import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java index 0580fc039..7472dfffb 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java @@ -7,20 +7,18 @@ import org.hl7.fhir.r4.model.MeasureReport; import org.hl7.fhir.r4.model.Observation; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.opencds.cqf.ruler.common.utility.IdCreator; -import org.opencds.cqf.ruler.common.utility.ResourceCreator; import org.opencds.cqf.ruler.test.DaoIntegrationTest; import org.opencds.cqf.ruler.test.DaoOnlyConfig; +import org.opencds.cqf.ruler.utility.IdCreator; +import org.opencds.cqf.ruler.utility.ResourceCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@ExtendWith(SpringExtension.class) + @SpringBootTest(classes = { DaoOnlyConfig.class }, properties = { "scheduling_disabled=true", "spring.main.allow-bean-definition-overriding=true", diff --git a/plugin/dev-tools/pom.xml b/plugin/dev-tools/pom.xml index 009f32345..3996666ec 100644 --- a/plugin/dev-tools/pom.xml +++ b/plugin/dev-tools/pom.xml @@ -9,10 +9,6 @@ cqf-ruler-dev-tools - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - +
diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java index 01d1910b7..2a917a567 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProvider.java @@ -14,7 +14,7 @@ import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.ValueSet; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Clients; +import org.opencds.cqf.ruler.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java index 78c8c483c..b55494998 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemUpdateProvider.java @@ -19,7 +19,7 @@ import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.instance.model.api.IIdType; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Ids; +import org.opencds.cqf.ruler.utility.Ids; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java index 3c6f7a004..177dcb44a 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProvider.java @@ -14,7 +14,7 @@ import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.ValueSet; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Clients; +import org.opencds.cqf.ruler.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java index fb88f9153..3663a3fbd 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemUpdateProvider.java @@ -19,7 +19,7 @@ import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.ValueSet; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Ids; +import org.opencds.cqf.ruler.utility.Ids; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDaoCodeSystem; diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java index db2acf118..988707c2d 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java @@ -18,20 +18,18 @@ import org.hl7.fhir.dstu3.model.Resource; import org.hl7.fhir.dstu3.model.ValueSet; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.StringAndListParam; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=dstu3", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) public class CacheValueSetsProviderIT extends RestIntegrationTest { diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java index e5b11b454..942cfc62e 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java @@ -21,20 +21,18 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; -import org.opencds.cqf.ruler.common.utility.Searches; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; +import org.opencds.cqf.ruler.utility.Searches; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.rest.api.server.IBundleProvider; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, DevToolsConfig.class }, properties = { "hapi.fhir.fhir_version=dstu3", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true" }) diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java index cfb678bb2..fb37781c9 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java @@ -18,20 +18,18 @@ import org.hl7.fhir.r4.model.Resource; import org.hl7.fhir.r4.model.ValueSet; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mockito; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.rest.api.QualifiedParamList; import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.StringAndListParam; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) public class CacheValueSetsProviderIT extends RestIntegrationTest { diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java index b66ec4237..20ac4eaa5 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java @@ -21,20 +21,18 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; -import org.opencds.cqf.ruler.common.utility.Searches; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; +import org.opencds.cqf.ruler.utility.Searches; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.rest.api.server.IBundleProvider; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) diff --git a/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java b/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java index aff23080c..d32215f47 100644 --- a/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java +++ b/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java @@ -7,17 +7,15 @@ import org.hl7.fhir.r4.model.Parameters; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, HelloWorldConfig.class }, properties = { // Override is currently required when using MDM as the construction of the MDM diff --git a/plugin/pom.xml b/plugin/pom.xml index f233fbeaa..ab7c6d01b 100644 --- a/plugin/pom.xml +++ b/plugin/pom.xml @@ -18,11 +18,12 @@ cql cr dev-tools - - hello-world ra sdc security + + + hello-world @@ -35,11 +36,7 @@ cqf-ruler-external 0.5.0-SNAPSHOT - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - + org.springframework.boot spring-boot-autoconfigure diff --git a/plugin/ra/pom.xml b/plugin/ra/pom.xml index fcb30ca1f..e89b6fafb 100644 --- a/plugin/ra/pom.xml +++ b/plugin/ra/pom.xml @@ -9,10 +9,6 @@ cqf-ruler-ra - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - +
diff --git a/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java b/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java index d1f7ea4b1..3a74991be 100644 --- a/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java +++ b/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java @@ -22,10 +22,10 @@ import org.hl7.fhir.r4.model.Period; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; -import org.opencds.cqf.ruler.common.provider.DaoRegistryOperationProvider; -import org.opencds.cqf.ruler.common.utility.IdCreator; -import org.opencds.cqf.ruler.common.utility.Operations; -import org.opencds.cqf.ruler.common.utility.Searches; +import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; +import org.opencds.cqf.ruler.utility.IdCreator; +import org.opencds.cqf.ruler.utility.Operations; +import org.opencds.cqf.ruler.utility.Searches; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java b/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java index 8804f770e..61a3c69bc 100644 --- a/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java +++ b/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java @@ -14,63 +14,29 @@ import org.hl7.fhir.r4.model.StringType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; -import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.ra.RAConfig; import org.opencds.cqf.ruler.ra.RAProperties; -import org.opencds.cqf.ruler.test.ResourceLoader; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.opencds.cqf.ruler.test.Urls; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; -@ExtendWith(SpringExtension.class) + @ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, RAConfig.class }, properties = { "hapi.fhir.fhir_version=r4" }) -public class ReportProviderIT implements ResourceLoader { - - private IGenericClient ourClient; - - @Autowired - private FhirContext ourCtx; - - @Autowired - DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - - @Override - public FhirContext getFhirContext() { - return ourCtx; - } - - @Override - public DaoRegistry getDaoRegistry() { - return myDaoRegistry; - } - +public class ReportProviderIT extends RestIntegrationTest { @Autowired private RAProperties myRaProperties; - @BeforeEach void beforeEach() { - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = Urls.getUrl(myRaProperties.getReport().getEndpoint(), port); - ourClient = Clients.forUrl(ourCtx, ourServerBase); + String ourServerBase = Urls.getUrl(myRaProperties.getReport().getEndpoint(), getPort()); myRaProperties.getReport().setEndpoint(ourServerBase); } @@ -82,7 +48,7 @@ public void testMissingPeriodStartParam() throws IOException { params.addParameter().setName("subject").setValue(new StringType("Patient/testReport01")); assertThrows(InternalErrorException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -97,7 +63,7 @@ public void testMissingPeriodEndParam() throws IOException { params.addParameter().setName("subject").setValue(new StringType("Patient/testReport01")); assertThrows(InternalErrorException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -112,7 +78,7 @@ public void testMissingSubjectParam() throws IOException { params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); assertThrows(InternalErrorException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -127,7 +93,7 @@ public void testStartPeriodBeforeEndPeriod() throws IOException { params.addParameter().setName("periodEnd").setValue(new StringType("2020-12-31")); assertThrows(InternalErrorException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -145,7 +111,7 @@ public void testSubjectPatient() throws IOException { loadResource("Patient-ra-patient01.json"); assertDoesNotThrow(() -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -164,7 +130,7 @@ public void testSubjectGroup() throws IOException { loadResource("Group-ra-group01.json"); assertDoesNotThrow(() -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -180,7 +146,7 @@ public void testSubjectIsNotPatientOrGroup() throws IOException { params.addParameter().setName("subject").setValue(new StringType("ra-patient01")); assertThrows(InternalErrorException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -196,7 +162,7 @@ public void testPatientSubjectNotFound() throws IOException { params.addParameter().setName("subject").setValue(new StringType("Patient/bad-patient")); assertThrows(ResourceNotFoundException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -212,7 +178,7 @@ public void testGroupSubjectNotFound() throws IOException { params.addParameter().setName("subject").setValue(new StringType("Group/bad-group")); assertThrows(ResourceNotFoundException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -229,11 +195,11 @@ public void testSubjectPatientNotFoundInGroup() throws IOException { params.addParameter().setName("periodEnd").setValue(new StringType("2021-12-31")); params.addParameter().setName("subject").setValue(new StringType("Group/ra-group00")); loadResource("Group-ra-group00.json"); - Group group = ourClient.read().resource(Group.class).withId("ra-group00").execute(); + Group group = getClient().read().resource(Group.class).withId("ra-group00").execute(); assertNotNull(group); assertThrows(ResourceNotFoundException.class, () -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -253,7 +219,7 @@ public void testSubjectMultiplePatientGroup() throws IOException { loadResource("Group-ra-group02.json"); assertDoesNotThrow(() -> { - ourClient.operation().onType(MeasureReport.class).named("$report") + getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -288,7 +254,7 @@ public void testSingleSubjectSingleReport() throws IOException { loadResource("Encounter-ra-encounter43pat01.json"); loadResource("Encounter-ra-encounter44pat01.json"); loadResource("MeasureReport-ra-measurereport01.json"); - Parameters actual = ourClient.operation().onType(MeasureReport.class).named("$report") + Parameters actual = getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); @@ -333,7 +299,7 @@ public void testReportDoesNotIncludeNonEvaluatedResources() throws IOException { // this is not an evaluatedResource of the report loadResource("Encounter-ra-encounter45pat01.json"); - Parameters actual = ourClient.operation().onType(MeasureReport.class).named("$report") + Parameters actual = getClient().operation().onType(MeasureReport.class).named("$report") .withParameters(params) .returnResourceType(Parameters.class) .execute(); diff --git a/plugin/sdc/pom.xml b/plugin/sdc/pom.xml index 2a2178d8d..00636fe11 100644 --- a/plugin/sdc/pom.xml +++ b/plugin/sdc/pom.xml @@ -9,10 +9,6 @@ cqf-ruler-sdc - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - + diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java index f96d74463..0c3b122af 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/ExtractProvider.java @@ -18,8 +18,8 @@ import org.hl7.fhir.dstu3.model.Reference; import org.hl7.fhir.dstu3.model.StringType; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; +import org.opencds.cqf.ruler.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java index 80accdcae..ad98d1fd0 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/dstu3/TransformProvider.java @@ -9,8 +9,8 @@ import org.hl7.fhir.dstu3.model.ConceptMap; import org.hl7.fhir.dstu3.model.Observation; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; +import org.opencds.cqf.ruler.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java index f60f9ac26..839c6d67d 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/ExtractProvider.java @@ -18,8 +18,8 @@ import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.StringType; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; +import org.opencds.cqf.ruler.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java index 0249bb73f..fa2eaea36 100644 --- a/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java +++ b/plugin/sdc/src/main/java/org/opencds/cqf/ruler/sdc/r4/TransformProvider.java @@ -9,8 +9,8 @@ import org.hl7.fhir.r4.model.ConceptMap; import org.hl7.fhir.r4.model.Observation; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.common.utility.Clients; import org.opencds.cqf.ruler.sdc.SDCProperties; +import org.opencds.cqf.ruler.utility.Clients; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java b/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java index 5bfac8c2c..1b3c4771e 100644 --- a/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java +++ b/plugin/sdc/src/test/java/org/opencds/cqf/ruler/sdc/r4/ExtractProviderIT.java @@ -12,59 +12,27 @@ import org.hl7.fhir.r4.model.QuestionnaireResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.sdc.SDCConfig; import org.opencds.cqf.ruler.sdc.SDCProperties; -import org.opencds.cqf.ruler.test.ResourceLoader; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; import org.springframework.test.context.ActiveProfiles; -import org.springframework.test.context.junit.jupiter.SpringExtension; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -@ExtendWith(SpringExtension.class) + @ActiveProfiles("test") @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, SDCConfig.class }, properties = { "hapi.fhir.fhir_version=r4" }) -public class ExtractProviderIT implements ResourceLoader { - private IGenericClient ourClient; - - @Autowired - private FhirContext ourCtx; - - @Autowired - DaoRegistry myDaoRegistry; - - @LocalServerPort - private int port; - - @Override - public FhirContext getFhirContext() { - return ourCtx; - } - - @Override - public DaoRegistry getDaoRegistry() { - return myDaoRegistry; - } - +public class ExtractProviderIT extends RestIntegrationTest { @Autowired private SDCProperties mySdcProperties; @BeforeEach void beforeEach() { - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + port + "/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); - + String ourServerBase = "http://localhost:" + getPort() + "/fhir/"; mySdcProperties.getExtract().setEndpoint(ourServerBase); } @@ -81,7 +49,7 @@ public void testExtract() throws IOException, URISyntaxException { Parameters params = new Parameters(); params.addParameter().setName("questionnaireResponse").setResource(questionnaireResponse); - Bundle actual = ourClient + Bundle actual = getClient() .operation() .onType(QuestionnaireResponse.class) .named("$extract") @@ -102,14 +70,14 @@ public void testExtract() throws IOException, URISyntaxException { @Test public void testExtract_noQuestionnaireReference_throwsException() throws IOException { - QuestionnaireResponse test = (QuestionnaireResponse) ourCtx.newJsonParser() + QuestionnaireResponse test = (QuestionnaireResponse) getFhirContext().newJsonParser() .parseResource(stringFromResource("mypain-questionnaire-response-no-url.json")); Parameters params = new Parameters(); params.addParameter().setName("questionnaireResponse").setResource(test); assertThrows(InternalErrorException.class, () -> { - ourClient.operation().onType(QuestionnaireResponse.class).named("$extract") + getClient().operation().onType(QuestionnaireResponse.class).named("$extract") .withParameters(params) .returnResourceType(Bundle.class) .execute(); diff --git a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java index 1f33a3fb1..62d35ad88 100644 --- a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java +++ b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java @@ -6,19 +6,17 @@ import org.hl7.fhir.dstu3.model.CapabilityStatement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.security.SecurityConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, SecurityConfig.class }, properties = { // Override is currently required when using MDM as the construction of the MDM diff --git a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java index b37a2795f..f6ebdcf5e 100644 --- a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java +++ b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java @@ -6,19 +6,17 @@ import org.hl7.fhir.r4.model.CapabilityStatement; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.security.SecurityConfig; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.web.server.LocalServerPort; -import org.springframework.test.context.junit.jupiter.SpringExtension; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; -@ExtendWith(SpringExtension.class) + @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, SecurityConfig.class }, properties = { // Override is currently required when using MDM as the construction of the MDM diff --git a/pom.xml b/pom.xml index 992d54544..82f8f8c3d 100644 --- a/pom.xml +++ b/pom.xml @@ -35,7 +35,6 @@ external test core - common plugin server diff --git a/server/pom.xml b/server/pom.xml index 772f57446..16a15e065 100644 --- a/server/pom.xml +++ b/server/pom.xml @@ -296,12 +296,6 @@ 0.5.0-SNAPSHOT runtime - - org.opencds.cqf.ruler - cqf-ruler-common - 0.5.0-SNAPSHOT - runtime - diff --git a/test/pom.xml b/test/pom.xml index 6fc16fb35..1b9b3ae41 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -16,9 +16,9 @@ 0.5.0-SNAPSHOT - + org.opencds.cqf.ruler - cqf-ruler-common + cqf-ruler-core 0.5.0-SNAPSHOT diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java b/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java index 26117f8c7..d9cc92ddb 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java @@ -17,8 +17,8 @@ import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.common.utility.DaoRegistryUser; -import org.opencds.cqf.ruler.common.utility.FhirContextUser; +import org.opencds.cqf.ruler.utility.DaoRegistryUser; +import org.opencds.cqf.ruler.utility.FhirContextUser; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; From b361de0af110f65cb05c811207a9c7cd10c2ac1e Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 24 Jan 2022 08:27:17 -0700 Subject: [PATCH 04/12] Update Readme to not say User since that's overloaded --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index c7353928d..24eee36ca 100644 --- a/README.md +++ b/README.md @@ -145,10 +145,10 @@ Examples ### Behavior Specific Utilities -If there is behavior you'd like to share across many classes, model that as an interface and use a name that follows the pattern `"ThingDoer"`. For example, all the classes that access a database might be `DatabaseUser`. Use `default` interface implementations to write logic that can be shared many places. The interfaces themselves shouldn't have mutable state (again `static final` is ok). If it's necessary for the for shared logic to have access to state, model that as an method without a default implementation. For example: +If there is behavior you'd like to share across many classes, model that as an interface and use a name that follows the pattern `"ThingDoer"`. For example, all the classes that access a database might be `DatabaseReader`. Use `default` interface implementations to write logic that can be shared many places. The interfaces themselves shouldn't have mutable state (again `static final` is ok). If it's necessary for the for shared logic to have access to state, model that as an method without a default implementation. For example: ```java -interface DatabaseUser { +interface DatabaseReader { Database getDb(); default Entity read(Id id) { return getDb().connect().find(id); From c618ad186592ee2115067d8889144dd1d039809f Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 24 Jan 2022 12:17:59 -0700 Subject: [PATCH 05/12] Test framework updates --- .../org/opencds/cqf/ruler/utility/Ids.java | 8 +- .../cqf/ruler/utility/ResourceCreator.java | 10 +- .../opencds/cqf/ruler/utility/Resources.java | 31 ++ .../r4/MeasureDataProcessProviderIT.java | 8 +- .../provider/LibraryEvaluationProviderIT.java | 8 +- .../cr/dstu3/ExpressionEvaluationIT.java | 8 +- .../ActivityDefinitionApplyProviderIT.java | 10 +- .../PlanDefinitionApplyProviderIT.java | 7 +- .../ruler/cr/r4/ExpressionEvaluationIT.java | 8 +- .../ActivityDefinitionApplyProviderIT.java | 7 +- .../provider/MeasureEvaluateProviderIT.java | 8 +- .../PlanDefinitionApplyProviderIT.java | 7 +- .../cr/r4/provider/SubmitDataProviderIT.java | 27 +- .../ruler/devtools/DevToolsProperties.java | 41 -- .../dstu3/CacheValueSetsProviderIT.java | 352 +++++++++--------- .../devtools/dstu3/CodeSystemProviderIT.java | 6 +- .../devtools/r4/CacheValueSetsProviderIT.java | 6 +- .../devtools/r4/CodeSystemProviderIT.java | 5 +- .../cqf/ruler/hello/HelloWorldProviderIT.java | 40 +- .../cqf/ruler/ra/r4/ReportProviderIT.java | 6 +- .../ruler/security/dstu3/OAuthProviderIT.java | 38 +- .../ruler/security/r4/OAuthProviderIT.java | 48 +-- test/pom.xml | 1 + .../cqf/ruler/test/DaoIntegrationTest.java | 29 +- .../opencds/cqf/ruler/test/DaoOnlyConfig.java | 6 + .../cqf/ruler/test/RestIntegrationTest.java | 30 +- .../opencds/cqf/ruler/test/TestDbService.java | 53 +++ 27 files changed, 384 insertions(+), 424 deletions(-) create mode 100644 core/src/main/java/org/opencds/cqf/ruler/utility/Resources.java create mode 100644 test/src/main/java/org/opencds/cqf/ruler/test/TestDbService.java diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java index 4c3731c28..52caa330c 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java @@ -76,16 +76,16 @@ public static IdType newId(FhirContext theFhirContext, * @param an IIdType type * @param theFhirVersionEnum the FHIR version to generate an Id for * @param theResourceType the type of the Resource to create an Id for - * @param theId the String representation of the Id to generate + * @param theIdPart the String representation of the Id to generate * @return the id */ public static IdType newId(FhirVersionEnum theFhirVersionEnum, String theResourceType, - String theId) { + String theIdPart) { checkNotNull(theFhirVersionEnum); checkNotNull(theResourceType); - checkNotNull(theId); + checkNotNull(theIdPart); - return newId(theFhirVersionEnum, theResourceType + "/" + theId); + return newId(theFhirVersionEnum, theResourceType + "/" + theIdPart); } /** diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java b/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java index 407047767..5c1d39c46 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java @@ -17,13 +17,7 @@ default T newResource(I theId) { return (T) newResource; } - @SuppressWarnings("unchecked") - default T newResource(Class theResourceClass, String theIdPart) { - checkNotNull(theResourceClass, "theResourceClass is required"); - checkNotNull(theIdPart, "theIdPart is required"); - - IBaseResource newResource = this.getFhirContext().getResourceDefinition(theResourceClass).newInstance(); - newResource.setId((I) Ids.newId(theResourceClass, theIdPart)); - return (T) newResource; + default T newResource(Class theResourceClass, String theIdPart) { + return Resources.newResource(theResourceClass, theIdPart); } } diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Resources.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Resources.java new file mode 100644 index 000000000..41d4dde93 --- /dev/null +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Resources.java @@ -0,0 +1,31 @@ +package org.opencds.cqf.ruler.utility; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import org.hl7.fhir.instance.model.api.IBaseResource; +import org.hl7.fhir.instance.model.api.IIdType; + +public class Resources { + + private Resources() { + } + + public static T newResource(Class theResourceClass, String theIdPart) { + checkNotNull(theResourceClass); + checkNotNull(theIdPart); + checkArgument(!theIdPart.contains("/"), "theIdPart must be a simple id. Do not include resourceType or history"); + T resource = null; + try { + resource = (T) theResourceClass.getConstructor().newInstance(); + } catch (Exception e) { + throw new IllegalArgumentException( + "theResourceClass must be a type with an empty default constructor to use this function"); + } + + @SuppressWarnings("unchecked") + I id = (I) Ids.newId(theResourceClass, theIdPart); + resource.setId(id); + return resource; + } +} diff --git a/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java b/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java index cdcd5d817..2c1c67fb4 100644 --- a/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java +++ b/plugin/case-reporting/src/test/java/org/opencds/cqf/ruler/casereporting/r4/MeasureDataProcessProviderIT.java @@ -8,17 +8,13 @@ import org.hl7.fhir.r4.model.MeasureReport; import org.hl7.fhir.r4.model.Parameters; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.casereporting.CaseReportingConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.boot.test.context.SpringBootTest; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, - CaseReportingConfig.class }, properties = { "hapi.fhir.fhir_version=r4", - "spring.main.allow-bean-definition-overriding=true", - "debug=true", - "spring.batch.job.enabled=false" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { MeasureDataProcessProviderIT.class, + CaseReportingConfig.class }, properties = { "hapi.fhir.fhir_version=r4" }) public class MeasureDataProcessProviderIT extends RestIntegrationTest { @Test public void testMeasureReportExtractLineListData() throws IOException { diff --git a/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java b/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java index be1f89ac7..c93ea5750 100644 --- a/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java +++ b/plugin/cpg/src/test/java/org/opencds/cqf/ruler/cpg/r4/provider/LibraryEvaluationProviderIT.java @@ -11,7 +11,6 @@ import org.hl7.fhir.r4.model.Parameters; import org.hl7.fhir.r4.model.StringType; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cpg.CpgConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.boot.test.context.SpringBootTest; @@ -19,11 +18,8 @@ import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, - CpgConfig.class }, properties = { "hapi.fhir.fhir_version=r4", - "spring.main.allow-bean-definition-overriding=true", - "debug=true", - "spring.batch.job.enabled=false" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { LibraryEvaluationProviderIT.class, + CpgConfig.class }, properties = { "hapi.fhir.fhir_version=r4" }) public class LibraryEvaluationProviderIT extends RestIntegrationTest { @Test public void testLibraryEvaluationValidationThrows() throws IOException { diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java index 184215831..aa2e45778 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/ExpressionEvaluationIT.java @@ -8,7 +8,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; @@ -19,14 +18,9 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { ExpressionEvaluationIT.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", "hapi.fhir.fhir_version=dstu3", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false" }) public class ExpressionEvaluationIT extends RestIntegrationTest { diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java index 30b987b7e..fc45d0640 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/ActivityDefinitionApplyProviderIT.java @@ -1,5 +1,6 @@ package org.opencds.cqf.ruler.cr.dstu3.provider; +import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Map; @@ -10,7 +11,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; @@ -21,13 +21,9 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { ActivityDefinitionApplyProviderIT.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", "hapi.fhir.fhir_version=dstu3", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false" }) public class ActivityDefinitionApplyProviderIT extends RestIntegrationTest { @@ -51,6 +47,6 @@ public void testActivityDefinitionApply() throws Exception { activityDefinition.getIdElement(), patient.getIdElement().getIdPart(), null, null, null, null, null, null, null, null); assertTrue(applyResult instanceof ProcedureRequest); - assertTrue(((ProcedureRequest) applyResult).getCode().getCoding().get(0).getCode().equals("454281000124100")); + assertEquals("454281000124100", ((ProcedureRequest) applyResult).getCode().getCoding().get(0).getCode()); } } diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java index 4f494a458..812bbd612 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/dstu3/provider/PlanDefinitionApplyProviderIT.java @@ -9,7 +9,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; @@ -21,13 +20,9 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { PlanDefinitionApplyProviderIT.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", "hapi.fhir.fhir_version=dstu3", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false", }) public class PlanDefinitionApplyProviderIT extends RestIntegrationTest{ diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java index 875ec5260..2eaaac30b 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluationIT.java @@ -8,7 +8,6 @@ import org.hl7.fhir.r4.model.DomainResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; @@ -19,14 +18,9 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { ExpressionEvaluationIT.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", "hapi.fhir.fhir_version=r4", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false" }) public class ExpressionEvaluationIT extends RestIntegrationTest { diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java index ae97022d6..b8bf22b3d 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/ActivityDefinitionApplyProviderIT.java @@ -11,7 +11,6 @@ import org.hl7.fhir.r4.model.ServiceRequest; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; @@ -22,13 +21,9 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { ActivityDefinitionApplyProviderIT.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", "hapi.fhir.fhir_version=r4", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false" }) public class ActivityDefinitionApplyProviderIT extends RestIntegrationTest { diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java index d99267f88..df118cb0e 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProviderIT.java @@ -2,7 +2,6 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; @@ -11,14 +10,9 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { MeasureEvaluateProviderIT.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", "hapi.fhir.fhir_version=r4", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false" }) public class MeasureEvaluateProviderIT extends RestIntegrationTest { diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java index d7a252d2e..fe43c755b 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/PlanDefinitionApplyProviderIT.java @@ -9,7 +9,6 @@ import org.hl7.fhir.r4.model.DomainResource; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.cql.CqlConfig; import org.opencds.cqf.ruler.cr.CrConfig; import org.opencds.cqf.ruler.devtools.DevToolsConfig; @@ -21,13 +20,9 @@ import ca.uhn.fhir.jpa.partition.SystemRequestDetails; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { PlanDefinitionApplyProviderIT.class, CrConfig.class, CqlConfig.class, DevToolsConfig.class }, properties = { - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", "hapi.fhir.fhir_version=r4", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false" }) public class PlanDefinitionApplyProviderIT extends RestIntegrationTest { diff --git a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java index 7472dfffb..4ba5e2ac8 100644 --- a/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java +++ b/plugin/cr/src/test/java/org/opencds/cqf/ruler/cr/r4/provider/SubmitDataProviderIT.java @@ -4,43 +4,30 @@ import com.google.common.collect.Lists; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.MeasureReport; import org.hl7.fhir.r4.model.Observation; import org.junit.jupiter.api.Test; import org.opencds.cqf.ruler.test.DaoIntegrationTest; -import org.opencds.cqf.ruler.test.DaoOnlyConfig; -import org.opencds.cqf.ruler.utility.IdCreator; -import org.opencds.cqf.ruler.utility.ResourceCreator; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; import org.springframework.boot.test.context.SpringBootTest; import ca.uhn.fhir.jpa.partition.SystemRequestDetails; +@SpringBootTest(classes = { SubmitDataProviderIT.class }, properties = { "hapi.fhir.fhir_version=r4", }) +public class SubmitDataProviderIT extends DaoIntegrationTest { -@SpringBootTest(classes = { DaoOnlyConfig.class }, properties = { - "scheduling_disabled=true", - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", - "hapi.fhir.fhir_version=r4", - "hapi.fhir.allow_external_references=true", - "hapi.fhir.enforce_referential_integrity_on_write=false", -}) -@EnableAutoConfiguration(exclude=QuartzAutoConfiguration.class) -public class SubmitDataProviderIT extends DaoIntegrationTest implements IdCreator, ResourceCreator { - @Autowired SubmitDataProvider mySubmitDataProvider; @Test public void testSubmitData() { - // Create a MR and a few resources - MeasureReport mr = newResource(newId("MeasureReport/test-mr")); - Observation obs = newResource(newId("Observation/test-obs")); + // Create a MR and a resource + MeasureReport mr = newResource(MeasureReport.class, "test-mr"); + Observation obs = newResource(Observation.class, "test-obs"); // Submit it - mySubmitDataProvider.submitData(new SystemRequestDetails(), newId("Measure/test-m"), mr, Lists.newArrayList(obs)); + mySubmitDataProvider.submitData(new SystemRequestDetails(), new IdType("Measure", "test-m"), mr, Lists.newArrayList(obs)); // Check if they made it to the db Observation savedObs = read(obs.getIdElement()); diff --git a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/DevToolsProperties.java b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/DevToolsProperties.java index 90f82861e..459a360a3 100644 --- a/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/DevToolsProperties.java +++ b/plugin/dev-tools/src/main/java/org/opencds/cqf/ruler/devtools/DevToolsProperties.java @@ -14,45 +14,4 @@ public Boolean getEnabled() { public void setEnabled(Boolean enabled) { this.enabled = enabled; } - - // private CodeSystemUpdate codeSystemUpdate; - - // public CodeSystemUpdate getCodeSystemUpdate() { - // return codeSystemUpdate; - // } - - // public void setCodeSystemUpdate(CodeSystemUpdate codeSystemUpdate) { - // this.codeSystemUpdate = codeSystemUpdate; - // } - - // public static class CodeSystemUpdate { - - // private String endpoint; - // private String username; - // private String password; - - // public String getEndpoint() { - // return endpoint; - // } - - // public void setEndpoint(String endpoint) { - // this.endpoint = endpoint; - // } - - // public String getUsername() { - // return username; - // } - - // public void setUsername(String username) { - // this.username = username; - // } - - // public String getPassword() { - // return password; - // } - - // public void setPassword(String password) { - // this.password = password; - // } - // } } diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java index 988707c2d..b85125793 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java @@ -19,7 +19,6 @@ import org.hl7.fhir.dstu3.model.ValueSet; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; @@ -29,170 +28,191 @@ import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.StringAndListParam; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, -DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=dstu3", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { CacheValueSetsProviderIT.class, + DevToolsConfig.class },properties = "hapi.fhir.fhir_version=dstu3") public class CacheValueSetsProviderIT extends RestIntegrationTest { - @Autowired - private CacheValueSetsProvider cacheValueSetsProvider; - - @Test - public void testCacheValueSetsEndpointDNE() throws Exception { - Endpoint endpoint = new Endpoint(); - endpoint.setId(new IdType("localhost")); - StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); - RequestDetails details = Mockito.mock(RequestDetails.class); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); - String detailMessage = "Could not find Endpoint/" + endpoint.getIdElement().getIdPart(); - validateOutcome(outcomeResource, detailMessage); - } - - @Test - public void testCacheValueSetsEndpointNull() throws Exception { - StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); - RequestDetails details = Mockito.mock(RequestDetails.class); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, new Endpoint().getIdElement(), stringAndListParam, null, null); - validateOutcome(outcomeResource, "Could not find Endpoint/null"); - } - - @Test - public void testCacheValueSetsAuthenticationErrorUsername() throws Exception { - Endpoint endpoint = uploadLocalServerEndpoint(); - StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); - RequestDetails details = Mockito.mock(RequestDetails.class); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, "username", null); - String detailMessage = "User name was provided, but not a password."; - validateOutcome(outcomeResource, detailMessage); - } - - @Test - public void testCacheValueSetsAuthenticationErrorPassword() throws Exception { - Endpoint endpoint = uploadLocalServerEndpoint(); - StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); - RequestDetails details = Mockito.mock(RequestDetails.class); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, "password"); - String detailMessage = "Password was provided, but not a user name."; - validateOutcome(outcomeResource, detailMessage); - } - - @Test - public void testCacheValueSetsValueSetDNE() throws Exception { - Endpoint endpoint = uploadLocalServerEndpoint(); - StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton("dne"))); - RequestDetails details = Mockito.mock(RequestDetails.class); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); - validateOutcome(outcomeResource, "HTTP 404 : Resource ValueSet/" + "dne" + " is not known"); - } - - @Test - public void testCacheValueSetsValueSetNull() throws Exception { - Endpoint endpoint = uploadLocalServerEndpoint(); - StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton(new ValueSet().getId()))); - RequestDetails details = Mockito.mock(RequestDetails.class); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); - validateOutcome(outcomeResource, "HTTP 404 : Resource ValueSet/" + new ValueSet().getIdElement().getIdPart() + " is not known"); - } - - @Test - public void testCacheValueSetsNoCompose() throws Exception { - Endpoint endpoint = uploadLocalServerEndpoint(); - RequestDetails details = Mockito.mock(RequestDetails.class); - ValueSet vs = uploadValueSet("valueset/valueset-benzodiazepine-medications.json"); - assertTrue(vs.getCompose().getInclude().isEmpty()); - StringAndListParam stringAndListParam = getStringAndListParamFromValueSet(vs); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); - assertTrue(outcomeResource instanceof Bundle); - Bundle resultBundle = (Bundle) outcomeResource; - assertEquals(1, resultBundle.getEntry().size()); - BundleEntryComponent entry = resultBundle.getEntry().get(0); - assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); - assertEquals("200 OK", entry.getResponse().getStatus()); - // ValueSet resultingValueSet = createClient(ourCtx, endpoint).read().resource(ValueSet.class).withId(vs.getIdElement()).execute(); - // resultingValueSet not returning with a version - // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); - } - - // Get help with this.... - // @Test - // public void testCacheValueSetsExpandAndAddConcepts() throws Exception { - // Endpoint endpoint = uploadLocalServerEndpoint(); - // RequestDetails details = Mockito.mock(RequestDetails.class); - // ValueSet vs = uploadValueSet("valueset/valueset-buprenorphine-and-methadone-medications.json"); - // vs.getCompose().getInclude().forEach(include -> { - // assertTrue(!include.hasConcept()); - // }); - // StringAndListParam stringAndListParam = getStringAndListParamFromValueSet(vs); - - // IGenericClient localClient = createClient(ourCtx, endpoint); - // // localClient.operation().onServer().named("updateCodeSystems").withNoParameters(Parameters.class).execute(); - // Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); - // assertTrue(outcomeResource instanceof Bundle); - // Bundle resultBundle = (Bundle) outcomeResource; - // assertTrue(resultBundle.getEntry().size() == 1); - // BundleEntryComponent entry = resultBundle.getEntry().get(0); - // assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); - // assertTrue(entry.getResponse().getStatus().equals("200 OK")); - // ValueSet resultingValueSet = localClient.read().resource(ValueSet.class).withId(vs.getIdElement()).execute(); - // resultingValueSet.getCompose().getInclude().forEach(include -> { - // assertTrue(include.hasConcept()); - // }); - // } - - @Test - public void testCacheValueSetsAlreadyExpanded() throws Exception { - Endpoint endpoint = uploadLocalServerEndpoint(); - RequestDetails details = Mockito.mock(RequestDetails.class); - ValueSet vs = uploadValueSet("valueset/valueset-benzodiazepine-medications.json"); - StringAndListParam stringAndListParam = getStringAndListParamFromValueSet(vs); - Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), stringAndListParam, null, null); - assertTrue(outcomeResource instanceof Bundle); - Bundle resultBundle = (Bundle) outcomeResource; - assertEquals(1, resultBundle.getEntry().size()); - BundleEntryComponent entry = resultBundle.getEntry().get(0); - assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); - assertEquals("200 OK", entry.getResponse().getStatus()); - // ValueSet resultingValueSet = myDaoRegistry.getResourceDao(ValueSet.class).read(vs.getIdElement()); - // resultingValueSet not returning with a version - // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); - } - - private StringAndListParam getStringAndListParamFromValueSet(String location) throws IOException { - ValueSet vs = uploadValueSet(location); - return getStringAndListParamFromValueSet(vs); - } - - private StringAndListParam getStringAndListParamFromValueSet(ValueSet vs) throws IOException { - StringAndListParam stringAndListParam = new StringAndListParam(); - stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", Arrays.asList(QualifiedParamList.singleton(vs.getIdElement().getIdPart()))); - return stringAndListParam; - } - - private void validateOutcome(Resource outcomeResource, String detailMessage) { - assertTrue(outcomeResource instanceof OperationOutcome); - OperationOutcome outcome = (OperationOutcome) outcomeResource; - for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { - assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); - assertTrue(issue.getDetails().getCodingFirstRep().getDisplay().startsWith(detailMessage)); - } - } - - private ValueSet uploadValueSet(String location) throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(CacheValueSetsProvider.class.getResourceAsStream(location))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - return (ValueSet) loadResource("json", resourceString); - } - - private Endpoint uploadLocalServerEndpoint() throws IOException { - BufferedReader reader = new BufferedReader(new InputStreamReader(CacheValueSetsProvider.class.getResourceAsStream("endpoint/LocalServerEndpoint.json"))); - String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); - reader.close(); - // Don't want to update during loading because need to setAddress first - Endpoint endpoint = (Endpoint) loadResource("json", resourceString); - endpoint.setAddress("http://localhost:" + getPort() + "/fhir/"); - create(endpoint); - return endpoint; - } + @Autowired + private CacheValueSetsProvider cacheValueSetsProvider; + + @Test + public void testCacheValueSetsEndpointDNE() throws Exception { + Endpoint endpoint = new Endpoint(); + endpoint.setId(new IdType("localhost")); + StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); + RequestDetails details = Mockito.mock(RequestDetails.class); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), + stringAndListParam, null, null); + String detailMessage = "Could not find Endpoint/" + endpoint.getIdElement().getIdPart(); + validateOutcome(outcomeResource, detailMessage); + } + + @Test + public void testCacheValueSetsEndpointNull() throws Exception { + StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); + RequestDetails details = Mockito.mock(RequestDetails.class); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, new Endpoint().getIdElement(), + stringAndListParam, null, null); + validateOutcome(outcomeResource, "Could not find Endpoint/null"); + } + + @Test + public void testCacheValueSetsAuthenticationErrorUsername() throws Exception { + Endpoint endpoint = uploadLocalServerEndpoint(); + StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); + RequestDetails details = Mockito.mock(RequestDetails.class); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), + stringAndListParam, "username", null); + String detailMessage = "User name was provided, but not a password."; + validateOutcome(outcomeResource, detailMessage); + } + + @Test + public void testCacheValueSetsAuthenticationErrorPassword() throws Exception { + Endpoint endpoint = uploadLocalServerEndpoint(); + StringAndListParam stringAndListParam = getStringAndListParamFromValueSet("valueset/AcuteInpatient.json"); + RequestDetails details = Mockito.mock(RequestDetails.class); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), + stringAndListParam, null, "password"); + String detailMessage = "Password was provided, but not a user name."; + validateOutcome(outcomeResource, detailMessage); + } + + @Test + public void testCacheValueSetsValueSetDNE() throws Exception { + Endpoint endpoint = uploadLocalServerEndpoint(); + StringAndListParam stringAndListParam = new StringAndListParam(); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", + Arrays.asList(QualifiedParamList.singleton("dne"))); + RequestDetails details = Mockito.mock(RequestDetails.class); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), + stringAndListParam, null, null); + validateOutcome(outcomeResource, "HTTP 404 : Resource ValueSet/" + "dne" + " is not known"); + } + + @Test + public void testCacheValueSetsValueSetNull() throws Exception { + Endpoint endpoint = uploadLocalServerEndpoint(); + StringAndListParam stringAndListParam = new StringAndListParam(); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", + Arrays.asList(QualifiedParamList.singleton(new ValueSet().getId()))); + RequestDetails details = Mockito.mock(RequestDetails.class); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), + stringAndListParam, null, null); + validateOutcome(outcomeResource, + "HTTP 404 : Resource ValueSet/" + new ValueSet().getIdElement().getIdPart() + " is not known"); + } + + @Test + public void testCacheValueSetsNoCompose() throws Exception { + Endpoint endpoint = uploadLocalServerEndpoint(); + RequestDetails details = Mockito.mock(RequestDetails.class); + ValueSet vs = uploadValueSet("valueset/valueset-benzodiazepine-medications.json"); + assertTrue(vs.getCompose().getInclude().isEmpty()); + StringAndListParam stringAndListParam = getStringAndListParamFromValueSet(vs); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), + stringAndListParam, null, null); + assertTrue(outcomeResource instanceof Bundle); + Bundle resultBundle = (Bundle) outcomeResource; + assertEquals(1, resultBundle.getEntry().size()); + BundleEntryComponent entry = resultBundle.getEntry().get(0); + assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); + assertEquals("200 OK", entry.getResponse().getStatus()); + // ValueSet resultingValueSet = createClient(ourCtx, + // endpoint).read().resource(ValueSet.class).withId(vs.getIdElement()).execute(); + // resultingValueSet not returning with a version + // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); + } + + // Get help with this.... + // @Test + // public void testCacheValueSetsExpandAndAddConcepts() throws Exception { + // Endpoint endpoint = uploadLocalServerEndpoint(); + // RequestDetails details = Mockito.mock(RequestDetails.class); + // ValueSet vs = + // uploadValueSet("valueset/valueset-buprenorphine-and-methadone-medications.json"); + // vs.getCompose().getInclude().forEach(include -> { + // assertTrue(!include.hasConcept()); + // }); + // StringAndListParam stringAndListParam = + // getStringAndListParamFromValueSet(vs); + + // IGenericClient localClient = createClient(ourCtx, endpoint); + // // + // localClient.operation().onServer().named("updateCodeSystems").withNoParameters(Parameters.class).execute(); + // Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, + // endpoint.getIdElement(), stringAndListParam, null, null); + // assertTrue(outcomeResource instanceof Bundle); + // Bundle resultBundle = (Bundle) outcomeResource; + // assertTrue(resultBundle.getEntry().size() == 1); + // BundleEntryComponent entry = resultBundle.getEntry().get(0); + // assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + + // vs.getIdElement().getIdPart())); + // assertTrue(entry.getResponse().getStatus().equals("200 OK")); + // ValueSet resultingValueSet = + // localClient.read().resource(ValueSet.class).withId(vs.getIdElement()).execute(); + // resultingValueSet.getCompose().getInclude().forEach(include -> { + // assertTrue(include.hasConcept()); + // }); + // } + + @Test + public void testCacheValueSetsAlreadyExpanded() throws Exception { + Endpoint endpoint = uploadLocalServerEndpoint(); + RequestDetails details = Mockito.mock(RequestDetails.class); + ValueSet vs = uploadValueSet("valueset/valueset-benzodiazepine-medications.json"); + StringAndListParam stringAndListParam = getStringAndListParamFromValueSet(vs); + Resource outcomeResource = cacheValueSetsProvider.cacheValuesets(details, endpoint.getIdElement(), + stringAndListParam, null, null); + assertTrue(outcomeResource instanceof Bundle); + Bundle resultBundle = (Bundle) outcomeResource; + assertEquals(1, resultBundle.getEntry().size()); + BundleEntryComponent entry = resultBundle.getEntry().get(0); + assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); + assertEquals("200 OK", entry.getResponse().getStatus()); + // ValueSet resultingValueSet = + // myDaoRegistry.getResourceDao(ValueSet.class).read(vs.getIdElement()); + // resultingValueSet not returning with a version + // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); + } + + private StringAndListParam getStringAndListParamFromValueSet(String location) throws IOException { + ValueSet vs = uploadValueSet(location); + return getStringAndListParamFromValueSet(vs); + } + + private StringAndListParam getStringAndListParamFromValueSet(ValueSet vs) throws IOException { + StringAndListParam stringAndListParam = new StringAndListParam(); + stringAndListParam.setValuesAsQueryTokens(getFhirContext(), "valueset", + Arrays.asList(QualifiedParamList.singleton(vs.getIdElement().getIdPart()))); + return stringAndListParam; + } + + private void validateOutcome(Resource outcomeResource, String detailMessage) { + assertTrue(outcomeResource instanceof OperationOutcome); + OperationOutcome outcome = (OperationOutcome) outcomeResource; + for (OperationOutcomeIssueComponent issue : outcome.getIssue()) { + assertEquals(OperationOutcome.IssueSeverity.ERROR, issue.getSeverity()); + assertTrue(issue.getDetails().getCodingFirstRep().getDisplay().startsWith(detailMessage)); + } + } + + private ValueSet uploadValueSet(String location) throws IOException { + BufferedReader reader = new BufferedReader( + new InputStreamReader(CacheValueSetsProvider.class.getResourceAsStream(location))); + String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); + reader.close(); + return (ValueSet) loadResource("json", resourceString); + } + + private Endpoint uploadLocalServerEndpoint() throws IOException { + BufferedReader reader = new BufferedReader(new InputStreamReader( + CacheValueSetsProvider.class.getResourceAsStream("endpoint/LocalServerEndpoint.json"))); + String resourceString = reader.lines().collect(Collectors.joining(System.lineSeparator())); + reader.close(); + // Don't want to update during loading because need to setAddress first + Endpoint endpoint = (Endpoint) loadResource("json", resourceString); + endpoint.setAddress("http://localhost:" + getPort() + "/fhir/"); + create(endpoint); + return endpoint; + } } diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java index 942cfc62e..e63f3a02b 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CodeSystemProviderIT.java @@ -21,7 +21,6 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.opencds.cqf.ruler.utility.Searches; @@ -33,9 +32,8 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, - DevToolsConfig.class }, properties = { "hapi.fhir.fhir_version=dstu3", "spring.batch.job.enabled=false", - "spring.main.allow-bean-definition-overriding=true" }) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { CodeSystemProviderIT.class, + DevToolsConfig.class }, properties = "hapi.fhir.fhir_version=dstu3") @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class CodeSystemProviderIT extends RestIntegrationTest { private Logger log = LoggerFactory.getLogger(CodeSystemProviderIT.class); diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java index fb37781c9..c76eb179c 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java @@ -19,7 +19,6 @@ import org.hl7.fhir.r4.model.ValueSet; import org.junit.jupiter.api.Test; import org.mockito.Mockito; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.beans.factory.annotation.Autowired; @@ -29,9 +28,8 @@ import ca.uhn.fhir.rest.api.server.RequestDetails; import ca.uhn.fhir.rest.param.StringAndListParam; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, -DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { CacheValueSetsProviderIT.class, +DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4"}) public class CacheValueSetsProviderIT extends RestIntegrationTest { @Autowired private CacheValueSetsProvider cacheValueSetsProvider; diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java index 20ac4eaa5..9cba9d16e 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CodeSystemProviderIT.java @@ -21,7 +21,6 @@ import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.devtools.DevToolsConfig; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.opencds.cqf.ruler.utility.Searches; @@ -33,8 +32,8 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider; -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, -DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4", "spring.batch.job.enabled=false", "spring.main.allow-bean-definition-overriding=true"}) +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { CodeSystemProviderIT.class, +DevToolsConfig.class }, properties ={"hapi.fhir.fhir_version=r4" }) @TestMethodOrder(MethodOrderer.OrderAnnotation.class) public class CodeSystemProviderIT extends RestIntegrationTest { private Logger log = LoggerFactory.getLogger(CodeSystemProviderIT.class); diff --git a/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java b/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java index d32215f47..7e31e2d2a 100644 --- a/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java +++ b/plugin/hello-world/src/test/java/org/opencds/cqf/ruler/hello/HelloWorldProviderIT.java @@ -5,54 +5,24 @@ import org.hl7.fhir.r4.model.OperationOutcome; import org.hl7.fhir.r4.model.Parameters; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; -import org.springframework.beans.factory.annotation.Autowired; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { HelloWorldProviderIT.class, HelloWorldConfig.class }, properties = { - // Override is currently required when using MDM as the construction of the MDM - // beans are ambiguous as they are constructed multiple places. This is evident - // when running in a spring boot environment - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", - "spring.datasource.url=jdbc:h2:mem:dbr4-mt", "hapi.fhir.fhir_version=r4", "hello.world.message=Howdy" }) -public class HelloWorldProviderIT { - private IGenericClient ourClient; - - @Autowired - FhirContext ourCtx; - - @LocalServerPort - private int port; - - @BeforeEach - void beforeEach() { - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + port + "/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); -// ourClient.registerInterceptor(new LoggingInterceptor(false)); - } - +public class HelloWorldProviderIT extends RestIntegrationTest { @Test public void testHelloWorldConfig() { - OperationOutcome outcome = ourClient.operation().onServer().named("$hello-world") + OperationOutcome outcome = getClient().operation().onServer().named("$hello-world") .withNoParameters(Parameters.class).returnResourceType(OperationOutcome.class).execute(); assertNotNull(outcome); - assertEquals(outcome.getIssueFirstRep().getDiagnostics(), "Howdy"); + assertEquals("Howdy", outcome.getIssueFirstRep().getDiagnostics()); } } diff --git a/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java b/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java index 61a3c69bc..ed2eb9bc6 100644 --- a/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java +++ b/plugin/ra/src/test/java/org/opencds/cqf/ruler/ra/r4/ReportProviderIT.java @@ -14,21 +14,17 @@ import org.hl7.fhir.r4.model.StringType; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.ra.RAConfig; import org.opencds.cqf.ruler.ra.RAProperties; import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.opencds.cqf.ruler.test.Urls; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.test.context.ActiveProfiles; import ca.uhn.fhir.rest.server.exceptions.InternalErrorException; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; - -@ActiveProfiles("test") -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { ReportProviderIT.class, RAConfig.class }, properties = { "hapi.fhir.fhir_version=r4" }) public class ReportProviderIT extends RestIntegrationTest { @Autowired diff --git a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java index 62d35ad88..890ad0c5a 100644 --- a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java +++ b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/dstu3/OAuthProviderIT.java @@ -4,50 +4,20 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import org.hl7.fhir.dstu3.model.CapabilityStatement; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.security.SecurityConfig; -import org.springframework.beans.factory.annotation.Autowired; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { OAuthProviderIT.class, SecurityConfig.class }, properties = { - // Override is currently required when using MDM as the construction of the MDM - // beans are ambiguous as they are constructed multiple places. This is evident - // when running in a spring boot environment - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", - "spring.datasource.url=jdbc:h2:mem:dbdstu3-mt", "hapi.fhir.fhir_version=dstu3" }) -public class OAuthProviderIT { - private IGenericClient ourClient; - - @Autowired - private FhirContext ourCtx; - - @LocalServerPort - private int port; - - @BeforeEach - void beforeEach() { - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + port + "/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); -// ourClient.registerInterceptor(new LoggingInterceptor(false)); - } - +public class OAuthProviderIT extends RestIntegrationTest { @Test public void testOAuthConfig() { - CapabilityStatement cs = ourClient.capabilities().ofType(CapabilityStatement.class).execute(); + CapabilityStatement cs = getClient().capabilities().ofType(CapabilityStatement.class).execute(); assertNotNull(cs); assertEquals(true, cs.getRestFirstRep().getSecurity().getCors()); diff --git a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java index f6ebdcf5e..d10d630dc 100644 --- a/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java +++ b/plugin/security/src/test/java/org/opencds/cqf/ruler/security/r4/OAuthProviderIT.java @@ -4,54 +4,24 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import org.hl7.fhir.r4.model.CapabilityStatement; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.Application; import org.opencds.cqf.ruler.security.SecurityConfig; -import org.springframework.beans.factory.annotation.Autowired; +import org.opencds.cqf.ruler.test.RestIntegrationTest; import org.springframework.boot.test.context.SpringBootTest; -import org.springframework.boot.web.server.LocalServerPort; - -import ca.uhn.fhir.context.FhirContext; -import ca.uhn.fhir.rest.client.api.IGenericClient; -import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; - - -@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { Application.class, - SecurityConfig.class }, properties = { - // Override is currently required when using MDM as the construction of the MDM - // beans are ambiguous as they are constructed multiple places. This is evident - // when running in a spring boot environment - "spring.main.allow-bean-definition-overriding=true", - "spring.batch.job.enabled=false", - "spring.datasource.url=jdbc:h2:mem:dbr4-mt", - "hapi.fhir.fhir_version=r4" -}) -public class OAuthProviderIT { - private IGenericClient ourClient; - - @Autowired - private FhirContext ourCtx; - - @LocalServerPort - private int port; - - @BeforeEach - void beforeEach() { - ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER); - ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000); - String ourServerBase = "http://localhost:" + port + "/fhir/"; - ourClient = ourCtx.newRestfulGenericClient(ourServerBase); -// ourClient.registerInterceptor(new LoggingInterceptor(false)); - } +@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = { OAuthProviderIT.class, + SecurityConfig.class }, properties = { + "hapi.fhir.fhir_version=r4" + }) +public class OAuthProviderIT extends RestIntegrationTest { @Test public void testOAuthConfig() { - CapabilityStatement cs = ourClient.capabilities().ofType(CapabilityStatement.class).execute(); + CapabilityStatement cs = getClient().capabilities().ofType(CapabilityStatement.class).execute(); assertNotNull(cs); assertEquals(true, cs.getRestFirstRep().getSecurity().getCors()); - assertEquals("http://hl7.org/fhir/restful-security-service", cs.getRestFirstRep().getSecurity().getService().stream().findAny().get().getCodingFirstRep().getSystem()); + assertEquals("http://hl7.org/fhir/restful-security-service", + cs.getRestFirstRep().getSecurity().getService().stream().findAny().get().getCodingFirstRep().getSystem()); } } diff --git a/test/pom.xml b/test/pom.xml index 1b9b3ae41..4b5967c32 100644 --- a/test/pom.xml +++ b/test/pom.xml @@ -90,6 +90,7 @@ org.springframework.boot spring-boot-starter-test + compile diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java index e3ab3fec6..d922a414b 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java @@ -1,11 +1,32 @@ package org.opencds.cqf.ruler.test; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.opencds.cqf.ruler.utility.IdCreator; +import org.opencds.cqf.ruler.utility.ResourceCreator; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -public class DaoIntegrationTest implements ResourceLoader { +@EnableAutoConfiguration(exclude = QuartzAutoConfiguration.class) +@Import(DaoOnlyConfig.class) +@TestPropertySource(properties = { + "scheduling_disabled=true", + "spring.main.allow-bean-definition-overriding=true", + "spring.batch.job.enabled=false", + "hapi.fhir.allow_external_references=true", + "hapi.fhir.enforce_referential_integrity_on_write=false", + "spring.datasource.url=jdbc:h2:mem:db" }) +@TestInstance(Lifecycle.PER_CLASS) +public class DaoIntegrationTest implements ResourceLoader, ResourceCreator, IdCreator { + @Autowired + TestDbService myDbService; @Autowired private FhirContext myCtx; @@ -22,5 +43,9 @@ public FhirContext getFhirContext() { public DaoRegistry getDaoRegistry() { return myDaoRegistry; } - + + @AfterAll + void baseAfterAll() { + myDbService.resetDatabase(); + } } diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java b/test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java index db608bbb8..76050f5ef 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/DaoOnlyConfig.java @@ -1,8 +1,14 @@ package org.opencds.cqf.ruler.test; +import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; @ComponentScan("org.opencds.cqf.ruler.external") public class DaoOnlyConfig { + @Bean + public TestDbService testDbService() { + return new TestDbService(); + } + } diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java index 845577283..75c376c32 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java @@ -1,15 +1,38 @@ package org.opencds.cqf.ruler.test; +import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.TestInstance; +import org.junit.jupiter.api.TestInstance.Lifecycle; +import org.opencds.cqf.ruler.Application; +import org.opencds.cqf.ruler.utility.IdCreator; +import org.opencds.cqf.ruler.utility.ResourceCreator; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.context.annotation.Import; +import org.springframework.test.context.TestPropertySource; import ca.uhn.fhir.context.FhirContext; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; -public class RestIntegrationTest implements ResourceLoader { +@EnableAutoConfiguration(exclude = QuartzAutoConfiguration.class) +@Import(Application.class) +@TestPropertySource(properties = { + "scheduling_disabled=true", + "spring.main.allow-bean-definition-overriding=true", + "spring.batch.job.enabled=false", + "hapi.fhir.allow_external_references=true", + "hapi.fhir.enforce_referential_integrity_on_write=false", + "spring.datasource.url=jdbc:h2:mem:db" }) +@TestInstance(Lifecycle.PER_CLASS) +public class RestIntegrationTest implements ResourceLoader, ResourceCreator, IdCreator { + + @Autowired + TestDbService myDbService; @Autowired private FhirContext myCtx; @@ -47,4 +70,9 @@ void baseBeforeEach() { String ourServerBase = "http://localhost:" + myPort + "/fhir/"; myClient = myCtx.newRestfulGenericClient(ourServerBase); } + + @AfterAll + void baseAfterAll() { + myDbService.resetDatabase(); + } } diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/TestDbService.java b/test/src/main/java/org/opencds/cqf/ruler/test/TestDbService.java new file mode 100644 index 000000000..f2f4e3766 --- /dev/null +++ b/test/src/main/java/org/opencds/cqf/ruler/test/TestDbService.java @@ -0,0 +1,53 @@ +package org.opencds.cqf.ruler.test; + +import java.util.List; +import java.util.stream.Collectors; + +import javax.annotation.PostConstruct; +import javax.persistence.EntityManager; +import javax.persistence.Table; +import javax.transaction.Transactional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.util.StringUtils; + +@Service +public class TestDbService { + + @Autowired + private EntityManager entityManager; + private List tableNames; + + @PostConstruct + void afterPropertiesSet() { + tableNames = entityManager.getMetamodel().getEntities().stream() + .filter(entityType -> entityType.getJavaType().getAnnotation(Table.class) != null) + .map(entityType -> entityType.getJavaType().getAnnotation(Table.class)) + .map(this::convertToTableName) // TODO + .collect(Collectors.toList()); + } + + private String convertToTableName(Table table) { + String schema = table.schema(); + String tableName = table.name(); + + String convertedSchema = StringUtils.hasText(schema) ? schema.toLowerCase() + "." : ""; + String convertedTableName = tableName.replaceAll("([a-z])([A-Z])", "$1_$2"); + + return convertedSchema + convertedTableName; + } + + @Transactional + public void resetDatabase() { + entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY FALSE").executeUpdate(); + + for (String tableName : tableNames) { + entityManager.createNativeQuery("TRUNCATE TABLE " + tableName).executeUpdate(); + } + + entityManager.createNativeQuery("DROP ALL OBJECTS").executeUpdate(); + + entityManager.createNativeQuery("SET REFERENTIAL_INTEGRITY TRUE").executeUpdate(); + } +} From 245d1552d0039e065b3df48a1df09d7e5088240e Mon Sep 17 00:00:00 2001 From: JP Date: Mon, 24 Jan 2022 12:42:44 -0700 Subject: [PATCH 06/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 24eee36ca..56ac0a567 100644 --- a/README.md +++ b/README.md @@ -122,7 +122,7 @@ Behavior specific utilities allow the reuse of behavior across many different cl ### Class Specific Utilities -Utility or Helper methods that are associated with a single class should go into a class that has the pluralized name of the associated class. For example, utilities for `Client` should go into the `Clients` class. The ensures that the utility class is focused on one aspect and allows for more readable code: +Utility or Helper methods that are associated with a single class should go into a class that has the pluralized name of the associated class. For example, utilities for `Client` should go into the `Clients` class. This ensures that the utility class is focused on one class and allows for more readable code: `Clients.forUrl("test.com")` From 43cf55435df63ce4147fd2a357060605c31acd2c Mon Sep 17 00:00:00 2001 From: JP Date: Mon, 24 Jan 2022 12:51:54 -0700 Subject: [PATCH 07/12] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 56ac0a567..e68f49882 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ To run the cqf-ruler directory from this project use: ### Module Structure -The cqf-ruler uses the hapi-fhir-jpaserver-starter project as a base. On top of that, it adds an extensible API and utility functions to allow creating plugins which contain functionality for a specific IG. This diagram shows how it's structured +The cqf-ruler uses the hapi-fhir-jpaserver-starter project as a base. On top of that, it adds an extensiblity API and utility functions to allow creating plugins which contain functionality for a specific IG. This diagram shows how it's structured ![Module Diagram](docs/diagrams/modules.drawio.svg) From a5bf435d6e26dbb9ca4577ca6f960347f407d5b5 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Mon, 24 Jan 2022 15:39:37 -0700 Subject: [PATCH 08/12] Readme cleanup --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 24eee36ca..58a4307b9 100644 --- a/README.md +++ b/README.md @@ -110,9 +110,9 @@ To this end: * The CQF Ruler project has adopted the HAPI Coding Conventions: * Plugins should generally use the "hapi.fhir" prefix for configuration properties -## Utility Guidelines +### Utility Guidelines -### Types of Utilities +#### Types of Utilities In general, reusable utilities are separated along two different dimensions, Classes and Behaviors. @@ -120,7 +120,7 @@ Class specific utilities are functions that are associated with specific class o Behavior specific utilities allow the reuse of behavior across many different classes. -### Class Specific Utilities +#### Class Specific Utilities Utility or Helper methods that are associated with a single class should go into a class that has the pluralized name of the associated class. For example, utilities for `Client` should go into the `Clients` class. The ensures that the utility class is focused on one aspect and allows for more readable code: @@ -143,7 +143,7 @@ Examples * Factory functions * Adding behavior to a class you can't extend -### Behavior Specific Utilities +#### Behavior Specific Utilities If there is behavior you'd like to share across many classes, model that as an interface and use a name that follows the pattern `"ThingDoer"`. For example, all the classes that access a database might be `DatabaseReader`. Use `default` interface implementations to write logic that can be shared many places. The interfaces themselves shouldn't have mutable state (again `static final` is ok). If it's necessary for the for shared logic to have access to state, model that as an method without a default implementation. For example: From 409ea1735956478fb2c1a7aabc323a36171c3fbf Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Tue, 25 Jan 2022 15:45:41 -0700 Subject: [PATCH 09/12] Fix Versions utility --- .../main/java/org/opencds/cqf/ruler/utility/Versions.java | 1 - .../java/org/opencds/cqf/ruler/utility/VersionsTest.java | 6 +++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Versions.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Versions.java index e4990677d..494a37bd7 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/Versions.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Versions.java @@ -76,7 +76,6 @@ public static ResourceType selectByVersion( String theVersion, Function theGetVersion) { checkNotNull(theResources); - checkNotNull(theVersion); checkNotNull(theGetVersion); ResourceType library = null; diff --git a/core/src/test/java/org/opencds/cqf/ruler/utility/VersionsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/VersionsTest.java index dd6547721..22e2f259e 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/utility/VersionsTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/VersionsTest.java @@ -49,8 +49,12 @@ public void testSelectFromList() { Library lib = Versions.selectByVersion(libraries, "1.0.0", getVersion); assertEquals("1.0.0", lib.getVersion()); - // Gets max version (null is considering max version) + // Gets max version (null version on library is considered max version) lib = Versions.selectByVersion(libraries, "2.0.0", getVersion); assertNull(lib.getVersion()); + + // Null version max version (null input gets max version) + lib = Versions.selectByVersion(libraries, null, getVersion); + assertNull(lib.getVersion()); } } From 4de1284b883106e95f8a84aa8dd07ef946b3bb3e Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Tue, 25 Jan 2022 22:47:16 -0700 Subject: [PATCH 10/12] Tests for canonicals, tests for IdCreator, Searches byCanonical, bug fixes --- .../org/opencds/cqf/ruler/Application.java | 3 +- .../opencds/cqf/ruler/utility/Canonicals.java | 228 ++++++++++++------ .../opencds/cqf/ruler/utility/Searches.java | 33 ++- .../cqf/ruler/utility/CanonicalsTest.java | 65 +++++ .../cqf/ruler/utility/IdCreatorTest.java | 40 +++ .../cqf/ruler/cr/r4/ExpressionEvaluation.java | 7 +- .../cqf/ruler/test/DaoIntegrationTest.java | 3 +- .../cqf/ruler/test/RestIntegrationTest.java | 7 +- 8 files changed, 303 insertions(+), 83 deletions(-) create mode 100644 core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java create mode 100644 core/src/test/java/org/opencds/cqf/ruler/utility/IdCreatorTest.java diff --git a/core/src/main/java/org/opencds/cqf/ruler/Application.java b/core/src/main/java/org/opencds/cqf/ruler/Application.java index 35eddfcae..139572ba9 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/Application.java +++ b/core/src/main/java/org/opencds/cqf/ruler/Application.java @@ -12,6 +12,7 @@ import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration; +import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.ServletComponentScan; import org.springframework.boot.web.servlet.ServletRegistrationBean; @@ -35,7 +36,7 @@ Application.class }, excludeFilters = @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = { FhirTesterConfig.class, org.opencds.cqf.ruler.external.Application.class, StarterCqlR4Config.class, StarterCqlDstu3Config.class, CqlR4Config.class, CqlDstu3Config.class, BaseCqlConfig.class })) -@SpringBootApplication(exclude = { ElasticsearchRestClientAutoConfiguration.class }) +@SpringBootApplication(exclude = { ElasticsearchRestClientAutoConfiguration.class, QuartzAutoConfiguration.class }) @Import({ SubscriptionSubmitterConfig.class, SubscriptionProcessorConfig.class, SubscriptionChannelConfig.class, WebsocketDispatcherConfig.class, MdmConfig.class, TesterUIConfig.class, BeanFinderConfig.class }) public class Application extends SpringBootServletInitializer { diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java index 41a839f7c..47d0ebce3 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java @@ -3,52 +3,48 @@ import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; -import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IPrimitiveType; -import ca.uhn.fhir.context.FhirVersionEnum; - public class Canonicals { private Canonicals() { } - interface CanonicalParts { - String getVersion(); - + interface CanonicalParts { String getUrl(); - IdType getId(); - } - - public static > String getId(CanonicalType theCanonicalType) { - checkNotNull(theCanonicalType); - checkArgument(theCanonicalType.getValue() != null); + String getIdPart(); - return getId(theCanonicalType.getValue()); - } + String getResourceType(); - @SuppressWarnings("unchecked") - public static , IdType extends IIdType> IdType getIdElement( - CanonicalType theCanonicalType) { - checkNotNull(theCanonicalType); - checkArgument(theCanonicalType.getValue() != null); + String getVersion(); - String id = getId(theCanonicalType.getValue()); - String resourceName = getResourceName(theCanonicalType.getValue()); + String getFragment(); - return (IdType) Ids.newId(theCanonicalType.getClass(), resourceName, id); } - public static > String getResourceName(CanonicalType canonicalType) { - if (canonicalType == null || !canonicalType.hasValue()) { - throw new IllegalArgumentException("CanonicalType must have a value for id extraction"); - } + /** + * Gets the Resource type component of a canonical url + * + * @param A CanonicalType + * @param theCanonicalType the canonical url to parse + * @return the Resource type, or null if one can not be parsed + */ + public static > String getResourceType(CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.hasValue()); - return getResourceName(canonicalType.getValue()); + return getResourceType(theCanonicalType.getValue()); } - public static String getResourceName(String theCanonical) { + /** + * Gets the ResourceType component of a canonical url + * + * @param theCanonical the canonical url to parse + * @return the ResourceType, or null if one can not be parsed + */ + + public static String getResourceType(String theCanonical) { checkNotNull(theCanonical); if (!theCanonical.contains("/")) { @@ -59,16 +55,61 @@ public static String getResourceName(String theCanonical) { return theCanonical.contains("/") ? theCanonical.substring(theCanonical.lastIndexOf("/") + 1) : theCanonical; } - public static String getId(String theCanonical) { + /** + * Gets the ID component of a canonical url. Does not include resource name if present in the url. + * + * @param A CanonicalType + * @param theCanonicalType the canonical url to parse + * @return the Id, or null if one can not be parsed + */ + public static > String getIdPart(CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.hasValue()); + + return getIdPart(theCanonicalType.getValue()); + } + + /** + * Gets the ID component of a canonical url. Does not include resource name if present in the url. + * + * @param theCanonical the canonical url to parse + * @return the Id, or null if one can not be parsed + */ + public static String getIdPart(String theCanonical) { checkNotNull(theCanonical); if (!theCanonical.contains("/")) { return null; } - return theCanonical.contains("/") ? theCanonical.substring(theCanonical.lastIndexOf("/") + 1) : theCanonical; + int lastIndex = Math.min(theCanonical.lastIndexOf("|"), theCanonical.lastIndexOf("#")); + if (lastIndex == -1) { + lastIndex = theCanonical.length(); + } + + return theCanonical.substring(theCanonical.lastIndexOf("/") + 1, lastIndex); + } + + /** + * Gets the Version component of a canonical url + * + * @param A CanonicalType + * @param theCanonicalType the canonical url to parse + * @return the Version, or null if one can not be parsed + */ + public static > String getVersion(CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.hasValue()); + + return getVersion(theCanonicalType.getValue()); } + /** + * Gets the Version component of a canonical url + * + * @param theCanonical the canonical url to parse + * @return the Version, or null if one can not be parsed + */ public static String getVersion(String theCanonical) { checkNotNull(theCanonical); @@ -76,75 +117,122 @@ public static String getVersion(String theCanonical) { return null; } - String[] urlParts = theCanonical.split("\\|"); - if (urlParts.length <= 1) { - return null; + int lastIndex = theCanonical.lastIndexOf("#"); + if (lastIndex == -1) { + lastIndex = theCanonical.length(); } - return urlParts[1]; + return theCanonical.substring(theCanonical.lastIndexOf("|") + 1, lastIndex); + } + + /** + * Gets the Url component of a canonical url. Includes the base url, the resource type, and the id if present. + * + * @param A CanonicalType + * @param theCanonicalType the canonical url to parse + * @return the Url, or null if one can not be parsed + */ + public static > String getUrl(CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.hasValue()); + + return getUrl(theCanonicalType.getValue()); } + + /** + * Get the Url component of a canonical url. Includes the base url, the resource type, and the id if present. + * + * @param theCanonical the canonical url to parse + * @return the Url, or null if one can not be parsed + */ public static String getUrl(String theCanonical) { checkNotNull(theCanonical); - if (!theCanonical.contains("|")) { - return theCanonical; + if (!theCanonical.contains("/")) { + return null; } - String[] urlParts = theCanonical.split("\\|"); - return urlParts[0]; + int lastIndex = Math.min(theCanonical.lastIndexOf("|"), theCanonical.lastIndexOf("#")); + if (lastIndex == -1) { + lastIndex = theCanonical.length(); + } + + return theCanonical.substring(0, lastIndex); } - public static , IdType extends IIdType> CanonicalParts getCanonicalParts( + /** + * Gets the Fragment component of a canonical url. + * + * @param A CanonicalType + * @param theCanonicalType the canonical url to parse + * @return the Fragment, or null if one can not be parsed + */ + public static > String getFragment(CanonicalType theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.hasValue()); + + return getFragment(theCanonicalType.getValue()); + } + + + /** + * Gets the Fragment component of a canonical url. + * + * @param theCanonical the canonical url to parse + * @return the Fragment, or null if one can not be parsed + */ + public static String getFragment(String theCanonical) { + checkNotNull(theCanonical); + + if (!theCanonical.contains("#")) { + return null; + } + + return theCanonical.substring(theCanonical.lastIndexOf("#") + 1); + } + + public static > CanonicalParts getCanonicalParts( CanonicalType theCanonicalType) { checkNotNull(theCanonicalType); - checkArgument(theCanonicalType.getValue() != null, "theCanonicalType must have a value"); + checkArgument(theCanonicalType.hasValue()); - String version = getVersion(theCanonicalType.getValue()); - String url = getUrl(theCanonicalType.getValue()); - IdType id = getIdElement(theCanonicalType); - return new CanonicalParts() { - @Override - public String getVersion() { - return version; - } + return getCanonicalParts(theCanonicalType.getValue()); - @Override - public IdType getId() { - return id; - } + } + public static CanonicalParts getCanonicalParts(String theCanonical) { + checkNotNull(theCanonical); + + String url = getUrl(theCanonical); + String resourceType = getResourceType(theCanonical); + String id = getIdPart(theCanonical); + String version = getVersion(theCanonical); + String fragment = getFragment(theCanonical); + return new CanonicalParts() { @Override public String getUrl() { return url; } - }; - } - public static CanonicalParts getCanonicalParts(FhirVersionEnum theFhirVersionEnum, - String theCanonical) { - checkNotNull(theFhirVersionEnum); - checkNotNull(theCanonical); + @Override + public String getResourceType() { + return resourceType; + } - String version = getVersion(theCanonical); - String url = getUrl(theCanonical); - String resourceType = getResourceName(theCanonical); - String id = getId(theCanonical); - IdType idElement = Ids.newId(theFhirVersionEnum, resourceType, id); - return new CanonicalParts() { @Override - public String getVersion() { - return version; + public String getIdPart() { + return id; } @Override - public IdType getId() { - return idElement; + public String getVersion() { + return version; } @Override - public String getUrl() { - return url; + public String getFragment() { + return fragment; } }; } diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java index e88f5b92c..887d16ed2 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java @@ -1,7 +1,10 @@ package org.opencds.cqf.ruler.utility; +import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; +import org.hl7.fhir.instance.model.api.IPrimitiveType; + import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.rest.param.StringParam; @@ -27,20 +30,42 @@ public static SearchParameterMap byParam(String theParamName, IQueryParameterTyp checkNotNull(theParamName); checkNotNull(theParam); - return SearchParameterMap.newSynchronous(theParamName, theParam); + return sync().add(theParamName, theParam); } public static SearchParameterMap byName(String theName) { checkNotNull(theName); - return SearchParameterMap.newSynchronous("name", new StringParam(theName)); + return byParam("name", new StringParam(theName)); + } + + public static SearchParameterMap byNameAndVersion(String theName, String theVersion) { + checkNotNull(theName); + + return byName(theName).add("version", new StringParam(theVersion)); } public static SearchParameterMap byUrl(String theUrl) { checkNotNull(theUrl); + return byParam("url", new UriParam(theUrl)); + } + + public static SearchParameterMap byCanonical(String theCanonical) { + checkNotNull(theCanonical); + + SearchParameterMap search = byUrl(Canonicals.getUrl(theCanonical)); + String version = Canonicals.getVersion(theCanonical); + if (version != null) { + search.add("version", new StringParam(version)); + } + + return search; + } - String url = Canonicals.getUrl(theUrl); + public static > SearchParameterMap byCanonical(C theCanonicalType) { + checkNotNull(theCanonicalType); + checkArgument(theCanonicalType.hasValue()); - return SearchParameterMap.newSynchronous("url", new UriParam(url)); + return byCanonical(theCanonicalType.getValue()); } } diff --git a/core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java new file mode 100644 index 000000000..b0e27d985 --- /dev/null +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java @@ -0,0 +1,65 @@ +package org.opencds.cqf.ruler.utility; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.hl7.fhir.r4.model.CanonicalType; +import org.junit.jupiter.api.Test; +import org.opencds.cqf.ruler.utility.Canonicals.CanonicalParts; + +public class CanonicalsTest { + + @Test + public void fullCanonicalUrl() { + String testUrl = "http://fhir.acme.com/Questionnaire/example|1.0#vs1"; + + assertEquals("http://fhir.acme.com/Questionnaire/example", Canonicals.getUrl(testUrl)); + assertEquals("example", Canonicals.getIdPart(testUrl)); + assertEquals("1.0", Canonicals.getVersion(testUrl)); + assertEquals("vs1", Canonicals.getFragment(testUrl)); + } + + @Test + public void partialCanonicalUrl() { + String testUrl = "http://fhir.acme.com/Questionnaire/example"; + + assertEquals("http://fhir.acme.com/Questionnaire/example", Canonicals.getUrl(testUrl)); + assertEquals("example", Canonicals.getIdPart(testUrl)); + assertNull(Canonicals.getVersion(testUrl)); + assertNull(Canonicals.getFragment(testUrl)); + } + + @Test + public void fullCanonicalType() { + CanonicalType testUrl = new CanonicalType("http://fhir.acme.com/Questionnaire/example|1.0#vs1"); + + assertEquals("http://fhir.acme.com/Questionnaire/example", Canonicals.getUrl(testUrl)); + assertEquals("example", Canonicals.getIdPart(testUrl)); + assertEquals("1.0", Canonicals.getVersion(testUrl)); + assertEquals("vs1", Canonicals.getFragment(testUrl)); + } + + @Test + public void partialCanonicalType() { + CanonicalType testUrl = new CanonicalType("http://fhir.acme.com/Questionnaire/example"); + assertEquals("http://fhir.acme.com/Questionnaire/example", Canonicals.getUrl(testUrl)); + assertEquals("Questionnaire", Canonicals.getResourceType(testUrl)); + assertEquals("example", Canonicals.getIdPart(testUrl)); + assertNull(Canonicals.getVersion(testUrl)); + assertNull(Canonicals.getFragment(testUrl)); + } + + @Test + public void canonicalParts() { + CanonicalType testUrl = new CanonicalType("http://fhir.acme.com/Questionnaire/example|1.0#vs1"); + + CanonicalParts parts = Canonicals.getCanonicalParts(testUrl); + + assertEquals("http://fhir.acme.com/Questionnaire/example", parts.getUrl()); + assertEquals("Questionnaire", parts.getResourceType()); + assertEquals("example", Canonicals.getIdPart(testUrl), parts.getIdPart()); + assertEquals("1.0", Canonicals.getVersion(testUrl), parts.getVersion()); + assertEquals("vs1", Canonicals.getFragment(testUrl), parts.getFragment()); + } + +} diff --git a/core/src/test/java/org/opencds/cqf/ruler/utility/IdCreatorTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/IdCreatorTest.java new file mode 100644 index 000000000..0e8d0fd6d --- /dev/null +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/IdCreatorTest.java @@ -0,0 +1,40 @@ +package org.opencds.cqf.ruler.utility; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import org.hl7.fhir.instance.model.api.IIdType; +import org.hl7.fhir.r4.model.IdType; +import org.junit.jupiter.api.Test; + +import ca.uhn.fhir.context.FhirContext; + +public class IdCreatorTest implements IdCreator { + + @Override + public FhirContext getFhirContext() { + return FhirContext.forR4Cached(); + } + + @Test + public void createIdFromString() { + IIdType id = newId("Measure/123"); + + assertNotNull(id); + assertThat(id, instanceOf(IdType.class)); + assertEquals("Measure", id.getResourceType()); + assertEquals("123", id.getIdPart()); + } + + @Test + public void createIdFromParts() { + IIdType id = newId("Measure", "123"); + + assertNotNull(id); + assertThat(id, instanceOf(IdType.class)); + assertEquals("Measure", id.getResourceType()); + assertEquals("123", id.getIdPart()); + } +} diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java index e7fb58195..6f72ad2b8 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/ExpressionEvaluation.java @@ -10,6 +10,7 @@ import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.DomainResource; import org.hl7.fhir.r4.model.Extension; +import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Library; import org.hl7.fhir.r4.model.Measure; import org.hl7.fhir.r4.model.PlanDefinition; @@ -104,7 +105,7 @@ private Context setupContext(DomainResource instance, String cql, String patient // log error } if (executionLibrary == null) { - Library library = (Library) jpaFhirDal.read(Canonicals.getIdElement(libraries.get(0))); + Library library = (Library) jpaFhirDal.read(new IdType("Library", Canonicals.getIdPart(libraries.get(0)))); vi.setId(library.getName()); if (library.getVersion() != null) { vi.setVersion(library.getVersion()); @@ -198,7 +199,7 @@ private String buildIncludes(LibraryLoader libraryLoader, JpaFhirDal jpaFhirDal, } // else check local data for Library to get name and version from else { - Library library = (Library) jpaFhirDal.read(Canonicals.getIdElement(reference)); + Library library = (Library) jpaFhirDal.read(new IdType("Library", Canonicals.getIdPart(reference))); builder.append(buildLibraryIncludeString( new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion()))); } @@ -209,7 +210,7 @@ private String buildIncludes(LibraryLoader libraryLoader, JpaFhirDal jpaFhirDal, private VersionedIdentifier getVersionedIdentifierFromCanonical(CanonicalType reference) { VersionedIdentifier vi = new VersionedIdentifier(); - String cqlLibraryName = Canonicals.getIdElement(reference).getIdPart(); + String cqlLibraryName = Canonicals.getIdPart(reference); vi.withId(cqlLibraryName); String cqlLibraryVersion = null; if (reference.hasValue() && reference.getValue().split("\\|").length > 1) { diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java index d922a414b..93403a33c 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java @@ -22,7 +22,8 @@ "spring.batch.job.enabled=false", "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false", - "spring.datasource.url=jdbc:h2:mem:db" }) + "spring.datasource.url=jdbc:h2:mem:db" , + "spring.main.lazy-initialization=true" }) @TestInstance(Lifecycle.PER_CLASS) public class DaoIntegrationTest implements ResourceLoader, ResourceCreator, IdCreator { @Autowired diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java index 75c376c32..92ec13484 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java @@ -8,8 +8,6 @@ import org.opencds.cqf.ruler.utility.IdCreator; import org.opencds.cqf.ruler.utility.ResourceCreator; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.autoconfigure.EnableAutoConfiguration; -import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.annotation.Import; import org.springframework.test.context.TestPropertySource; @@ -19,7 +17,7 @@ import ca.uhn.fhir.rest.client.api.IGenericClient; import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum; -@EnableAutoConfiguration(exclude = QuartzAutoConfiguration.class) + @Import(Application.class) @TestPropertySource(properties = { "scheduling_disabled=true", @@ -27,7 +25,8 @@ "spring.batch.job.enabled=false", "hapi.fhir.allow_external_references=true", "hapi.fhir.enforce_referential_integrity_on_write=false", - "spring.datasource.url=jdbc:h2:mem:db" }) + "spring.datasource.url=jdbc:h2:mem:db", + "spring.main.lazy-initialization=true" }) @TestInstance(Lifecycle.PER_CLASS) public class RestIntegrationTest implements ResourceLoader, ResourceCreator, IdCreator { From 1fcbe0d10fae8442300ee07cc9f07db18564540a Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Wed, 26 Jan 2022 14:48:26 -0700 Subject: [PATCH 11/12] Continued refinement of utility classes --- .../DaoRegistryUser.java | 3 +- .../FhirContextUser.java | 2 +- .../{utility => behavior}/IdCreator.java | 3 +- .../ResourceCreator.java | 3 +- .../DaoRegistryOperationProvider.java | 4 +- .../cqf/ruler/utility/CanonicalParts.java | 37 ++ .../opencds/cqf/ruler/utility/Canonicals.java | 51 +- .../org/opencds/cqf/ruler/utility/Ids.java | 2 +- .../opencds/cqf/ruler/utility/Libraries.java | 74 +++ .../cqf/ruler/utility/LibraryFunctions.java | 37 ++ .../ruler/utility/ResolutionUtilities.java | 458 ------------------ .../opencds/cqf/ruler/utility/Searches.java | 23 +- .../ruler/utility/TypedBundleProvider.java | 14 + .../{utility => behavior}/IdCreatorTest.java | 2 +- .../cqf/ruler/utility/CanonicalsTest.java | 16 +- .../cqf/ruler/utility/LibrariesTest.java | 34 +- .../discovery/DiscoveryResolutionR4.java | 22 +- .../discovery/DiscoveryResolutionStu3.java | 21 +- .../ruler/cdshooks/dstu3/CdsHooksServlet.java | 37 +- .../ruler/cdshooks/r4/CdsHooksServlet.java | 39 +- .../org/opencds/cqf/ruler/cql/CqlConfig.java | 9 +- .../ruler/cql/JpaLibraryContentProvider.java | 40 +- .../org/opencds/cqf/ruler/cql/Libraries.java | 75 --- plugin/cr/pom.xml | 2 - .../cqf/ruler/ra/r4/ReportProvider.java | 2 +- pom.xml | 13 +- .../cqf/ruler/test/DaoIntegrationTest.java | 4 +- .../cqf/ruler/test/ResourceLoader.java | 4 +- .../cqf/ruler/test/RestIntegrationTest.java | 4 +- 29 files changed, 338 insertions(+), 697 deletions(-) rename core/src/main/java/org/opencds/cqf/ruler/{utility => behavior}/DaoRegistryUser.java (97%) rename core/src/main/java/org/opencds/cqf/ruler/{utility => behavior}/FhirContextUser.java (73%) rename core/src/main/java/org/opencds/cqf/ruler/{utility => behavior}/IdCreator.java (86%) rename core/src/main/java/org/opencds/cqf/ruler/{utility => behavior}/ResourceCreator.java (90%) create mode 100644 core/src/main/java/org/opencds/cqf/ruler/utility/CanonicalParts.java create mode 100644 core/src/main/java/org/opencds/cqf/ruler/utility/Libraries.java create mode 100644 core/src/main/java/org/opencds/cqf/ruler/utility/LibraryFunctions.java delete mode 100644 core/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java rename core/src/test/java/org/opencds/cqf/ruler/{utility => behavior}/IdCreatorTest.java (96%) rename plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java => core/src/test/java/org/opencds/cqf/ruler/utility/LibrariesTest.java (62%) delete mode 100644 plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/DaoRegistryUser.java b/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java similarity index 97% rename from core/src/main/java/org/opencds/cqf/ruler/utility/DaoRegistryUser.java rename to core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java index 39a320f9b..63779874c 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/DaoRegistryUser.java +++ b/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java @@ -1,10 +1,11 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.behavior; import static com.google.common.base.Preconditions.checkNotNull; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import org.opencds.cqf.ruler.utility.TypedBundleProvider; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/FhirContextUser.java b/core/src/main/java/org/opencds/cqf/ruler/behavior/FhirContextUser.java similarity index 73% rename from core/src/main/java/org/opencds/cqf/ruler/utility/FhirContextUser.java rename to core/src/main/java/org/opencds/cqf/ruler/behavior/FhirContextUser.java index 15a5ec101..9f65a2bd2 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/FhirContextUser.java +++ b/core/src/main/java/org/opencds/cqf/ruler/behavior/FhirContextUser.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.behavior; import ca.uhn.fhir.context.FhirContext; diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/IdCreator.java b/core/src/main/java/org/opencds/cqf/ruler/behavior/IdCreator.java similarity index 86% rename from core/src/main/java/org/opencds/cqf/ruler/utility/IdCreator.java rename to core/src/main/java/org/opencds/cqf/ruler/behavior/IdCreator.java index 4908343f7..47547e6f3 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/IdCreator.java +++ b/core/src/main/java/org/opencds/cqf/ruler/behavior/IdCreator.java @@ -1,8 +1,9 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.behavior; import static com.google.common.base.Preconditions.checkNotNull; import org.hl7.fhir.instance.model.api.IIdType; +import org.opencds.cqf.ruler.utility.Ids; public interface IdCreator extends FhirContextUser { diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java b/core/src/main/java/org/opencds/cqf/ruler/behavior/ResourceCreator.java similarity index 90% rename from core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java rename to core/src/main/java/org/opencds/cqf/ruler/behavior/ResourceCreator.java index 5c1d39c46..cbf3efc36 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/ResourceCreator.java +++ b/core/src/main/java/org/opencds/cqf/ruler/behavior/ResourceCreator.java @@ -1,10 +1,11 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.behavior; import static com.google.common.base.Preconditions.checkArgument; import static com.google.common.base.Preconditions.checkNotNull; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import org.opencds.cqf.ruler.utility.Resources; public interface ResourceCreator extends FhirContextUser { @SuppressWarnings("unchecked") diff --git a/core/src/main/java/org/opencds/cqf/ruler/provider/DaoRegistryOperationProvider.java b/core/src/main/java/org/opencds/cqf/ruler/provider/DaoRegistryOperationProvider.java index efdb43d75..953442560 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/provider/DaoRegistryOperationProvider.java +++ b/core/src/main/java/org/opencds/cqf/ruler/provider/DaoRegistryOperationProvider.java @@ -1,8 +1,8 @@ package org.opencds.cqf.ruler.provider; import org.opencds.cqf.ruler.api.OperationProvider; -import org.opencds.cqf.ruler.utility.DaoRegistryUser; -import org.opencds.cqf.ruler.utility.FhirContextUser; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; +import org.opencds.cqf.ruler.behavior.FhirContextUser; import org.springframework.beans.factory.annotation.Autowired; import ca.uhn.fhir.context.FhirContext; diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/CanonicalParts.java b/core/src/main/java/org/opencds/cqf/ruler/utility/CanonicalParts.java new file mode 100644 index 000000000..348680747 --- /dev/null +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/CanonicalParts.java @@ -0,0 +1,37 @@ +package org.opencds.cqf.ruler.utility; + +class CanonicalParts { + private final String url; + private final String idPart; + private final String resourceType; + private final String version; + private final String fragment; + + CanonicalParts(String url, String idPart, String resourceType, String version, String fragment) { + this.url = url; + this.idPart = idPart; + this.resourceType = resourceType; + this.version = version; + this.fragment = fragment; + } + + public String url() { + return this.url; + } + + public String idPart() { + return this.idPart; + } + + public String resourceType() { + return this.resourceType; + } + + public String version() { + return this.version; + } + + public String fragment() { + return this.fragment; + } +} diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java index 47d0ebce3..3860e4e90 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Canonicals.java @@ -9,20 +9,7 @@ public class Canonicals { private Canonicals() { } - - interface CanonicalParts { - String getUrl(); - - String getIdPart(); - - String getResourceType(); - - String getVersion(); - - String getFragment(); - - } - + /** * Gets the Resource type component of a canonical url * @@ -192,48 +179,22 @@ public static String getFragment(String theCanonical) { return theCanonical.substring(theCanonical.lastIndexOf("#") + 1); } - public static > CanonicalParts getCanonicalParts( + public static > CanonicalParts getParts( CanonicalType theCanonicalType) { checkNotNull(theCanonicalType); checkArgument(theCanonicalType.hasValue()); - return getCanonicalParts(theCanonicalType.getValue()); - + return getParts(theCanonicalType.getValue()); } - public static CanonicalParts getCanonicalParts(String theCanonical) { + public static CanonicalParts getParts(String theCanonical) { checkNotNull(theCanonical); String url = getUrl(theCanonical); - String resourceType = getResourceType(theCanonical); String id = getIdPart(theCanonical); + String resourceType = getResourceType(theCanonical); String version = getVersion(theCanonical); String fragment = getFragment(theCanonical); - return new CanonicalParts() { - @Override - public String getUrl() { - return url; - } - - @Override - public String getResourceType() { - return resourceType; - } - - @Override - public String getIdPart() { - return id; - } - - @Override - public String getVersion() { - return version; - } - - @Override - public String getFragment() { - return fragment; - } - }; + return new CanonicalParts(url, id, resourceType, version, fragment); } } diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java index 52caa330c..9b1544071 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Ids.java @@ -130,7 +130,7 @@ public static IdType newId(FhirVersionEnum theFhirVersi case R5: return (IdType) new org.hl7.fhir.r5.model.IdType(theId); default: - throw new IllegalArgumentException(String.format("createId does not support FHIR version %s", + throw new IllegalArgumentException(String.format("newId does not support FHIR version %s", theFhirVersionEnum.getFhirVersionString())); } } diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Libraries.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Libraries.java new file mode 100644 index 000000000..f8a10e996 --- /dev/null +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Libraries.java @@ -0,0 +1,74 @@ +package org.opencds.cqf.ruler.utility; + +import static com.google.common.base.Preconditions.checkArgument; +import static com.google.common.base.Preconditions.checkNotNull; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.function.Function; + +import org.hl7.fhir.instance.model.api.IBase; +import org.hl7.fhir.instance.model.api.IBaseResource; + +import ca.uhn.fhir.context.FhirContext; +import ca.uhn.fhir.context.FhirVersionEnum; + +public class Libraries { + + private static final Map cachedFunctions = new ConcurrentHashMap<>(); + private static final String LIBRARY_RESOURCE_TYPE = "Library"; + + private Libraries() { + } + + static byte[] getContent(IBaseResource library, LibraryFunctions libraryFunctions, String contentType) { + for (IBase attachment : libraryFunctions.getAttachments().apply(library)) { + String libraryContentType = libraryFunctions.getContentType().apply(attachment); + if (libraryContentType != null && libraryContentType.equals(contentType)) { + byte[] content = libraryFunctions.getContent().apply(attachment); + if (content != null) { + return content; + } + } + } + + return null; + } + + public static byte[] getContent(IBaseResource library, String contentType) { + checkNotNull(library); + checkArgument(library.fhirType().equals(LIBRARY_RESOURCE_TYPE)); + checkNotNull(contentType); + + LibraryFunctions libraryFunctions = getFunctions(library); + return getContent(library, libraryFunctions, contentType); + } + + static LibraryFunctions getFunctions(IBaseResource library) { + FhirVersionEnum fhirVersion = library.getStructureFhirVersionEnum(); + return cachedFunctions.computeIfAbsent(fhirVersion, Libraries::getFunctions); + } + + static LibraryFunctions getFunctions(FhirVersionEnum fhirVersionEnum) { + FhirContext fhirContext = FhirContext.forCached(fhirVersionEnum); + + Class libraryClass = fhirContext.getResourceDefinition(LIBRARY_RESOURCE_TYPE).getImplementingClass(); + Function> attachments = Reflections + .getFunction(libraryClass, "content"); + Function contentType = Reflections.getPrimitiveFunction( + fhirContext.getElementDefinition("Attachment").getImplementingClass(), "contentType"); + Function content = Reflections + .getPrimitiveFunction(fhirContext.getElementDefinition("Attachment").getImplementingClass(), "data"); + Function version = Reflections.getVersionFunction(libraryClass); + return new LibraryFunctions(attachments, contentType, content, version); + } + + public static String getVersion(IBaseResource library) { + checkNotNull(library); + checkArgument(library.fhirType().equals(LIBRARY_RESOURCE_TYPE)); + + LibraryFunctions libraryFunctions = getFunctions(library); + return libraryFunctions.getVersion().apply(library); + } +} diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/LibraryFunctions.java b/core/src/main/java/org/opencds/cqf/ruler/utility/LibraryFunctions.java new file mode 100644 index 000000000..3d1c73397 --- /dev/null +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/LibraryFunctions.java @@ -0,0 +1,37 @@ +package org.opencds.cqf.ruler.utility; + +import java.util.List; +import java.util.function.Function; + +import org.hl7.fhir.instance.model.api.IBase; + +class LibraryFunctions { + + private final Function> getAttachments; + private final Function getContentType; + private final Function getContent; + private final Function getVersion; + + LibraryFunctions(Function> getAttachments, Function getContentType, Function getContent, Function getVersion) { + this.getAttachments = getAttachments; + this.getContentType = getContentType; + this.getContent = getContent; + this.getVersion = getVersion; + } + + public Function> getAttachments() { + return this.getAttachments; + } + + public Function getContentType() { + return this.getContentType; + } + + public Function getContent() { + return this.getContent; + } + + public Function getVersion() { + return this.getVersion; + } +} diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java b/core/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java deleted file mode 100644 index 1cd0fcac1..000000000 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/ResolutionUtilities.java +++ /dev/null @@ -1,458 +0,0 @@ -package org.opencds.cqf.ruler.utility; - -import java.util.List; - -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.hl7.fhir.instance.model.api.IIdType; -import org.hl7.fhir.instance.model.api.IPrimitiveType; - -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; -import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.param.StringParam; -import ca.uhn.fhir.rest.param.UriParam; - -/** - * This interface provides utility functions for resolving FHIR resources based - * on id, name and version, or url. It supplies Tenant-aware overloads for the - * resolution functions as well. - * - * TODO: Eventually we need FhirDal versions of these functions. - */ -public interface ResolutionUtilities { - /** - * Returns the Resource with a matching Id - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theId the Id of the Resource to resolve - * @return the Resource matching the criteria - */ - default ResourceType resolveById(DaoRegistry theDaoRegistry, - IIdType theId) { - return this.resolveById(theDaoRegistry, theId, null); - } - - /** - * Returns the Resource with a matching Id - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theId the Id of the Resource to resolve - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - @SuppressWarnings("unchecked") - default ResourceType resolveById(DaoRegistry theDaoRegistry, - IIdType theId, RequestDetails theRequestDetails) { - if (theId.getResourceType() == null) { - throw new IllegalArgumentException("theId does not have a resourceType set."); - } - return (ResourceType) this.resolveById(theDaoRegistry.getResourceDao(theId.getResourceType()), theId, - theRequestDetails); - } - - /** - * Returns the Resource with a matching Id - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theId the Id of the Resource to resolve - * @return the Resource matching the criteria - */ - default ResourceType resolveById(DaoRegistry theDaoRegistry, - Class theResourceType, IIdType theId) { - return this.resolveById(theDaoRegistry.getResourceDao(theResourceType), theId, null); - } - - /** - * Returns the Resource with a matching Id - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theId the Id of the Resource to resolve - * @return the Resource matching the criteria - */ - default ResourceType resolveById(DaoRegistry theDaoRegistry, - Class theResourceType, String theId) { - return this.resolveById(theDaoRegistry.getResourceDao(theResourceType), theId, null); - } - - /** - * Returns the Resource with a matching Id. Tenant aware. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theId the Id of the Resource to resolve - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveById(DaoRegistry theDaoRegistry, - Class theResourceType, IIdType theId, RequestDetails theRequestDetails) { - return this.resolveById(theDaoRegistry.getResourceDao(theResourceType), theId, theRequestDetails); - } - - /** - * Returns the Resource with a matching Id. Tenant aware. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theId the Id of the Resource to resolve - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveById(DaoRegistry theDaoRegistry, - Class theResourceType, String theId, RequestDetails theRequestDetails) { - return this.resolveById(theDaoRegistry.getResourceDao(theResourceType), theId, theRequestDetails); - } - - /** - * Returns the Resource with a matching Id - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theId the Id of the Resource to resolve. - * @return the Resource matching the criteria - */ - default ResourceType resolveById( - IFhirResourceDao theResourceDao, IIdType theId) { - return this.resolveById(theResourceDao, theId, null); - } - - /** - * Returns the Resource with a matching Id - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theId the Id of the Resource to resolve. - * @return the Resource matching the criteria - */ - default ResourceType resolveById( - IFhirResourceDao theResourceDao, String theId) { - return this.resolveById(theResourceDao, theId, null); - } - - /** - * Returns the Resource with a matching Id, tenant aware - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theId the Id of the Resource to resolve. - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveById( - IFhirResourceDao theResourceDao, String theId, RequestDetails theRequestDetails) { - IIdType id = Ids.newId(theResourceDao.getContext(), theId); - return this.resolveById(theResourceDao, id, theRequestDetails); - } - - /** - * Returns the Resource with a matching Id, tenant aware - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theId the Id of the Resource to resolve. - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveById( - IFhirResourceDao theResourceDao, IIdType theId, RequestDetails theRequestDetails) { - return theResourceDao.read(theId, theRequestDetails); - } - - /** - * Returns a Resource with a matching name. The highest matching version is - * returned if more than one resource is found. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theName the name of the Resource - * @return the Resource matching the criteria - */ - default ResourceType resolveByName(DaoRegistry theDaoRegistry, - Class theResourceType, String theName) { - return resolveByNameAndVersion(theDaoRegistry.getResourceDao(theResourceType), theName, null, null); - } - - /** - * Returns a Resource with a matching name. The highest matching version is - * returned if more than one resource is found. Tenant aware. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @param theName the name of the Resource - * @return the Resource matching the criteria - */ - default ResourceType resolveByName(DaoRegistry theDaoRegistry, - Class theResourceType, String theName, RequestDetails theRequestDetails) { - return resolveByNameAndVersion(theDaoRegistry.getResourceDao(theResourceType), theName, null, - theRequestDetails); - } - - /** - * Returns a Resource with a matching name. The highest matching version is - * returned if more than one resource is found. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theName the name of the Resource - * @return the Resource matching the criteria - */ - default ResourceType resolveByName( - IFhirResourceDao theResourceDao, String theName) { - return resolveByNameAndVersion(theResourceDao, theName, null, null); - } - - /** - * Returns a Resource with a matching name. The highest matching version is - * returned if more than one resource is found. Tenant aware. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @param theName the name of the Resource - * @return the Resource matching the criteria - */ - default ResourceType resolveByName( - IFhirResourceDao theResourceDao, String theName, RequestDetails theRequestDetails) { - return resolveByNameAndVersion(theResourceDao, theName, null, theRequestDetails); - } - - /** - * Returns a Resource with a matching name and version. The highest matching - * version is returned no direct match is found. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theName the name of the Resource - * @param theVersion the business version of the Resource - * @return the Resource matching the criteria - */ - default ResourceType resolveByNameAndVersion(DaoRegistry theDaoRegistry, - Class theResourceType, String theName, String theVersion) { - return this.resolveByNameAndVersion(theDaoRegistry.getResourceDao(theResourceType), theName, theVersion, null); - } - - /** - * Returns a Resource with a matching name and version. The highest matching - * version is returned no direct match is found. Tenant aware. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theName the name of the Resource - * @param theVersion the business version of the Resource - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveByNameAndVersion(DaoRegistry theDaoRegistry, - Class theResourceType, String theName, String theVersion, RequestDetails theRequestDetails) { - return this.resolveByNameAndVersion(theDaoRegistry.getResourceDao(theResourceType), theName, theVersion, - theRequestDetails); - } - - /** - * Returns a Resource with a matching name and version. The highest matching - * version is returned no direct match is found. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theName the name of the Resource - * @param theVersion the business version of the Resource - * @return the Resource matching the criteria - */ - default ResourceType resolveByNameAndVersion( - IFhirResourceDao theResourceDao, String theName, String theVersion) { - return this.resolveByNameAndVersion(theResourceDao, theName, theVersion, null); - } - - /** - * Returns a Resource with a matching name and version. The highest matching - * version is returned no direct match is found. Tenant aware. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theName the name of the Resource - * @param theVersion the business version of the Resource - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveByNameAndVersion( - IFhirResourceDao theResourceDao, String theName, String theVersion, - RequestDetails theRequestDetails) { - @SuppressWarnings("unchecked") - List resources = (List) theResourceDao - .search(SearchParameterMap.newSynchronous().add("name", new StringParam(theName))).getAllResources(); - - return Versions.selectByVersion(resources, theVersion, Reflections.getVersionFunction(theResourceDao.getResourceType())); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theUrl the url of the Resource to resolve - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl(DaoRegistry theDaoRegistry, - Class theResourceType, String theUrl) { - return this.resolveByCanonicalUrl(theDaoRegistry.getResourceDao(theResourceType), theUrl, null); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. Tenant aware. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theUrl the url of the Resource to resolve - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl(DaoRegistry theDaoRegistry, - Class theResourceType, String theUrl, RequestDetails theRequestDetails) { - return this.resolveByCanonicalUrl(theDaoRegistry.getResourceDao(theResourceType), theUrl, theRequestDetails); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theUrl the url of the Resource to resolve - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl( - IFhirResourceDao theResourceDao, String theUrl) { - return this.resolveByCanonicalUrl(theResourceDao, theUrl, null); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. Tenant aware. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theUrl the url of the Resource to resolve - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl( - IFhirResourceDao theResourceDao, String theUrl, RequestDetails theRequestDetails) { - - String url = Canonicals.getUrl(theUrl); - String version = Canonicals.getVersion(theUrl); - - @SuppressWarnings("unchecked") - List resources = (List) theResourceDao - .search(SearchParameterMap.newSynchronous().add("url", new UriParam(url))).getAllResources(); - - return Versions.selectByVersion(resources, version, Reflections.getVersionFunction(theResourceDao.getResourceType())); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theUrl the url of the Resource to resolve - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl(DaoRegistry theDaoRegistry, - Class theResourceType, IPrimitiveType theUrl) { - return this.resolveByCanonicalUrl(theDaoRegistry.getResourceDao(theResourceType), theUrl.getValue(), null); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. Tenant aware. - * - * @param an IBaseResource type - * @param theDaoRegistry the DaoRegistry to use for resolution - * @param theResourceType the class of the Resource - * @param theUrl the url of the Resource to resolve - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl(DaoRegistry theDaoRegistry, - Class theResourceType, IPrimitiveType theUrl, RequestDetails theRequestDetails) { - return this.resolveByCanonicalUrl(theDaoRegistry.getResourceDao(theResourceType), theUrl.getValue(), - theRequestDetails); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theUrl the url of the Resource to resolve - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl( - IFhirResourceDao theResourceDao, IPrimitiveType theUrl) { - return this.resolveByCanonicalUrl(theResourceDao, theUrl.getValue(), null); - } - - /** - * Returns a Resource with a matching canonical url. If the canonical url - * contains a version the matching version is returned. If the canonical url - * does not contain a version, or if no matching version is found, the highest - * version is returned. Tenant aware. - * - * @param an IBaseResource type - * @param theResourceDao the IFhirResourceDao to use for resolution - * @param theUrl the url of the Resource to resolve - * @param theRequestDetails the RequestDetails to use for resolution. Use this - * parameter to select a tenant. - * @return the Resource matching the criteria - */ - default ResourceType resolveByCanonicalUrl( - IFhirResourceDao theResourceDao, IPrimitiveType theUrl, - RequestDetails theRequestDetails) { - return this.resolveByCanonicalUrl(theResourceDao, theUrl.getValue(), theRequestDetails); - } -} diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java b/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java index 887d16ed2..c42f8230b 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/Searches.java @@ -11,6 +11,10 @@ import ca.uhn.fhir.rest.param.UriParam; public class Searches { + private static final String VERSION_SP = "version"; + private static final String URL_SP = "url"; + private static final String NAME_SP = "name"; + private Searches() { } @@ -36,18 +40,27 @@ public static SearchParameterMap byParam(String theParamName, IQueryParameterTyp public static SearchParameterMap byName(String theName) { checkNotNull(theName); - return byParam("name", new StringParam(theName)); + return byParam(NAME_SP, new StringParam(theName)); } - public static SearchParameterMap byNameAndVersion(String theName, String theVersion) { + public static SearchParameterMap byName(String theName, String theVersion) { checkNotNull(theName); + checkNotNull(theVersion); + + return byName(theName).add(VERSION_SP, new StringParam(theVersion)); + } - return byName(theName).add("version", new StringParam(theVersion)); + public static SearchParameterMap byUrl(String theUrl, String theVersion) { + checkNotNull(theUrl); + checkNotNull(theVersion); + + return byParam(URL_SP, new UriParam(theUrl)).add(VERSION_SP, new StringParam(theVersion)); } public static SearchParameterMap byUrl(String theUrl) { checkNotNull(theUrl); - return byParam("url", new UriParam(theUrl)); + + return byParam(URL_SP, new UriParam(theUrl)); } public static SearchParameterMap byCanonical(String theCanonical) { @@ -56,7 +69,7 @@ public static SearchParameterMap byCanonical(String theCanonical) { SearchParameterMap search = byUrl(Canonicals.getUrl(theCanonical)); String version = Canonicals.getVersion(theCanonical); if (version != null) { - search.add("version", new StringParam(version)); + search.add(VERSION_SP, new StringParam(version)); } return search; diff --git a/core/src/main/java/org/opencds/cqf/ruler/utility/TypedBundleProvider.java b/core/src/main/java/org/opencds/cqf/ruler/utility/TypedBundleProvider.java index f7d3aa204..563af3293 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/utility/TypedBundleProvider.java +++ b/core/src/main/java/org/opencds/cqf/ruler/utility/TypedBundleProvider.java @@ -1,6 +1,7 @@ package org.opencds.cqf.ruler.utility; import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.base.Preconditions.checkState; import java.util.ArrayList; import java.util.Date; @@ -67,4 +68,17 @@ public List getAllResourcesTyped() { } return retval; } + + public T single() { + checkState(this.myInnerProvider.size() > 1, "More than one resource found"); + + return first(); + } + + + public T first() { + checkState(this.myInnerProvider.size() == 0, "No resources found"); + + return getResourcesTyped(0, 1).get(0); + } } diff --git a/core/src/test/java/org/opencds/cqf/ruler/utility/IdCreatorTest.java b/core/src/test/java/org/opencds/cqf/ruler/behavior/IdCreatorTest.java similarity index 96% rename from core/src/test/java/org/opencds/cqf/ruler/utility/IdCreatorTest.java rename to core/src/test/java/org/opencds/cqf/ruler/behavior/IdCreatorTest.java index 0e8d0fd6d..dc0a2242a 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/utility/IdCreatorTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/behavior/IdCreatorTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.utility; +package org.opencds.cqf.ruler.behavior; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.MatcherAssert.assertThat; diff --git a/core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java index b0e27d985..8e6c18f3a 100644 --- a/core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/CanonicalsTest.java @@ -5,10 +5,8 @@ import org.hl7.fhir.r4.model.CanonicalType; import org.junit.jupiter.api.Test; -import org.opencds.cqf.ruler.utility.Canonicals.CanonicalParts; public class CanonicalsTest { - @Test public void fullCanonicalUrl() { String testUrl = "http://fhir.acme.com/Questionnaire/example|1.0#vs1"; @@ -42,6 +40,7 @@ public void fullCanonicalType() { @Test public void partialCanonicalType() { CanonicalType testUrl = new CanonicalType("http://fhir.acme.com/Questionnaire/example"); + assertEquals("http://fhir.acme.com/Questionnaire/example", Canonicals.getUrl(testUrl)); assertEquals("Questionnaire", Canonicals.getResourceType(testUrl)); assertEquals("example", Canonicals.getIdPart(testUrl)); @@ -53,13 +52,12 @@ public void partialCanonicalType() { public void canonicalParts() { CanonicalType testUrl = new CanonicalType("http://fhir.acme.com/Questionnaire/example|1.0#vs1"); - CanonicalParts parts = Canonicals.getCanonicalParts(testUrl); + CanonicalParts parts = Canonicals.getParts(testUrl); - assertEquals("http://fhir.acme.com/Questionnaire/example", parts.getUrl()); - assertEquals("Questionnaire", parts.getResourceType()); - assertEquals("example", Canonicals.getIdPart(testUrl), parts.getIdPart()); - assertEquals("1.0", Canonicals.getVersion(testUrl), parts.getVersion()); - assertEquals("vs1", Canonicals.getFragment(testUrl), parts.getFragment()); + assertEquals("http://fhir.acme.com/Questionnaire/example", parts.url()); + assertEquals("Questionnaire", parts.resourceType()); + assertEquals("example", parts.idPart()); + assertEquals("1.0", parts.version()); + assertEquals("vs1", parts.fragment()); } - } diff --git a/plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java b/core/src/test/java/org/opencds/cqf/ruler/utility/LibrariesTest.java similarity index 62% rename from plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java rename to core/src/test/java/org/opencds/cqf/ruler/utility/LibrariesTest.java index 3a970946c..680cb96b4 100644 --- a/plugin/cql/src/test/java/org/opencds/cqf/ruler/cql/LibraryUtilitiesTest.java +++ b/core/src/test/java/org/opencds/cqf/ruler/utility/LibrariesTest.java @@ -1,4 +1,4 @@ -package org.opencds.cqf.ruler.cql; +package org.opencds.cqf.ruler.utility; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertNull; @@ -8,13 +8,13 @@ import org.hl7.fhir.r4.model.Measure; import org.junit.jupiter.api.Test; -public class LibraryUtilitiesTest implements Libraries { +public class LibrariesTest { @Test public void libraryNoContentReturnsNull() { Library library = new Library(); - byte[] content = this.getContent(library, "text/cql"); + byte[] content = Libraries.getContent(library, "text/cql"); assertNull(content); } @@ -25,7 +25,7 @@ public void libraryWithContentReturnsContent() { library.addContent().setContentType("text/cql").setData("test-data".getBytes()); - byte[] content = this.getContent(library, "text/cql"); + byte[] content = Libraries.getContent(library, "text/cql"); assertEquals("test-data", new String(content)); } @@ -36,7 +36,7 @@ public void libraryMismatchedContentReturnsNull() { library.addContent().setContentType("text/cql").setData("test-data".getBytes()); - byte[] content = this.getContent(library, "text/elm"); + byte[] content = Libraries.getContent(library, "text/elm"); assertNull(content); } @@ -47,16 +47,34 @@ public void libraryDstu3WithContentReturnsContent() { library.addContent().setContentType("text/cql").setData("test-data".getBytes()); - byte[] content = this.getContent(library, "text/cql"); + byte[] content = Libraries.getContent(library, "text/cql"); assertEquals("test-data", new String(content)); } @Test public void notALibraryThrowsException() { - + Measure m = new Measure(); assertThrows(IllegalArgumentException.class, () -> { - this.getContent(new Measure(), "text/cql"); + Libraries.getContent(m, "text/cql"); }); } + + @Test + public void libraryWithVersionReturnsVersion() { + Library library = new Library().setVersion("1.0.0"); + + String version = Libraries.getVersion(library); + + assertEquals("1.0.0", version); + } + + @Test + public void libraryNoVersionReturnsNull() { + Library library = new Library(); + + String version = Libraries.getVersion(library); + + assertNull(version); + } } diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java index 106a0dc1b..10868a3ca 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java @@ -5,18 +5,18 @@ import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Bundle; -import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.DataRequirement; import org.hl7.fhir.r4.model.Library; import org.hl7.fhir.r4.model.PlanDefinition; import org.hl7.fhir.r4.model.ValueSet; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; +import org.opencds.cqf.ruler.utility.Searches; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; -public class DiscoveryResolutionR4 implements ResolutionUtilities { +public class DiscoveryResolutionR4 implements DaoRegistryUser { private final String PATIENT_ID_CONTEXT = "{{context.patientId}}"; private final int DEFAULT_MAX_URI_LENGTH = 8000; @@ -29,6 +29,11 @@ public DiscoveryResolutionR4(DaoRegistry daoRegistry) { this.maxUriLength = DEFAULT_MAX_URI_LENGTH; } + @Override + public DaoRegistry getDaoRegistry() { + return this.daoRegistry; + } + public int getMaxUriLength() { return this.maxUriLength; } @@ -65,15 +70,11 @@ public Library resolvePrimaryLibrary(PlanDefinition planDefinition) { // library Library library = null; if (planDefinition.hasLibrary() && !planDefinition.getLibrary().isEmpty()) { - library = resolveLibrary(planDefinition.getLibrary().get(0)); + library = search(Library.class, Searches.byCanonical(planDefinition.getLibrary().get(0))).single(); } return library; } - public Library resolveLibrary(CanonicalType libraryId) { - return this.resolveByCanonicalUrl(daoRegistry, Library.class, libraryId.getValue()); - } - public List resolveValueCodingCodes(List valueCodings) { List result = new ArrayList<>(); @@ -92,10 +93,7 @@ public List resolveValueCodingCodes(List valueCodings) { } public List resolveValueSetCodes(String valueSetId) { - ValueSet valueSet = this.resolveByCanonicalUrl(daoRegistry, ValueSet.class, valueSetId); - if (valueSet == null) { - return null; - } + ValueSet valueSet = search(ValueSet.class, Searches.byCanonical(valueSetId)).single(); List result = new ArrayList<>(); StringBuilder codes = new StringBuilder(); if (valueSet.hasExpansion() && valueSet.getExpansion().hasContains()) { diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java index 1ef1c41a3..a00d461d8 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java @@ -10,12 +10,13 @@ import org.hl7.fhir.dstu3.model.PlanDefinition; import org.hl7.fhir.dstu3.model.ValueSet; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; +import org.opencds.cqf.ruler.utility.Searches; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; -public class DiscoveryResolutionStu3 implements ResolutionUtilities { +public class DiscoveryResolutionStu3 implements DaoRegistryUser { private final String PATIENT_ID_CONTEXT = "{{context.patientId}}"; private final int DEFAULT_MAX_URI_LENGTH = 8000; @@ -28,6 +29,11 @@ public DiscoveryResolutionStu3(DaoRegistry daoRegistry) { this.maxUriLength = DEFAULT_MAX_URI_LENGTH; } + @Override + public DaoRegistry getDaoRegistry() { + return this.daoRegistry; + } + public int getMaxUriLength() { return this.maxUriLength; } @@ -64,15 +70,11 @@ public Library resolvePrimaryLibrary(PlanDefinition planDefinition) { // library Library library = null; if (planDefinition.hasLibrary() && planDefinition.getLibraryFirstRep().hasReference()) { - library = resolveLibrary(planDefinition.getLibraryFirstRep().getReference()); + library = read(planDefinition.getLibraryFirstRep().getReferenceElement()); } return library; } - public Library resolveLibrary(String libraryId) { - return this.resolveById(daoRegistry, Library.class, libraryId); - } - public List resolveValueCodingCodes(List valueCodings) { List result = new ArrayList<>(); @@ -91,10 +93,7 @@ public List resolveValueCodingCodes(List valueCodings) { } public List resolveValueSetCodes(String valueSetId) { - ValueSet valueSet = this.resolveByCanonicalUrl(daoRegistry, ValueSet.class, valueSetId); - if (valueSet == null) { - return null; - } + ValueSet valueSet = this.search(ValueSet.class, Searches.byCanonical(valueSetId)).first(); List result = new ArrayList<>(); StringBuilder codes = new StringBuilder(); if (valueSet.hasExpansion() && valueSet.getExpansion().hasContains()) { diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java index 8981f42a6..1cd997a4f 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java @@ -26,6 +26,7 @@ import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.Library; import org.hl7.fhir.dstu3.model.PlanDefinition; +import org.hl7.fhir.dstu3.model.Reference; import org.opencds.cqf.cql.engine.debug.DebugMap; import org.opencds.cqf.cql.engine.exception.CqlException; import org.opencds.cqf.cql.engine.execution.Context; @@ -34,6 +35,7 @@ import org.opencds.cqf.cql.engine.model.ModelResolver; import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; import org.opencds.cqf.ruler.cdshooks.discovery.DiscoveryResolutionStu3; import org.opencds.cqf.ruler.cdshooks.evaluation.EvaluationContext; import org.opencds.cqf.ruler.cdshooks.evaluation.Stu3EvaluationContext; @@ -51,7 +53,6 @@ import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; import org.opencds.cqf.ruler.cr.dstu3.provider.PlanDefinitionApplyProvider; import org.opencds.cqf.ruler.external.AppProperties; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -64,7 +65,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -public class CdsHooksServlet extends HttpServlet implements ResolutionUtilities { +public class CdsHooksServlet extends HttpServlet implements DaoRegistryUser { private static final long serialVersionUID = 1L; @@ -160,14 +161,14 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) Hook hook = HookFactory.createHook(cdsHooksRequest); String hookName = hook.getRequest().getHook(); - logger.info("cds-hooks hook: " + hookName); - logger.info("cds-hooks hook instance: " + hook.getRequest().getHookInstance()); - logger.info("cds-hooks maxCodesPerQuery: " + this.getProviderConfiguration().getMaxCodesPerQuery()); - logger.info("cds-hooks expandValueSets: " + this.getProviderConfiguration().getExpandValueSets()); - logger.info("cds-hooks searchStyle: " + this.getProviderConfiguration().getSearchStyle()); - logger.info("cds-hooks prefetch maxUriLength: " + this.getProviderConfiguration().getMaxUriLength()); - logger.info("cds-hooks local server address: " + baseUrl); - logger.info("cds-hooks fhir server address: " + hook.getRequest().getFhirServerUrl()); + logger.info("cds-hooks hook: {}", hookName); + logger.info("cds-hooks hook instance: {}", hook.getRequest().getHookInstance()); + logger.info("cds-hooks maxCodesPerQuery: {}", this.getProviderConfiguration().getMaxCodesPerQuery()); + logger.info("cds-hooks expandValueSets: {}", this.getProviderConfiguration().getExpandValueSets()); + logger.info("cds-hooks searchStyle: {}", this.getProviderConfiguration().getSearchStyle()); + logger.info("cds-hooks prefetch maxUriLength: {}", this.getProviderConfiguration().getMaxUriLength()); + logger.info("cds-hooks local server address: {}", baseUrl); + logger.info("cds-hooks fhir server address: {}", hook.getRequest().getFhirServerUrl()); PlanDefinition planDefinition = planDefinitionProvider.getDao() .read(new IdType(hook.getRequest().getServiceName())); @@ -196,12 +197,13 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) Arrays.asList( jpaLibraryContentProviderFactory.create(requestDetails)))); - Library primaryLibrary = this.resolveByCanonicalUrl(daoRegistry, Library.class, planDefinition.getLibrary().get(0).getReference()); + Reference reference = planDefinition.getLibrary().get(0); + Library library = read(reference.getReferenceElement()); - org.cqframework.cql.elm.execution.Library library = libraryLoader.load( - new VersionedIdentifier().withId(primaryLibrary.getName()).withVersion(primaryLibrary.getVersion())); + org.cqframework.cql.elm.execution.Library elm = libraryLoader.load( + new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())); - Context context = new Context(library); + Context context = new Context(elm); context.setDebugMap(this.getDebugMap()); // provider case @@ -216,7 +218,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) EvaluationContext evaluationContext = new Stu3EvaluationContext(hook, version, FhirContext.forCached(FhirVersionEnum.DSTU3).newRestfulGenericClient(baseUrl), - serverTerminologyProvider, context, library, + serverTerminologyProvider, context, elm, planDefinition, this.getProviderConfiguration(), this.modelResolver); this.setAccessControlHeaders(response); @@ -374,4 +376,9 @@ public DebugMap getDebugMap() { } return debugMap; } + + @Override + public DaoRegistry getDaoRegistry() { + return this.daoRegistry; + } } diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java index 385c30467..2d02205a2 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java @@ -23,6 +23,7 @@ import org.apache.http.entity.ContentType; import org.cqframework.cql.elm.execution.VersionedIdentifier; +import org.hl7.fhir.r4.model.CanonicalType; import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Library; import org.hl7.fhir.r4.model.PlanDefinition; @@ -34,6 +35,7 @@ import org.opencds.cqf.cql.engine.model.ModelResolver; import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; import org.opencds.cqf.ruler.cdshooks.discovery.DiscoveryResolutionR4; import org.opencds.cqf.ruler.cdshooks.evaluation.EvaluationContext; import org.opencds.cqf.ruler.cdshooks.evaluation.R4EvaluationContext; @@ -51,7 +53,7 @@ import org.opencds.cqf.ruler.cql.LibraryLoaderFactory; import org.opencds.cqf.ruler.cr.r4.provider.PlanDefinitionApplyProvider; import org.opencds.cqf.ruler.external.AppProperties; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.utility.Searches; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -64,7 +66,7 @@ import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException; import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException; -public class CdsHooksServlet extends HttpServlet implements ResolutionUtilities { +public class CdsHooksServlet extends HttpServlet implements DaoRegistryUser { private static final long serialVersionUID = 1L; @@ -159,14 +161,14 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) Hook hook = HookFactory.createHook(cdsHooksRequest); String hookName = hook.getRequest().getHook(); - logger.info("cds-hooks hook: " + hookName); - logger.info("cds-hooks hook instance: " + hook.getRequest().getHookInstance()); - logger.info("cds-hooks maxCodesPerQuery: " + this.getProviderConfiguration().getMaxCodesPerQuery()); - logger.info("cds-hooks expandValueSets: " + this.getProviderConfiguration().getExpandValueSets()); - logger.info("cds-hooks searchStyle: " + this.getProviderConfiguration().getSearchStyle()); - logger.info("cds-hooks prefetch maxUriLength: " + this.getProviderConfiguration().getMaxUriLength()); - logger.info("cds-hooks local server address: " + baseUrl); - logger.info("cds-hooks fhir server address: " + hook.getRequest().getFhirServerUrl()); + logger.info("cds-hooks hook: {}", hookName); + logger.info("cds-hooks hook instance: {}", hook.getRequest().getHookInstance()); + logger.info("cds-hooks maxCodesPerQuery: {}", this.getProviderConfiguration().getMaxCodesPerQuery()); + logger.info("cds-hooks expandValueSets: {}", this.getProviderConfiguration().getExpandValueSets()); + logger.info("cds-hooks searchStyle: {}", this.getProviderConfiguration().getSearchStyle()); + logger.info("cds-hooks prefetch maxUriLength: {}", this.getProviderConfiguration().getMaxUriLength()); + logger.info("cds-hooks local server address: {}", baseUrl); + logger.info("cds-hooks fhir server address: {}", hook.getRequest().getFhirServerUrl()); PlanDefinition planDefinition = planDefinitionProvider.getDao() .read(new IdType(hook.getRequest().getServiceName())); @@ -195,13 +197,13 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) Arrays.asList( jpaLibraryContentProviderFactory.create(requestDetails)))); - Library primaryLibrary = this.resolveByCanonicalUrl(daoRegistry, Library.class, - planDefinition.getLibrary().get(0), requestDetails); + CanonicalType canonical = planDefinition.getLibrary().get(0); + Library library = search(Library.class, Searches.byCanonical(canonical)).single(); - org.cqframework.cql.elm.execution.Library library = libraryLoader.load( - new VersionedIdentifier().withId(primaryLibrary.getName()).withVersion(primaryLibrary.getVersion())); + org.cqframework.cql.elm.execution.Library elm = libraryLoader.load( + new VersionedIdentifier().withId(library.getName()).withVersion(library.getVersion())); - Context context = new Context(library); + Context context = new Context(elm); context.setDebugMap(this.getDebugMap()); @@ -220,7 +222,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) EvaluationContext evaluationContext = new R4EvaluationContext(hook, version, FhirContext.forCached(FhirVersionEnum.R4).newRestfulGenericClient(baseUrl), serverTerminologyProvider, - context, library, + context, elm, planDefinition, this.getProviderConfiguration(), this.modelResolver); this.setAccessControlHeaders(response); @@ -377,4 +379,9 @@ public DebugMap getDebugMap() { } return debugMap; } + + @Override + public DaoRegistry getDaoRegistry() { + return this.daoRegistry; + } } diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/CqlConfig.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/CqlConfig.java index 09127ec4a..38f5d2d71 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/CqlConfig.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/CqlConfig.java @@ -107,8 +107,8 @@ public JpaTerminologyProviderFactory jpaTerminologyProviderFactory(ITermReadSvc } @Bean - JpaLibraryContentProviderFactory jpaLibraryContentProviderFactory(IFhirResourceDao libraryDao) { - return rd -> new JpaLibraryContentProvider(libraryDao, rd); + JpaLibraryContentProviderFactory jpaLibraryContentProviderFactory(DaoRegistry daoRegistry) { + return rd -> new JpaLibraryContentProvider(daoRegistry, rd); } @Bean @@ -144,11 +144,6 @@ public Map(); } - @Bean - public IFhirResourceDao libraryDao(DaoRegistry daoRegistry) { - return daoRegistry.getResourceDao("Library"); - } - @Bean @Primary public ElmCacheResourceChangeListener elmCacheResourceChangeListener( diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java index 65cd30cc2..1c3fecd18 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java @@ -2,33 +2,38 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; -import java.util.HashMap; -import java.util.Map; import org.hl7.fhir.instance.model.api.IBaseResource; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentType; -import org.opencds.cqf.ruler.utility.ResolutionUtilities; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; +import org.opencds.cqf.ruler.utility.Libraries; +import org.opencds.cqf.ruler.utility.Searches; +import org.opencds.cqf.ruler.utility.Versions; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; +import ca.uhn.fhir.jpa.api.dao.DaoRegistry; +import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.RequestDetails; public class JpaLibraryContentProvider - implements LibraryContentProvider, ResolutionUtilities, Libraries { - private static Map, ContentFunctions> cachedContentFunctions = new HashMap<>(); - - protected final IFhirResourceDao libraryDao; + implements LibraryContentProvider, DaoRegistryUser { + protected final DaoRegistry daoRegistry; protected final RequestDetails requestDetails; - public JpaLibraryContentProvider(IFhirResourceDao libraryDao) { - this(libraryDao, null); + public JpaLibraryContentProvider(DaoRegistry daoRegistry) { + this(daoRegistry, null); } - public JpaLibraryContentProvider(IFhirResourceDao libraryDao, RequestDetails requestDetails) { - this.libraryDao = libraryDao; + public JpaLibraryContentProvider(DaoRegistry daoRegistry, RequestDetails requestDetails) { + this.daoRegistry = daoRegistry; this.requestDetails = requestDetails; } + @Override + public DaoRegistry getDaoRegistry() { + return this.daoRegistry; + } + @Override public InputStream getLibraryContent(org.hl7.elm.r1.VersionedIdentifier libraryIdentifier, LibraryContentType libraryContentType) { @@ -38,15 +43,14 @@ public InputStream getLibraryContent(org.hl7.elm.r1.VersionedIdentifier libraryI return null; } - IBaseResource library = this.resolveByNameAndVersion(this.libraryDao, libraryIdentifier.getId(), - libraryIdentifier.getVersion(), this.requestDetails); + IBundleProvider libraries = search("Library", Searches.byName(libraryIdentifier.getId()), requestDetails); + IBaseResource library = Versions.selectByVersion(libraries.getAllResources(), libraryIdentifier.getVersion(), + Libraries::getVersion); + if (library == null) { return null; } - - ContentFunctions cf = cachedContentFunctions.computeIfAbsent(libraryDao.getResourceType(), - x -> this.getContentFunctions(this.libraryDao.getContext())); - byte[] content = this.getContent(library, cf, "text/cql"); + byte[] content = Libraries.getContent(library, "text/cql"); if (content == null) { return null; } diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java deleted file mode 100644 index 482d84984..000000000 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/Libraries.java +++ /dev/null @@ -1,75 +0,0 @@ -package org.opencds.cqf.ruler.cql; - -import java.util.List; -import java.util.Objects; -import java.util.function.Function; - -import org.hl7.fhir.instance.model.api.IBase; -import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.utility.Reflections; - -import ca.uhn.fhir.context.FhirContext; - -public interface Libraries { - - default byte[] getContent(IBaseResource library, ContentFunctions contentFunctions, String contentType) { - Objects.requireNonNull(library, "library can not be null"); - Objects.requireNonNull(contentFunctions, "contentFunctions can not be null"); - if (!library.fhirType().equals("Library")) { - throw new IllegalArgumentException("the library parameter is not a FHIR Library Resource"); - } - - for (IBase attachment : contentFunctions.getAttachments().apply(library)) { - String libraryContentType = contentFunctions.getContentType().apply(attachment); - if (libraryContentType != null && libraryContentType.equals(contentType)) { - byte[] content = contentFunctions.getContent().apply(attachment); - if (content != null) { - return content; - } - } - } - - return null; - } - - default byte[] getContent(IBaseResource library, String contentType) { - ContentFunctions contentFunctions = this.getContentFunctions(library); - return this.getContent(library, contentFunctions, contentType); - } - - default ContentFunctions getContentFunctions(IBaseResource library) { - return this.getContentFunctions(FhirContext.forCached(library.getStructureFhirVersionEnum())); - } - - default ContentFunctions getContentFunctions(FhirContext fhirContext) { - Function> attachments = Reflections.getFunction(fhirContext.getResourceDefinition("Library").getImplementingClass(), "content"); - Function contentType = Reflections.getPrimitiveFunction( - fhirContext.getElementDefinition("Attachment").getImplementingClass(), "contentType"); - Function content = Reflections.getPrimitiveFunction(fhirContext.getElementDefinition("Attachment").getImplementingClass(), "data"); - return new ContentFunctions() { - - @Override - public Function> getAttachments() { - return attachments; - } - - @Override - public Function getContentType() { - return contentType; - } - - @Override - public Function getContent() { - return content; - } - }; - } - - interface ContentFunctions { - Function> getAttachments(); - - Function getContentType(); - - Function getContent(); - } -} diff --git a/plugin/cr/pom.xml b/plugin/cr/pom.xml index 70e97e23a..cc2b60f6a 100644 --- a/plugin/cr/pom.xml +++ b/plugin/cr/pom.xml @@ -11,12 +11,10 @@ org.opencds.cqf.cql evaluator.measure - 1.3.1-SNAPSHOT org.opencds.cqf.cql evaluator.measure-hapi - 1.3.1-SNAPSHOT org.opencds.cqf.ruler diff --git a/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java b/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java index 3a74991be..95b85ea22 100644 --- a/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java +++ b/plugin/ra/src/main/java/org/opencds/cqf/ruler/ra/r4/ReportProvider.java @@ -22,8 +22,8 @@ import org.hl7.fhir.r4.model.Period; import org.hl7.fhir.r4.model.Reference; import org.hl7.fhir.r4.model.Resource; +import org.opencds.cqf.ruler.behavior.IdCreator; import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; -import org.opencds.cqf.ruler.utility.IdCreator; import org.opencds.cqf.ruler.utility.Operations; import org.opencds.cqf.ruler.utility.Searches; import org.slf4j.Logger; diff --git a/pom.xml b/pom.xml index 82f8f8c3d..27b6edfe6 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ - + 4.0.0 org.opencds.cqf.ruler @@ -301,6 +302,16 @@ evaluator.spring ${cql-evaluator.version} + + org.opencds.cqf.cql + evaluator.measure + ${cql-evaluator.version} + + + org.opencds.cqf.cql + evaluator.measure-hapi + ${cql-evaluator.version} + org.springframework diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java index 93403a33c..c1a012284 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/DaoIntegrationTest.java @@ -3,8 +3,8 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; -import org.opencds.cqf.ruler.utility.IdCreator; -import org.opencds.cqf.ruler.utility.ResourceCreator; +import org.opencds.cqf.ruler.behavior.IdCreator; +import org.opencds.cqf.ruler.behavior.ResourceCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.boot.autoconfigure.quartz.QuartzAutoConfiguration; diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java b/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java index d9cc92ddb..549e8daf5 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/ResourceLoader.java @@ -17,8 +17,8 @@ import org.apache.commons.io.IOUtils; import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseResource; -import org.opencds.cqf.ruler.utility.DaoRegistryUser; -import org.opencds.cqf.ruler.utility.FhirContextUser; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; +import org.opencds.cqf.ruler.behavior.FhirContextUser; import org.springframework.core.io.DefaultResourceLoader; import org.springframework.core.io.Resource; diff --git a/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java index 92ec13484..7e6e67398 100644 --- a/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java +++ b/test/src/main/java/org/opencds/cqf/ruler/test/RestIntegrationTest.java @@ -5,8 +5,8 @@ import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.api.TestInstance.Lifecycle; import org.opencds.cqf.ruler.Application; -import org.opencds.cqf.ruler.utility.IdCreator; -import org.opencds.cqf.ruler.utility.ResourceCreator; +import org.opencds.cqf.ruler.behavior.IdCreator; +import org.opencds.cqf.ruler.behavior.ResourceCreator; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.context.annotation.Import; From 30c9c4ec6cd391b52839ac39d19704c946c590b6 Mon Sep 17 00:00:00 2001 From: Jonathan Percival Date: Wed, 26 Jan 2022 16:04:09 -0700 Subject: [PATCH 12/12] More cleanup / testing --- .../cqf/ruler/behavior/DaoRegistryUser.java | 16 +++ .../discovery/DiscoveryResolutionR4.java | 9 +- .../discovery/DiscoveryResolutionStu3.java | 10 +- .../ruler/cdshooks/dstu3/CdsHooksServlet.java | 4 +- .../ruler/cdshooks/r4/CdsHooksServlet.java | 4 +- .../ruler/cql/JpaFhirRetrieveProvider.java | 132 +++++++++--------- .../ruler/cql/JpaLibraryContentProvider.java | 8 +- .../cqf/ruler/cql/JpaTerminologyProvider.java | 26 ++-- .../r4/provider/MeasureEvaluateProvider.java | 10 +- .../dstu3/CacheValueSetsProviderIT.java | 4 - .../devtools/r4/CacheValueSetsProviderIT.java | 3 - 11 files changed, 109 insertions(+), 117 deletions(-) diff --git a/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java b/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java index 63779874c..71299d8a7 100644 --- a/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java +++ b/core/src/main/java/org/opencds/cqf/ruler/behavior/DaoRegistryUser.java @@ -5,6 +5,7 @@ import org.hl7.fhir.instance.model.api.IBaseBundle; import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.instance.model.api.IIdType; +import org.opencds.cqf.ruler.utility.Ids; import org.opencds.cqf.ruler.utility.TypedBundleProvider; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; @@ -21,6 +22,21 @@ public interface DaoRegistryUser { public DaoRegistry getDaoRegistry(); + default T read(Class theResourceClass, String theIdPart) { + checkNotNull(theResourceClass); + checkNotNull(theIdPart); + + return read(theResourceClass, theIdPart, null); + } + + default T read(Class theResourceClass, String theIdPart, RequestDetails requestDetails) { + checkNotNull(theResourceClass); + checkNotNull(theIdPart); + checkNotNull(requestDetails); + + return getDaoRegistry().getResourceDao(theResourceClass).read(Ids.newId(theResourceClass, theIdPart), requestDetails); + } + default T read(IIdType theId) { checkNotNull(theId); diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java index 10868a3ca..4a4e6e1d7 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionR4.java @@ -3,7 +3,6 @@ import java.util.ArrayList; import java.util.List; -import org.hl7.fhir.instance.model.api.IBaseResource; import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r4.model.Coding; import org.hl7.fhir.r4.model.DataRequirement; @@ -14,7 +13,6 @@ import org.opencds.cqf.ruler.utility.Searches; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; public class DiscoveryResolutionR4 implements DaoRegistryUser { @@ -190,12 +188,11 @@ public PrefetchUrlList getPrefetchUrlList(PlanDefinition planDefinition) { } public DiscoveryResponse resolve() { - List planDefinitions = this.daoRegistry.getResourceDao(PlanDefinition.class).search(SearchParameterMap.newSynchronous()).getAllResources(); + List planDefinitions = search(PlanDefinition.class, Searches.all()).getAllResourcesTyped(); DiscoveryResponse response = new DiscoveryResponse(); - for (IBaseResource resource : planDefinitions) { - PlanDefinition planDefinition = (PlanDefinition)resource; + for (PlanDefinition resource : planDefinitions) { response.addElement( - new DiscoveryElementR4(planDefinition, getPrefetchUrlList(planDefinition))); + new DiscoveryElementR4(resource, getPrefetchUrlList(resource))); } return response; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java index a00d461d8..8b4b786b5 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/discovery/DiscoveryResolutionStu3.java @@ -9,12 +9,10 @@ import org.hl7.fhir.dstu3.model.Library; import org.hl7.fhir.dstu3.model.PlanDefinition; import org.hl7.fhir.dstu3.model.ValueSet; -import org.hl7.fhir.instance.model.api.IBaseResource; import org.opencds.cqf.ruler.behavior.DaoRegistryUser; import org.opencds.cqf.ruler.utility.Searches; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; public class DiscoveryResolutionStu3 implements DaoRegistryUser { @@ -199,13 +197,11 @@ public PrefetchUrlList getPrefetchUrlList(PlanDefinition planDefinition) { } public DiscoveryResponse resolve() { - List planDefinitions = this.daoRegistry.getResourceDao(PlanDefinition.class) - .search(SearchParameterMap.newSynchronous()).getAllResources(); + List planDefinitions = search(PlanDefinition.class, Searches.all()).getAllResourcesTyped(); DiscoveryResponse response = new DiscoveryResponse(); - for (IBaseResource resource : planDefinitions) { - PlanDefinition planDefinition = (PlanDefinition) resource; + for (PlanDefinition resource : planDefinitions) { response.addElement( - new DiscoveryElementStu3(planDefinition, getPrefetchUrlList(planDefinition))); + new DiscoveryElementStu3(resource, getPrefetchUrlList(resource))); } return response; diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java index 1cd997a4f..a5cc5f68f 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/dstu3/CdsHooksServlet.java @@ -23,7 +23,6 @@ import org.apache.http.entity.ContentType; import org.cqframework.cql.elm.execution.VersionedIdentifier; -import org.hl7.fhir.dstu3.model.IdType; import org.hl7.fhir.dstu3.model.Library; import org.hl7.fhir.dstu3.model.PlanDefinition; import org.hl7.fhir.dstu3.model.Reference; @@ -170,8 +169,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) logger.info("cds-hooks local server address: {}", baseUrl); logger.info("cds-hooks fhir server address: {}", hook.getRequest().getFhirServerUrl()); - PlanDefinition planDefinition = planDefinitionProvider.getDao() - .read(new IdType(hook.getRequest().getServiceName())); + PlanDefinition planDefinition = read(PlanDefinition.class, hook.getRequest().getServiceName()); AtomicBoolean planDefinitionHookMatchesRequestHook = new AtomicBoolean(false); planDefinition.getAction().forEach(action -> { diff --git a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java index 2d02205a2..57c794600 100644 --- a/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java +++ b/plugin/cds-hooks/src/main/java/org/opencds/cqf/ruler/cdshooks/r4/CdsHooksServlet.java @@ -24,7 +24,6 @@ import org.apache.http.entity.ContentType; import org.cqframework.cql.elm.execution.VersionedIdentifier; import org.hl7.fhir.r4.model.CanonicalType; -import org.hl7.fhir.r4.model.IdType; import org.hl7.fhir.r4.model.Library; import org.hl7.fhir.r4.model.PlanDefinition; import org.opencds.cqf.cql.engine.debug.DebugMap; @@ -170,8 +169,7 @@ protected void doPost(HttpServletRequest request, HttpServletResponse response) logger.info("cds-hooks local server address: {}", baseUrl); logger.info("cds-hooks fhir server address: {}", hook.getRequest().getFhirServerUrl()); - PlanDefinition planDefinition = planDefinitionProvider.getDao() - .read(new IdType(hook.getRequest().getServiceName())); + PlanDefinition planDefinition = read(PlanDefinition.class, hook.getRequest().getServiceName()); AtomicBoolean planDefinitionHookMatchesRequestHook = new AtomicBoolean(false); planDefinition.getAction().forEach(action -> { diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaFhirRetrieveProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaFhirRetrieveProvider.java index 2de1b9f5c..f30a3d2a9 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaFhirRetrieveProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaFhirRetrieveProvider.java @@ -3,7 +3,6 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -13,86 +12,83 @@ import org.opencds.cqf.cql.engine.fhir.retrieve.SearchParamFhirRetrieveProvider; import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterMap; import org.opencds.cqf.cql.engine.fhir.searchparam.SearchParameterResolver; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; import ca.uhn.fhir.model.api.IQueryParameterType; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.RequestDetails; /** - * This class provides an implementation of the cql-engine's RetrieveProvider interface which is used for loading + * This class provides an implementation of the cql-engine's RetrieveProvider + * interface which is used for loading * data during CQL evaluation. */ -public class JpaFhirRetrieveProvider extends SearchParamFhirRetrieveProvider { +public class JpaFhirRetrieveProvider extends SearchParamFhirRetrieveProvider implements DaoRegistryUser { - private static final Logger logger = LoggerFactory.getLogger(JpaFhirRetrieveProvider.class); + private static final Logger logger = LoggerFactory.getLogger(JpaFhirRetrieveProvider.class); - private final DaoRegistry myDaoRegistry; - private final RequestDetails myRequestDetails; + private final DaoRegistry myDaoRegistry; + private final RequestDetails myRequestDetails; - public JpaFhirRetrieveProvider(DaoRegistry theDaoRegistry, SearchParameterResolver theSearchParameterResolver) { + public JpaFhirRetrieveProvider(DaoRegistry theDaoRegistry, SearchParameterResolver theSearchParameterResolver) { this(theDaoRegistry, theSearchParameterResolver, null); - } - - public JpaFhirRetrieveProvider(DaoRegistry registry, SearchParameterResolver searchParameterResolver, RequestDetails requestDetails) { - super(searchParameterResolver); - this.myDaoRegistry = registry; - this.myRequestDetails = requestDetails; - } - - @Override - protected Iterable executeQueries(String dataType, List queries) { - if (queries == null || queries.isEmpty()) { - return Collections.emptyList(); - } - - List objects = new ArrayList<>(); - for (SearchParameterMap map : queries) { - objects.addAll(executeQuery(dataType, map)); - } - - return objects; - } - - protected Collection executeQuery(String dataType, SearchParameterMap map) { - // TODO: Once HAPI breaks this out from the server dependencies - // we can include it on its own. - ca.uhn.fhir.jpa.searchparam.SearchParameterMap hapiMap = ca.uhn.fhir.jpa.searchparam.SearchParameterMap.newSynchronous(); - try { - - Method[] methods = hapiMap.getClass().getDeclaredMethods(); - List methodList = Arrays.asList(methods); - List puts = methodList.stream().filter(x -> x.getName().equals("put")).collect(Collectors.toList()); - Method method = puts.get(0); - method.setAccessible(true); - - for (Map.Entry>> entry : map.entrySet()) { - method.invoke(hapiMap, entry.getKey(), entry.getValue()); - } - - } catch (Exception e) { - logger.warn("Error converting search parameter map", e); - } - - IFhirResourceDao dao = this.myDaoRegistry.getResourceDao(dataType); - - IBundleProvider bundleProvider = dao.search(hapiMap, myRequestDetails); - if (bundleProvider.size() == null) { - return resolveResourceList(bundleProvider.getAllResources()); - } - if (bundleProvider.size() == 0) { - return new ArrayList<>(); - } - List resourceList = bundleProvider.getAllResources(); - return resolveResourceList(resourceList); - } - - public Collection resolveResourceList(List resourceList) { - List ret = new ArrayList<>(resourceList.size()); - ret.addAll(resourceList); - return ret; - } + } + + public JpaFhirRetrieveProvider(DaoRegistry registry, SearchParameterResolver searchParameterResolver, + RequestDetails requestDetails) { + super(searchParameterResolver); + this.myDaoRegistry = registry; + this.myRequestDetails = requestDetails; + } + + @Override + protected Iterable executeQueries(String dataType, List queries) { + if (queries == null || queries.isEmpty()) { + return Collections.emptyList(); + } + + List objects = new ArrayList<>(); + for (SearchParameterMap map : queries) { + objects.addAll(executeQuery(dataType, map)); + } + + return objects; + } + + protected List executeQuery(String dataType, SearchParameterMap map) { + // TODO: Once HAPI breaks this out from the server dependencies + // we can include it on its own. + ca.uhn.fhir.jpa.searchparam.SearchParameterMap hapiMap = ca.uhn.fhir.jpa.searchparam.SearchParameterMap + .newSynchronous(); + try { + + Method[] methods = hapiMap.getClass().getDeclaredMethods(); + List methodList = Arrays.asList(methods); + List puts = methodList.stream().filter(x -> x.getName().equals("put")).collect(Collectors.toList()); + Method method = puts.get(0); + method.setAccessible(true); + + for (Map.Entry>> entry : map.entrySet()) { + method.invoke(hapiMap, entry.getKey(), entry.getValue()); + } + + } catch (Exception e) { + logger.warn("Error converting search parameter map", e); + } + + IBundleProvider bundleProvider = search(dataType, hapiMap, myRequestDetails); + if (bundleProvider.isEmpty()) { + return new ArrayList<>(); + } + + return bundleProvider.getAllResources(); + } + + @Override + public DaoRegistry getDaoRegistry() { + return this.myDaoRegistry; + } } diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java index 1c3fecd18..e683e149f 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaLibraryContentProvider.java @@ -2,6 +2,7 @@ import java.io.ByteArrayInputStream; import java.io.InputStream; +import java.util.List; import org.hl7.fhir.instance.model.api.IBaseResource; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; @@ -12,7 +13,6 @@ import org.opencds.cqf.ruler.utility.Versions; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.RequestDetails; public class JpaLibraryContentProvider @@ -43,8 +43,10 @@ public InputStream getLibraryContent(org.hl7.elm.r1.VersionedIdentifier libraryI return null; } - IBundleProvider libraries = search("Library", Searches.byName(libraryIdentifier.getId()), requestDetails); - IBaseResource library = Versions.selectByVersion(libraries.getAllResources(), libraryIdentifier.getVersion(), + String name = libraryIdentifier.getId(); + String version = libraryIdentifier.getVersion(); + List libraries = search("Library", Searches.byName(name), requestDetails).getAllResources(); + IBaseResource library = Versions.selectByVersion(libraries, version, Libraries::getVersion); if (library == null) { diff --git a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java index fc86a5475..9929814af 100644 --- a/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java +++ b/plugin/cql/src/main/java/org/opencds/cqf/ruler/cql/JpaTerminologyProvider.java @@ -8,19 +8,18 @@ import org.opencds.cqf.cql.engine.terminology.CodeSystemInfo; import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.engine.terminology.ValueSetInfo; +import org.opencds.cqf.ruler.behavior.DaoRegistryUser; import org.opencds.cqf.ruler.utility.Ids; +import org.opencds.cqf.ruler.utility.Searches; import ca.uhn.fhir.context.support.IValidationSupport; import ca.uhn.fhir.context.support.IValidationSupport.LookupCodeResult; import ca.uhn.fhir.context.support.ValidationSupportContext; import ca.uhn.fhir.context.support.ValueSetExpansionOptions; import ca.uhn.fhir.jpa.api.dao.DaoRegistry; -import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao; -import ca.uhn.fhir.jpa.searchparam.SearchParameterMap; import ca.uhn.fhir.jpa.term.api.ITermReadSvc; import ca.uhn.fhir.rest.api.server.IBundleProvider; import ca.uhn.fhir.rest.api.server.RequestDetails; -import ca.uhn.fhir.rest.param.UriParam; import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException; /** @@ -28,12 +27,11 @@ * interface, which is used for Terminology operations * in CQL */ -public class JpaTerminologyProvider implements TerminologyProvider { +public class JpaTerminologyProvider implements TerminologyProvider, DaoRegistryUser { private final ITermReadSvc myTerminologySvc; private final DaoRegistry myDaoRegistry; private final IValidationSupport myValidationSupport; - private final IFhirResourceDao myValueSetDao; private final RequestDetails myRequestDetails; public JpaTerminologyProvider(ITermReadSvc theTerminologySvc, DaoRegistry theDaoRegistry, @@ -46,10 +44,14 @@ public JpaTerminologyProvider(ITermReadSvc theTerminologySvc, DaoRegistry theDao myTerminologySvc = theTerminologySvc; myDaoRegistry = theDaoRegistry; myValidationSupport = theValidationSupport; - myValueSetDao = myDaoRegistry.getResourceDao("ValueSet"); myRequestDetails = theRequestDetails; } + @Override + public DaoRegistry getDaoRegistry() { + return this.myDaoRegistry; + } + @Override public boolean in(Code code, ValueSetInfo valueSet) throws ResourceNotFoundException { for (Code c : expand(valueSet)) { @@ -62,15 +64,15 @@ public boolean in(Code code, ValueSetInfo valueSet) throws ResourceNotFoundExcep return false; } - protected Boolean hasUrlId(ValueSetInfo valueSet) { + protected boolean hasUrlId(ValueSetInfo valueSet) { return valueSet.getId().startsWith("http://") || valueSet.getId().startsWith("https://"); } - protected Boolean hasVersion(ValueSetInfo valueSet) { + protected boolean hasVersion(ValueSetInfo valueSet) { return valueSet.getVersion() != null; } - protected Boolean hasVersionedCodeSystem(ValueSetInfo valueSet) { + protected boolean hasVersionedCodeSystem(ValueSetInfo valueSet) { return valueSet.getCodeSystems() != null && valueSet.getCodeSystems().size() > 1 || valueSet.getCodeSystems() != null && valueSet.getCodeSystems().stream().anyMatch(x -> x.getVersion() != null); } @@ -87,9 +89,7 @@ public Iterable expand(ValueSetInfo valueSet) throws ResourceNotFoundExcep valueSet.getId())); } - IBundleProvider bundleProvider = myValueSetDao - .search(SearchParameterMap.newSynchronous().add("url", new UriParam(valueSet.getId())), - myRequestDetails); + IBundleProvider bundleProvider = search("ValueSet", Searches.byUrl(valueSet.getId()), myRequestDetails); List valueSets = bundleProvider.getAllResources(); if (valueSets.isEmpty()) { throw new IllegalArgumentException(String.format("Could not resolve value set %s.", valueSet.getId())); @@ -99,7 +99,7 @@ public Iterable expand(ValueSetInfo valueSet) throws ResourceNotFoundExcep throw new IllegalArgumentException("Found more than 1 ValueSet with url: " + valueSet.getId()); } } else { - vs = myValueSetDao.read(Ids.newId(this.myTerminologySvc.getFhirContext(), valueSet.getId()), + vs = read(Ids.newId(this.myTerminologySvc.getFhirContext(), "ValueSet", valueSet.getId()), myRequestDetails); if (vs == null) { throw new IllegalArgumentException(String.format("Could not resolve value set %s.", valueSet.getId())); diff --git a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProvider.java b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProvider.java index 73a0e2950..e0252c592 100644 --- a/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProvider.java +++ b/plugin/cr/src/main/java/org/opencds/cqf/ruler/cr/r4/provider/MeasureEvaluateProvider.java @@ -11,21 +11,20 @@ import org.opencds.cqf.cql.engine.terminology.TerminologyProvider; import org.opencds.cqf.cql.evaluator.cql2elm.content.LibraryContentProvider; import org.opencds.cqf.cql.evaluator.fhir.dal.FhirDal; -import org.opencds.cqf.ruler.api.OperationProvider; import org.opencds.cqf.ruler.cql.JpaDataProviderFactory; import org.opencds.cqf.ruler.cql.JpaFhirDalFactory; import org.opencds.cqf.ruler.cql.JpaLibraryContentProviderFactory; import org.opencds.cqf.ruler.cql.JpaTerminologyProviderFactory; +import org.opencds.cqf.ruler.provider.DaoRegistryOperationProvider; import org.springframework.beans.factory.annotation.Autowired; -import ca.uhn.fhir.jpa.api.dao.DaoRegistry; import ca.uhn.fhir.model.api.annotation.Description; import ca.uhn.fhir.rest.annotation.IdParam; import ca.uhn.fhir.rest.annotation.Operation; import ca.uhn.fhir.rest.annotation.OperationParam; import ca.uhn.fhir.rest.api.server.RequestDetails; -public class MeasureEvaluateProvider implements OperationProvider { +public class MeasureEvaluateProvider extends DaoRegistryOperationProvider { // private static final Logger logger = LoggerFactory.getLogger(MeasureEvaluateProvider.class); @@ -41,9 +40,6 @@ public class MeasureEvaluateProvider implements OperationProvider { @Autowired private JpaFhirDalFactory fhirDalFactory; - @Autowired - private DaoRegistry daoRegistry; - @Autowired private Map globalLibraryCache; @@ -82,7 +78,7 @@ public MeasureReport evaluateMeasure(RequestDetails requestDetails, @IdParam IdT null, null, null, null, null, terminologyProvider, libraryContentProvider, dataProvider, fhirDal, null, this.globalLibraryCache); - Measure measure = this.daoRegistry.getResourceDao(Measure.class).read(theId); + Measure measure = read(theId); MeasureReport report = measureProcessor.evaluateMeasure(measure.getUrl(), periodStart, periodEnd, reportType, subject, null, lastReceivedOn, null, null, null, null); diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java index b85125793..7a1f9c0a9 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/dstu3/CacheValueSetsProviderIT.java @@ -169,10 +169,6 @@ public void testCacheValueSetsAlreadyExpanded() throws Exception { BundleEntryComponent entry = resultBundle.getEntry().get(0); assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); assertEquals("200 OK", entry.getResponse().getStatus()); - // ValueSet resultingValueSet = - // myDaoRegistry.getResourceDao(ValueSet.class).read(vs.getIdElement()); - // resultingValueSet not returning with a version - // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); } private StringAndListParam getStringAndListParamFromValueSet(String location) throws IOException { diff --git a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java index c76eb179c..f5a22a0c0 100644 --- a/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java +++ b/plugin/dev-tools/src/test/java/org/opencds/cqf/ruler/devtools/r4/CacheValueSetsProviderIT.java @@ -151,9 +151,6 @@ public void testCacheValueSetsAlreadyExpanded() throws Exception { BundleEntryComponent entry = resultBundle.getEntry().get(0); assertTrue(entry.getResponse().getLocation().startsWith("ValueSet/" + vs.getIdElement().getIdPart())); assertEquals("200 OK", entry.getResponse().getStatus()); - // ValueSet resultingValueSet = myDaoRegistry.getResourceDao(ValueSet.class).read(vs.getIdElement()); - // resultingValueSet not returning with a version - // assertTrue(resultingValueSet.getVersion().endsWith("-cached")); } private StringAndListParam getStringAndListParamFromValueSet(String location) throws IOException {