Adding example

This commit is contained in:
Chris Schuler 2017-11-16 11:03:13 -07:00
parent efc25e2176
commit 240d5c8051
170 changed files with 1274 additions and 12181 deletions

View File

@ -0,0 +1,286 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<!--
Note: HAPI projects use the "hapi-fhir" POM as their base to provide easy management.
You do not need to use this in your own projects, so the "parent" tag and it's
contents below may be removed
if you are using this file as a basis for your own project.
-->
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>3.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-jpaserver-cds</artifactId>
<packaging>war</packaging>
<name>HAPI FHIR JPA Clinical Decision Support Server - Example</name>
<repositories>
<repository>
<id>oss-snapshots</id>
<snapshots>
<enabled>true</enabled>
</snapshots>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.opencds.cqf</groupId>
<artifactId>cqf-ruler</artifactId>
<version>0.1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-api</artifactId>
<version>${jetty_version}</version>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-client</artifactId>
<version>${jetty_version}</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>6.0.5</version>
</dependency>
<!-- This dependency includes the core HAPI-FHIR classes -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>${project.version}</version>
</dependency>
<!-- At least one "structures" JAR must also be included -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>${project.version}</version>
</dependency>
<!-- This dependency includes the JPA server itself, which is packaged separately from the rest of HAPI FHIR -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>${project.version}</version>
</dependency>
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>${project.version}</version>
<classifier>classes</classifier>
<scope>provided</scope>
</dependency>
<!-- HAPI-FHIR uses Logback for logging support. The logback library is included automatically by Maven as a part of the hapi-fhir-base dependency, but you also need to include a logging library. Logback
is used here, but log4j would also be fine. -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<!-- Needed for JEE/Servlet support -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- If you are using HAPI narrative generation, you will need to include Thymeleaf as well. Otherwise the following can be omitted. -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
</dependency>
<!-- Used for CORS support -->
<dependency>
<groupId>org.ebaysf.web</groupId>
<artifactId>cors-filter</artifactId>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<!-- Spring Web is used to deploy the server to a web container. -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- You may not need this if you are deploying to an application server which provides database connection pools itself. -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
<!-- This example uses Derby embedded database. If you are using another database such as Mysql or Oracle, you may omit the following dependencies and replace them with an appropriate database client
dependency for your database platform. -->
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbynet</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
</dependency>
<!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty.websocket</groupId>
<artifactId>websocket-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-schematron</artifactId>
<exclusions>
<exclusion>
<artifactId>Saxon-HE</artifactId>
<groupId>net.sf.saxon</groupId>
</exclusion>
</exclusions>
</dependency>
<!--
For some reason JavaDoc crashed during site generation unless we have this dependency
-->
<dependency>
<groupId>javax.interceptor</groupId>
<artifactId>javax.interceptor-api</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<!-- Tells Maven to name the generated WAR file as hapi-fhir-jpaserver-example.war -->
<finalName>hapi-fhir-jpaserver-cds</finalName>
<!-- The following is not required for the application to build, but allows you to test it by issuing "mvn jetty:run" from the command line. -->
<pluginManagement>
<plugins>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<webApp>
<contextPath>/hapi-fhir-jpaserver-cds</contextPath>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
</webApp>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins>
<!-- Tell Maven which Java source version you want to use -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- The configuration here tells the WAR plugin to include the FHIR Tester overlay. You can omit it if you are not using that feature. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Build-Time>${maven.build.timestamp}</Build-Time>
</manifestEntries>
</archive>
<overlays>
<overlay>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
</overlay>
</overlays>
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
</configuration>
</plugin>
<!-- This plugin is just a part of the HAPI internal build process, you do not need to incude it in your own projects -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<!-- This is to run the integration tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@ -0,0 +1,16 @@
package ca.uhn.fhir.jpa.cds.example;
import org.opencds.cqf.servlet.CdsServicesServlet;
public class CdsHooksServerExample extends CdsServicesServlet {
// @Override
// protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// // Change how requests are handled
// }
//
// @Override
// protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// // Change discovery response
// }
}

View File

@ -0,0 +1,165 @@
package ca.uhn.fhir.jpa.cds.example;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
import ca.uhn.fhir.jpa.rp.dstu3.ActivityDefinitionResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.MeasureResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.PlanDefinitionResourceProvider;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Meta;
import org.opencds.cqf.providers.FHIRActivityDefinitionResourceProvider;
import org.opencds.cqf.providers.FHIRMeasureResourceProvider;
import org.opencds.cqf.providers.FHIRPlanDefinitionResourceProvider;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletException;
import java.util.Collection;
import java.util.List;
public class CdsServerExample extends RestfulServer {
@SuppressWarnings("unchecked")
@Override
protected void initialize() throws ServletException {
super.initialize();
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU3;
setFhirContext(new FhirContext(fhirVersion));
// Get the spring context from the web container (it's declared in web.xml)
WebApplicationContext myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
if (myAppCtx == null) {
throw new ServletException("Error retrieving spring context from the web container");
}
String resourceProviderBeanName = "myResourceProvidersDstu3";
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
setResourceProviders(beans);
Object systemProvider = myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class);
setPlainProviders(systemProvider);
/*
* The conformance provider exports the supported resources, search parameters, etc for
* this server. The JPA version adds resource counts to the exported statement, so it
* is a nice addition.
*/
IFhirSystemDao<Bundle, Meta> systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
JpaConformanceProviderDstu3 confProvider =
new JpaConformanceProviderDstu3(this, systemDao, myAppCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription("Example Server");
setServerConformanceProvider(confProvider);
/*
* Enable ETag Support (this is already the default)
*/
setETagSupport(ETagSupportEnum.ENABLED);
/*
* This server tries to dynamically generate narratives
*/
FhirContext ctx = getFhirContext();
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
/*
* Default to JSON and pretty printing
*/
setDefaultPrettyPrint(true);
setDefaultResponseEncoding(EncodingEnum.JSON);
/*
* -- New in HAPI FHIR 1.5 --
* This configures the server to page search results to and from
* the database, instead of only paging them to memory. This may mean
* a performance hit when performing searches that return lots of results,
* but makes the server much more scalable.
*/
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
/*
* Load interceptors for the server from Spring (these are defined in FhirServerConfig.java)
*/
Collection<IServerInterceptor> interceptorBeans = myAppCtx.getBeansOfType(IServerInterceptor.class).values();
for (IServerInterceptor interceptor : interceptorBeans) {
this.registerInterceptor(interceptor);
}
/*
* Adding resource providers from the cqf-ruler
*/
// Measure processing
FHIRMeasureResourceProvider measureProvider = new FHIRMeasureResourceProvider(getResourceProviders());
MeasureResourceProvider jpaMeasureProvider = (MeasureResourceProvider) getProvider("Measure");
measureProvider.setDao(jpaMeasureProvider.getDao());
measureProvider.setContext(jpaMeasureProvider.getContext());
// PlanDefinition processing
FHIRPlanDefinitionResourceProvider planDefProvider = new FHIRPlanDefinitionResourceProvider(getResourceProviders());
PlanDefinitionResourceProvider jpaPlanDefProvider =
(PlanDefinitionResourceProvider) getProvider("PlanDefinition");
planDefProvider.setDao(jpaPlanDefProvider.getDao());
planDefProvider.setContext(jpaPlanDefProvider.getContext());
// ActivityDefinition processing
FHIRActivityDefinitionResourceProvider actDefProvider = new FHIRActivityDefinitionResourceProvider(getResourceProviders());
ActivityDefinitionResourceProvider jpaActDefProvider =
(ActivityDefinitionResourceProvider) getProvider("ActivityDefinition");
actDefProvider.setDao(jpaActDefProvider.getDao());
actDefProvider.setContext(jpaActDefProvider.getContext());
try {
unregisterProvider(jpaMeasureProvider);
unregisterProvider(jpaPlanDefProvider);
unregisterProvider(jpaActDefProvider);
} catch (Exception e) {
throw new ServletException("Unable to unregister provider: " + e.getMessage());
}
registerProvider(measureProvider);
registerProvider(planDefProvider);
registerProvider(actDefProvider);
/*
* If you are hosting this server at a specific DNS name, the server will try to
* figure out the FHIR base URL based on what the web container tells it, but
* this doesn't always work. If you are setting links in your search bundles that
* just refer to "localhost", you might want to use a server address strategy:
*/
//setServerAddressStrategy(new HardcodedServerAddressStrategy("http://mydomain.com/fhir/baseDstu2"));
/*
* If you are using DSTU3+, you may want to add a terminology uploader, which allows
* uploading of external terminologies such as Snomed CT. Note that this uploader
* does not have any security attached (any anonymous user may use it by default)
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
* with this feature.
*/
registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
}
public IResourceProvider getProvider(String name) {
for (IResourceProvider res : getResourceProviders()) {
if (res.getResourceType().getSimpleName().equals(name)) {
return res;
}
}
throw new IllegalArgumentException("This should never happen!");
}
}

View File

@ -0,0 +1,125 @@
package ca.uhn.fhir.jpa.cds.example;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
/**
* This is the primary configuration file for the example server
*/
@Configuration
@EnableTransactionManagement()
public class FhirServerConfig extends BaseJavaConfigDstu3 {
/**
* Configure FHIR properties around the the JPA server via this bean
*/
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
return retVal;
}
/**
* The following bean configures the database connection. The 'url' property value of "jdbc:derby:directory:jpaserver_derby_files;create=true" indicates that the server should save resources in a
* directory called "jpaserver_derby_files".
*
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
*/
@Bean(destroyMethod = "close")
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
retVal.setUrl("jdbc:derby:directory:target/jpaserver_derby_files;create=true");
retVal.setUsername("");
retVal.setPassword("");
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.jdbc.batch_size", "20");
extraProperties.put("hibernate.cache.use_query_cache", "false");
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
extraProperties.put("hibernate.cache.use_structured_entries", "false");
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
extraProperties.put("hibernate.search.model_mapping", LuceneSearchMappingFactory.class.getName());
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
// extraProperties.put("hibernate.search.default.worker.execution", "async");
return extraProperties;
}
/**
* Do some fancy logging to create a nice access log that has details about each incoming request.
*/
public IServerInterceptor loggingInterceptor() {
LoggingInterceptor retVal = new LoggingInterceptor();
retVal.setLoggerName("fhirtest.access");
retVal.setMessageFormat(
"Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]");
retVal.setLogExceptions(true);
retVal.setErrorMessageFormat("ERROR - ${requestVerb} ${requestUrl}");
return retVal;
}
/**
* This interceptor adds some pretty syntax highlighting in responses when a browser is detected
*/
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor responseHighlighterInterceptor() {
ResponseHighlighterInterceptor retVal = new ResponseHighlighterInterceptor();
return retVal;
}
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
SubscriptionsRequireManualActivationInterceptorDstu3 retVal = new SubscriptionsRequireManualActivationInterceptorDstu3();
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
}

View File

@ -0,0 +1,56 @@
package ca.uhn.fhir.jpa.cds.example;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.to.FhirTesterMvcConfig;
import ca.uhn.fhir.to.TesterConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
//@formatter:off
/**
* This spring config file configures the web testing module. It serves two
* purposes:
* 1. It imports FhirTesterMvcConfig, which is the spring config for the
* tester itself
* 2. It tells the tester which server(s) to talk to, via the testerConfig()
* method below
*/
@Configuration
@Import(FhirTesterMvcConfig.class)
public class FhirTesterConfig {
/**
* This bean tells the testing webpage which servers it should configure itself
* to communicate with. In this example we configure it to talk to the local
* server, as well as one public server. If you are creating a project to
* deploy somewhere else, you might choose to only put your own server's
* address here.
*
* Note the use of the ${serverBase} variable below. This will be replaced with
* the base URL as reported by the server itself. Often for a simple Tomcat
* (or other container) installation, this will end up being something
* like "http://localhost:8080/hapi-fhir-jpaserver-example". If you are
* deploying your server to a place with a fully qualified domain name,
* you might want to use that instead of using the variable.
*/
@Bean
public TesterConfig testerConfig() {
TesterConfig retVal = new TesterConfig();
retVal
.addServer()
.withId("home")
.withFhirVersion(FhirVersionEnum.DSTU3)
.withBaseUrl("${serverBase}/baseDstu3")
.withName("Local Tester")
.addServer()
.withId("hapi")
.withFhirVersion(FhirVersionEnum.DSTU3)
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu3")
.withName("Public HAPI Test Server");
return retVal;
}
}
//@formatter:on

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <html lang="en">
<head th:include="tmpl-head :: head"> <head th:include="tmpl-head :: head">
<title>About This Server</title> <title>About This Server</title>
</head> </head>

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <html lang="en">
<div th:fragment="footer"> <div th:fragment="footer">
<script> <script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){ (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){

View File

@ -1,5 +1,5 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en" xmlns:th="http://www.w3.org/1999/xhtml"> <html lang="en">
<div th:fragment="banner" class="well"> <div th:fragment="banner" class="well">
<th:block th:if="${serverId} == 'home'"> <th:block th:if="${serverId} == 'home'">
<p> <p>

View File

@ -1,5 +1,5 @@
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" <web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd" metadata-complete="true"> xsi:schemaLocation="http://java.sun.com/xml/ns/javaee ./xsd/web-app_3_0.xsd">
<listener> <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
@ -13,7 +13,7 @@
<context-param> <context-param>
<param-name>contextConfigLocation</param-name> <param-name>contextConfigLocation</param-name>
<param-value> <param-value>
ca.uhn.fhir.jpa.cqf.ruler.config.FhirServerConfigDstu3 ca.uhn.fhir.jpa.cds.example.FhirServerConfig
</param-value> </param-value>
</context-param> </context-param>
@ -21,7 +21,7 @@
<servlet> <servlet>
<servlet-name>cdsServicesServlet</servlet-name> <servlet-name>cdsServicesServlet</servlet-name>
<servlet-class>ca.uhn.fhir.jpa.cqf.ruler.servlet.CdsServicesServlet</servlet-class> <servlet-class>ca.uhn.fhir.jpa.cds.example.CdsHooksServerExample</servlet-class>
<load-on-startup>3</load-on-startup> <load-on-startup>3</load-on-startup>
</servlet> </servlet>
@ -34,18 +34,17 @@
</init-param> </init-param>
<init-param> <init-param>
<param-name>contextConfigLocation</param-name> <param-name>contextConfigLocation</param-name>
<param-value>ca.uhn.fhir.jpa.cqf.ruler.config.FhirTesterConfigDstu3</param-value> <param-value>ca.uhn.fhir.jpa.cds.example.FhirTesterConfig</param-value>
</init-param> </init-param>
<load-on-startup>2</load-on-startup> <load-on-startup>2</load-on-startup>
</servlet> </servlet>
<servlet> <servlet>
<servlet-name>baseServlet</servlet-name> <servlet-name>fhirServlet</servlet-name>
<servlet-class>ca.uhn.fhir.jpa.cqf.ruler.servlet.BaseServlet</servlet-class> <servlet-class>ca.uhn.fhir.jpa.cds.example.CdsServerExample</servlet-class>
<init-param> <init-param>
<param-name>ImplementationDescription</param-name> <param-name>ImplementationDescription</param-name>
<param-value>FHIR CQF Ruler-of-All-Knowledge JPA Server</param-value> <param-value>FHIR JPA Server</param-value>
</init-param> </init-param>
<init-param> <init-param>
<param-name>FhirVersion</param-name> <param-name>FhirVersion</param-name>
@ -54,16 +53,6 @@
<load-on-startup>1</load-on-startup> <load-on-startup>1</load-on-startup>
</servlet> </servlet>
<servlet-mapping>
<servlet-name>baseServlet</servlet-name>
<url-pattern>/baseDstu3/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/tester/*</url-pattern>
</servlet-mapping>
<servlet-mapping> <servlet-mapping>
<servlet-name>cdsServicesServlet</servlet-name> <servlet-name>cdsServicesServlet</servlet-name>
<url-pattern>/cds-services</url-pattern> <url-pattern>/cds-services</url-pattern>
@ -74,6 +63,18 @@
<url-pattern>/cds-services/*</url-pattern> <url-pattern>/cds-services/*</url-pattern>
</servlet-mapping> </servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServlet</servlet-name>
<url-pattern>/baseDstu3/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>spring</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
<!-- This filters provide support for Cross Origin Resource Sharing (CORS) --> <!-- This filters provide support for Cross Origin Resource Sharing (CORS) -->
<filter> <filter>
<filter-name>CORS Filter</filter-name> <filter-name>CORS Filter</filter-name>
@ -81,7 +82,7 @@
<init-param> <init-param>
<description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description> <description>A comma separated list of allowed origins. Note: An '*' cannot be used for an allowed origin when using credentials.</description>
<param-name>cors.allowed.origins</param-name> <param-name>cors.allowed.origins</param-name>
<param-value>http://sandbox.cds-hooks.org, *</param-value> <param-value>*</param-value>
</init-param> </init-param>
<init-param> <init-param>
<description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description> <description>A comma separated list of HTTP verbs, using which a CORS request can be made.</description>
@ -91,7 +92,7 @@
<init-param> <init-param>
<description>A comma separated list of allowed headers when making a non simple CORS request.</description> <description>A comma separated list of allowed headers when making a non simple CORS request.</description>
<param-name>cors.allowed.headers</param-name> <param-name>cors.allowed.headers</param-name>
<param-value>X-FHIR-Starter,Origin,Accept,Authorization,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers</param-value> <param-value>X-FHIR-Starter,Origin,Accept,X-Requested-With,Content-Type,Access-Control-Request-Method,Access-Control-Request-Headers,Prefer</param-value>
</init-param> </init-param>
<init-param> <init-param>
<description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description> <description>A comma separated list non-standard response headers that will be exposed to XHR2 object.</description>
@ -119,4 +120,5 @@
<url-pattern>/*</url-pattern> <url-pattern>/*</url-pattern>
</filter-mapping> </filter-mapping>
</web-app> </web-app>

View File

@ -0,0 +1,260 @@
package ca.uhn.fhir.jpa.cds.example;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.primitive.IdDt;
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 ca.uhn.fhir.rest.server.IResourceProvider;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Test;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.ServerSocket;
import java.net.URL;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Scanner;
public class CdsExampleTests {
private static IGenericClient ourClient;
private static FhirContext ourCtx = FhirContext.forDstu3();
protected static int ourPort;
private static Server ourServer;
private static String ourServerBase;
private static Collection<IResourceProvider> providers;
@BeforeClass
public static void beforeClass() throws Exception {
String path = Paths.get("").toAbsolutePath().toString();
ourPort = RandomServerPortProvider.findFreePort();
ourServer = new Server(ourPort);
WebAppContext webAppContext = new WebAppContext();
webAppContext.setContextPath("/hapi-fhir-jpaserver-cds");
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-cds");
webAppContext.setParentLoaderPriority(true);
ourServer.setHandler(webAppContext);
ourServer.start();
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver-cds/baseDstu3";
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
ourClient.registerInterceptor(new LoggingInterceptor(true));
// Load test data
// Normally, I would use a transaction bundle, but issues with the random ports prevents that...
// So, doing it the old-fashioned way =)
// General
putResource("general-practitioner.json", "Practitioner-12208");
putResource("general-patient.json", "Patient-12214");
putResource("general-fhirhelpers-3.json", "FHIRHelpers");
}
@AfterClass
public static void afterClass() throws Exception {
ourServer.stop();
}
private static void putResource(String resourceFileName, String id) {
InputStream is = CdsExampleTests.class.getResourceAsStream(resourceFileName);
Scanner scanner = new Scanner(is).useDelimiter("\\A");
String json = scanner.hasNext() ? scanner.next() : "";
IBaseResource resource = ourCtx.newJsonParser().parseResource(json);
ourClient.update(id, resource);
}
@Test
public void MeasureProcessingTest() {
putResource("measure-processing-library.json", "col-logic");
putResource("measure-processing-measure.json", "col");
putResource("measure-processing-procedure.json", "Procedure-9");
putResource("measure-processing-condition.json", "Condition-13");
putResource("measure-processing-valueset-1.json", "2.16.840.1.113883.3.464.1003.108.11.1001");
putResource("measure-processing-valueset-2.json", "2.16.840.1.113883.3.464.1003.198.12.1019");
putResource("measure-processing-valueset-3.json", "2.16.840.1.113883.3.464.1003.108.12.1020");
putResource("measure-processing-valueset-4.json", "2.16.840.1.113883.3.464.1003.198.12.1010");
putResource("measure-processing-valueset-5.json", "2.16.840.1.113883.3.464.1003.198.12.1011");
Parameters inParams = new Parameters();
inParams.addParameter().setName("patient").setValue(new StringType("Patient-12214"));
inParams.addParameter().setName("startPeriod").setValue(new DateType("2001-01-01"));
inParams.addParameter().setName("endPeriod").setValue(new DateType("2015-03-01"));
Parameters outParams = ourClient
.operation()
.onInstance(new IdDt("Measure", "col"))
.named("$evaluate")
.withParameters(inParams)
.useHttpGet()
.execute();
List<Parameters.ParametersParameterComponent> response = outParams.getParameter();
Assert.assertTrue(!response.isEmpty());
Parameters.ParametersParameterComponent component = response.get(0);
Assert.assertTrue(component.getResource() instanceof MeasureReport);
MeasureReport report = (MeasureReport) component.getResource();
Assert.assertTrue(report.getEvaluatedResources() != null);
for (MeasureReport.MeasureReportGroupComponent group : report.getGroup()) {
if (group.getIdentifier().getValue().equals("history-of-colorectal-cancer")) {
Assert.assertTrue(group.getPopulation().get(0).getCount() > 0);
}
if (group.getIdentifier().getValue().equals("history-of-total-colectomy")) {
Assert.assertTrue(group.getPopulation().get(0).getCount() > 0);
}
}
}
@Test
public void PlanDefinitionApplyTest() throws ClassNotFoundException {
putResource("plandefinition-apply-library.json", "plandefinitionApplyTest");
putResource("plandefinition-apply.json", "apply-example");
Parameters inParams = new Parameters();
inParams.addParameter().setName("patient").setValue(new StringType("Patient-12214"));
Parameters outParams = ourClient
.operation()
.onInstance(new IdDt("PlanDefinition", "apply-example"))
.named("$apply")
.withParameters(inParams)
.useHttpGet()
.execute();
List<Parameters.ParametersParameterComponent> response = outParams.getParameter();
Assert.assertTrue(!response.isEmpty());
Resource resource = response.get(0).getResource();
Assert.assertTrue(resource instanceof CarePlan);
CarePlan carePlan = (CarePlan) resource;
Assert.assertTrue(carePlan.getTitle().equals("This is a dynamic definition!"));
}
@Test
public void ActivityDefinitionApplyTest() {
putResource("activitydefinition-apply-library.json", "activityDefinitionApplyTest");
putResource("activitydefinition-apply.json", "ad-apply-example");
Parameters inParams = new Parameters();
inParams.addParameter().setName("patient").setValue(new StringType("Patient-12214"));
Parameters outParams = ourClient
.operation()
.onInstance(new IdDt("ActivityDefinition", "ad-apply-example"))
.named("$apply")
.withParameters(inParams)
.useHttpGet()
.execute();
List<Parameters.ParametersParameterComponent> response = outParams.getParameter();
Assert.assertTrue(!response.isEmpty());
Resource resource = response.get(0).getResource();
Assert.assertTrue(resource instanceof ProcedureRequest);
ProcedureRequest procedureRequest = (ProcedureRequest) resource;
Assert.assertTrue(procedureRequest.getDoNotPerform());
}
//@Test
public void CdsHooksPatientViewTest() throws IOException {
putResource("cds-bcs-library.json", "patient-view");
putResource("cds-bcs-patient.json", "Patient-6532");
putResource("cds-bcs-plandefinition.json", "bcs-decision-support");
putResource("cds-bcs-activitydefinition.json", "mammogram-service-request");
// Get the CDS Hooks request
InputStream is = this.getClass().getResourceAsStream("cds-bcs-request.json");
Scanner scanner = new Scanner(is).useDelimiter("\\A");
String cdsHooksRequest = scanner.hasNext() ? scanner.next() : "";
byte[] data = cdsHooksRequest.getBytes("UTF-8");
URL url = new URL("http://localhost:" + ourPort + "/hapi-fhir-jpaserver-cds/cds-services/bcs-decision-support");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Content-Type", "application/json");
conn.setRequestProperty("Content-Length", String.valueOf(data.length));
conn.setDoOutput(true);
conn.getOutputStream().write(data);
StringBuilder response = new StringBuilder();
try(Reader in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8")))
{
for (int i; (i = in.read()) >= 0;) {
response.append((char) i);
}
}
String expected = "{\n" +
" \"cards\": [\n" +
" {\n" +
" \"summary\": \"High risk for opioid overdose - taper now\",\n" +
" \"indicator\": \"warning\",\n" +
" \"detail\": \"Total morphine milligram equivalent (MME) is 20200.700mg/d. Taper to less than 50.\"\n" +
" }\n" +
" ]\n" +
"}";
Assert.assertTrue(
response.toString().replaceAll("\\s+", "")
.equals(expected.replaceAll("\\s+", ""))
);
}
}
class RandomServerPortProvider {
private static List<Integer> ourPorts = new ArrayList<>();
static int findFreePort() {
ServerSocket server;
try {
server = new ServerSocket(0);
int port = server.getLocalPort();
ourPorts.add(port);
server.close();
Thread.sleep(500);
return port;
} catch (IOException | InterruptedException e) {
throw new Error(e);
}
}
public static List<Integer> list() {
return ourPorts;
}
}

View File

@ -0,0 +1,37 @@
{
"resourceType": "ActivityDefinition",
"id": "mammogram-service-request",
"text": {
"status": "generated",
"div": "<div xmlns=\"http://www.w3.org/1999/xhtml\">Create ServiceRequest for Mammogrm Procedure</div>"
},
"status": "draft",
"description": "Create ServiceRequest for Mammogram Procedure",
"kind": "ProcedureRequest",
"code": {
"coding": [
{
"system": "http://www.ama-assn.org/go/cpt",
"code": "77056",
"display": "Mammography; bilateral"
}
]
},
"timingTiming": {
"_event": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/cqif-basic-cqlExpression",
"valueString": "Now()"
}
]
}
]
},
"participant": [
{
"type": "practitioner"
}
]
}

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,96 @@
{
"resourceType": "Patient",
"id": "Patient-6532",
"extension": [
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-race",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/v3/Race",
"code": "2106-3",
"display": "White"
}
]
}
},
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-ethnicity",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/v3/Ethnicity",
"code": "2186-5",
"display": "Not Hispanic or Latino"
}
]
}
},
{
"url": "http://hl7.org/fhir/us/core/StructureDefinition/us-core-religion",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/v3/ReligiousAffiliation",
"code": "1041",
"display": "Roman Catholic Church"
}
]
}
}
],
"identifier": [
{
"use": "official",
"type": {
"coding": [
{
"system": "http://hl7.org/fhir/identifier-type",
"code": "SB",
"display": "Social Beneficiary Identifier"
}
],
"text": "US Social Security Number"
},
"system": "http://hl7.org/fhir/sid/us-ssn",
"value": "000006532"
}
],
"active": true,
"name": [
{
"family": "Brandt",
"given": [
"Edith",
"Elaine"
]
}
],
"telecom": [
{
"system": "phone",
"value": "616-555-1082",
"use": "home"
},
{
"system": "phone",
"value": "616-555-1211",
"use": "mobile"
}
],
"gender": "female",
"birthDate": "1987-07-16",
"address": [
{
"use": "home",
"type": "postal",
"line": [
"893 N Elm Drive"
],
"city": "Grand Rapids",
"district": "Kent County",
"state": "MI",
"postalCode": "49504"
}
]
}

View File

@ -0,0 +1,33 @@
{
"resourceType": "PlanDefinition",
"id": "bcs-decision-support",
"status": "draft",
"library": {
"reference": "Library/patient-view"
},
"action": [
{
"condition": [
{
"kind": "applicability",
"language": "text/cql",
"expression": "Does Patient Qualify?"
}
],
"action": [
{
"condition": [
{
"kind": "applicability",
"language": "text/cql",
"expression": "Needs Mammogram"
}
],
"definition": {
"reference": "ActivityDefinition/mammogram-service-request"
}
}
]
}
]
}

View File

@ -0,0 +1,9 @@
{
"hookInstance": "d1577c69-dfbe-44ad-ba6d-3e05e953b2ea",
"fhirServer": "https://sb-fhir-dstu2.smarthealthit.org/smartdstu2/open",
"hook": "patient-view",
"user": "Practitioner/example",
"context": [],
"patient": "Patient/Patient-6535",
"prefetch": {}
}

View File

@ -1,137 +0,0 @@
# Created by https://www.gitignore.io
.DS_Store
# RxNorm data
src/main/resources/cds/OpioidManagementTerminologyKnowledge.db
# log files
*.log
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### Vim ###
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.loadpath
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
*.data
*.lck
*.properties
*.script
/*.tmp
*.txt

View File

@ -1,31 +0,0 @@
# cqf-ruler
The CQF Ruler is an implementation of FHIR's [Clinical Reasoning Module](
http://hl7.org/fhir/clinicalreasoning-module.html) and serves as a
knowledge artifact repository and clinical decision support service.
## Usage
- `$ mvn install`
- `$ mvn -Djetty.http.port=XXXX jetty:run`
Visit the [wiki](https://github.com/DBCG/cqf-ruler/wiki) for more documentation.
## Dependencies
Before the instructions in the above "Usage" section will work, you need to
install several primary dependencies.
### Java
Go to [http://www.oracle.com/technetwork/java/javase/downloads/](
http://www.oracle.com/technetwork/java/javase/downloads/) and download the
latest (version 8 or higher) JDK for your platform, and install it.
### Apache Maven
Go to [https://maven.apache.org](https://maven.apache.org), visit the main
"Download" page, and under "Files" download a binary archive of your
choice. Then unpack that archive file and follow the installation
instructions in its README.txt. The end result of this should be that the
binary "mvn" is now in your path.

View File

@ -1,357 +0,0 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId>
<version>3.1.0-SNAPSHOT</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>cqf-ruler</artifactId>
<packaging>war</packaging>
<name>CQF Ruler</name>
<repositories>
<repository>
<id>oss-sonatype</id>
<url>https://oss.sonatype.org/content/repositories/snapshots</url>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
<repository>
<id>oss-sonatype-public</id>
<url>https://oss.sonatype.org/content/groups/public/</url>
</repository>
</repositories>
<dependencies>
<dependency>
<groupId>org.opencds.cqf</groupId>
<artifactId>cql-engine</artifactId>
<version>1.2.36-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.opencds.cqf</groupId>
<artifactId>cql-engine-fhir</artifactId>
<version>1.2.36-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>info.cqframework</groupId>
<artifactId>cql-to-elm</artifactId>
<version>1.2.16</version>
</dependency>
<dependency>
<groupId>org.xerial</groupId>
<artifactId>sqlite-jdbc</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<!-- This dependency includes the core HAPI-FHIR classes -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>${project.version}</version>
</dependency>
<!-- At least one "structures" JAR must also be included -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu3</artifactId>
<version>${project.version}</version>
</dependency>
<!-- This dependency includes the JPA server itself, which is packaged separately from the rest of HAPI FHIR -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>${project.version}</version>
</dependency>
<!-- This dependency is used for the "FHIR Tester" web app overlay -->
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>${project.version}</version>
<type>war</type>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
<version>${project.version}</version>
<classifier>classes</classifier>
<scope>provided</scope>
</dependency>
<!-- HAPI-FHIR uses Logback for logging support. The logback library is included automatically by Maven as a part of the hapi-fhir-base dependency, but you also need to include a logging library. Logback
is used here, but log4j would also be fine. -->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>jcl-over-slf4j</artifactId>
<version>1.7.22</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.15</version>
</dependency>
<!-- Needed for JEE/Servlet support -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- If you are using HAPI narrative generation, you will need to include Thymeleaf as well. Otherwise the following can be omitted. -->
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
</dependency>
<!-- Spring Web is used to deploy the server to a web container. -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<!-- You may not need this if you are deploying to an application server which provides database connection pools itself. -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>9.4.1212.jre7</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbynet</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
</dependency>
<!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. -->
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-schematron</artifactId>
</dependency>
<dependency>
<groupId>org.ebaysf.web</groupId>
<artifactId>cors-filter</artifactId>
<exclusions>
<exclusion>
<artifactId>servlet-api</artifactId>
<groupId>javax.servlet</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<!-- Tells Maven to name the generated WAR file as cql-measure-processor.war -->
<finalName>cqf-ruler</finalName>
<plugins>
<!-- Tell Maven which Java source version you want to use -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<configuration>
<webApp>
<contextPath>/cqf-ruler</contextPath>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
</webApp>
</configuration>
</plugin>
<!-- The configuration here tells the WAR plugin to include the FHIR Tester overlay. You can omit it if you are not using that feature. -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Build-Time>${maven.build.timestamp}</Build-Time>
</manifestEntries>
</archive>
<overlays>
<overlay>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-testpage-overlay</artifactId>
</overlay>
</overlays>
</configuration>
</plugin>
<!-- This plugin is just a part of the HAPI internal build process, you do not need to incude it in your own projects -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
<!-- This is to run the integration tests -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<configuration>
<redirectTestOutputToFile>true</redirectTestOutputToFile>
</configuration>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
<goal>verify</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
<dependencies>
<dependency>
<groupId>org.apache.maven.surefire</groupId>
<artifactId>surefire-junit47</artifactId>
<version>2.20.1</version>
</dependency>
</dependencies>
</plugin>
<!--<plugin>-->
<!--<groupId>org.apache.tomcat.maven</groupId>-->
<!--<artifactId>tomcat7-maven-plugin</artifactId>-->
<!--<configuration>-->
<!--<path>/</path>-->
<!--</configuration>-->
<!--</plugin>-->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>exec</goal>
</goals>
</execution>
</executions>
<configuration>
<executable>maven</executable>
<mainClass>ca.uhn.fhir.jpa.cqf.ruler.helpers.XlsxToValueSet</mainClass>
<arguments>
<argument>-b</argument>
<argument>-o</argument>
<argument>-s</argument>
<argument>-v</argument>
<argument>-c</argument>
<argument>-d</argument>
<argument>-u</argument>
<argument>-outDir</argument>
</arguments>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@ -1,30 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.Annotation;
import org.hl7.fhir.dstu3.model.Type;
import java.util.Date;
public class AnnotationBuilder extends BaseBuilder<Annotation> {
public AnnotationBuilder() {
super(new Annotation());
}
// Type is one of the following: Reference or String
public AnnotationBuilder buildAuthor(Type choice) {
complexProperty.setAuthor(choice);
return this;
}
public AnnotationBuilder buildTime(Date date) {
complexProperty.setTime(date);
return this;
}
// required
public AnnotationBuilder buildText(String text) {
complexProperty.setText(text);
return this;
}
}

View File

@ -1,21 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
/*
These builders are based off of work performed by Philips Healthcare.
I simplified their work with this generic base class and added/expanded builders.
Tip of the hat to Philips Healthcare developer nly98977
*/
public class BaseBuilder<T> {
protected T complexProperty;
public BaseBuilder(T complexProperty) {
this.complexProperty = complexProperty;
}
public T build() {
return complexProperty;
}
}

View File

@ -1,68 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.Annotation;
import org.hl7.fhir.dstu3.model.CarePlan;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Reference;
import java.util.ArrayList;
import java.util.List;
public class CarePlanActivityBuilder extends BaseBuilder<CarePlan.CarePlanActivityComponent> {
public CarePlanActivityBuilder() {
super(new CarePlan.CarePlanActivityComponent());
}
public CarePlanActivityBuilder buildOutcomeConcept(List<CodeableConcept> concepts) {
complexProperty.setOutcomeCodeableConcept(concepts);
return this;
}
public CarePlanActivityBuilder buildOutcomeConcept(CodeableConcept concept) {
if (!complexProperty.hasOutcomeCodeableConcept()) {
complexProperty.setOutcomeCodeableConcept(new ArrayList<>());
}
complexProperty.addOutcomeCodeableConcept(concept);
return this;
}
public CarePlanActivityBuilder buildOutcomeReference(List<Reference> references) {
complexProperty.setOutcomeReference(references);
return this;
}
public CarePlanActivityBuilder buildOutcomeReference(Reference reference) {
if (!complexProperty.hasOutcomeReference()) {
complexProperty.setOutcomeReference(new ArrayList<>());
}
complexProperty.addOutcomeReference(reference);
return this;
}
public CarePlanActivityBuilder buildProgress(List<Annotation> annotations) {
complexProperty.setProgress(annotations);
return this;
}
public CarePlanActivityBuilder buildProgress(Annotation annotation) {
if (!complexProperty.hasProgress()) {
complexProperty.setProgress(new ArrayList<>());
}
complexProperty.addProgress(annotation);
return this;
}
public CarePlanActivityBuilder buildReference(Reference reference) {
complexProperty.setReference(reference);
return this;
}
public CarePlanActivityBuilder buildDetail(CarePlan.CarePlanActivityDetailComponent detail) {
complexProperty.setDetail(detail);
return this;
}
}

View File

@ -1,139 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import java.util.ArrayList;
import java.util.List;
public class CarePlanActivityDetailBuilder extends BaseBuilder<CarePlan.CarePlanActivityDetailComponent> {
public CarePlanActivityDetailBuilder() {
super(new CarePlan.CarePlanActivityDetailComponent());
}
public CarePlanActivityDetailBuilder buildCategory(CodeableConcept category) {
complexProperty.setCategory(category);
return this;
}
public CarePlanActivityDetailBuilder buildDefinition(Reference reference) {
complexProperty.setDefinition(reference);
return this;
}
public CarePlanActivityDetailBuilder buildCode(CodeableConcept code) {
complexProperty.setCode(code);
return this;
}
public CarePlanActivityDetailBuilder buildReasonCode(List<CodeableConcept> concepts) {
complexProperty.setReasonCode(concepts);
return this;
}
public CarePlanActivityDetailBuilder buildReasonCode(CodeableConcept concept) {
if (!complexProperty.hasReasonCode()) {
complexProperty.setReasonCode(new ArrayList<>());
}
complexProperty.addReasonCode(concept);
return this;
}
public CarePlanActivityDetailBuilder buildReasonReference(List<Reference> references) {
complexProperty.setReasonReference(references);
return this;
}
public CarePlanActivityDetailBuilder buildReasonReference(Reference reference) {
if (!complexProperty.hasReasonReference()) {
complexProperty.setReasonReference(new ArrayList<>());
}
complexProperty.addReasonReference(reference);
return this;
}
public CarePlanActivityDetailBuilder buildGoal(List<Reference> goals) {
complexProperty.setGoal(goals);
return this;
}
public CarePlanActivityDetailBuilder buildGoal(Reference goal) {
if (!complexProperty.hasGoal()) {
complexProperty.setGoal(new ArrayList<>());
}
complexProperty.addGoal(goal);
return this;
}
// required
public CarePlanActivityDetailBuilder buildStatus(CarePlan.CarePlanActivityStatus status) {
complexProperty.setStatus(status);
return this;
}
// String overload
public CarePlanActivityDetailBuilder buildStatus(String status) throws FHIRException {
complexProperty.setStatus(CarePlan.CarePlanActivityStatus.fromCode(status));
return this;
}
public CarePlanActivityDetailBuilder buildStatusReason(String reason) {
complexProperty.setStatusReason(reason);
return this;
}
public CarePlanActivityDetailBuilder buildProhibited(boolean prohibited) {
complexProperty.setProhibited(prohibited);
return this;
}
// Type is one of the following: Timing, Period, or String
public CarePlanActivityDetailBuilder buildScheduled(Type type) {
complexProperty.setScheduled(type);
return this;
}
public CarePlanActivityDetailBuilder buildLocation(Reference location) {
complexProperty.setLocation(location);
return this;
}
public CarePlanActivityDetailBuilder buildPerformer(List<Reference> performers) {
complexProperty.setPerformer(performers);
return this;
}
public CarePlanActivityDetailBuilder buildPerformer(Reference performer) {
if (!complexProperty.hasPerformer()) {
complexProperty.setPerformer(new ArrayList<>());
}
complexProperty.addPerformer(performer);
return this;
}
// Type is one of the following: CodeableConcept or Reference
public CarePlanActivityDetailBuilder buildProduct(Type type) {
complexProperty.setProduct(type);
return this;
}
public CarePlanActivityDetailBuilder buildDailyAmount(SimpleQuantity amount) {
complexProperty.setDailyAmount(amount);
return this;
}
public CarePlanActivityDetailBuilder buildQuantity(SimpleQuantity quantity) {
complexProperty.setQuantity(quantity);
return this;
}
public CarePlanActivityDetailBuilder buildDescription(String description) {
complexProperty.setDescription(description);
return this;
}
}

View File

@ -1,252 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class CarePlanBuilder extends BaseBuilder<CarePlan> {
public CarePlanBuilder() {
super(new CarePlan());
}
public CarePlanBuilder buildIdentifier(List<Identifier> identifiers) {
complexProperty.setIdentifier(identifiers);
return this;
}
public CarePlanBuilder buildIdentifier(Identifier identifier) {
if (!complexProperty.hasIdentifier()) {
complexProperty.setIdentifier(new ArrayList<>());
}
complexProperty.addIdentifier(identifier);
return this;
}
public CarePlanBuilder buildDefinition(List<Reference> references) {
complexProperty.setDefinition(references);
return this;
}
public CarePlanBuilder buildDefinition(Reference reference) {
if (!complexProperty.hasDefinition()) {
complexProperty.setDefinition(new ArrayList<>());
}
complexProperty.addDefinition(reference);
return this;
}
public CarePlanBuilder buildBasedOn(List<Reference> references) {
complexProperty.setBasedOn(references);
return this;
}
public CarePlanBuilder buildBasedOn(Reference reference) {
if (!complexProperty.hasBasedOn()) {
complexProperty.setBasedOn(new ArrayList<>());
}
complexProperty.addBasedOn(reference);
return this;
}
public CarePlanBuilder buildReplaces(List<Reference> references) {
complexProperty.setReplaces(references);
return this;
}
public CarePlanBuilder buildReplaces(Reference reference) {
if (!complexProperty.hasReplaces()) {
complexProperty.setReplaces(new ArrayList<>());
}
complexProperty.addReplaces(reference);
return this;
}
public CarePlanBuilder buildPartOf(List<Reference> references) {
complexProperty.setPartOf(references);
return this;
}
public CarePlanBuilder buildPartOf(Reference reference) {
if (!complexProperty.hasPartOf()) {
complexProperty.setPartOf(new ArrayList<>());
}
complexProperty.addPartOf(reference);
return this;
}
// required
public CarePlanBuilder buildStatus(CarePlan.CarePlanStatus status) {
complexProperty.setStatus(status);
return this;
}
// String overload
public CarePlanBuilder buildStatus(String status) throws FHIRException {
complexProperty.setStatus(CarePlan.CarePlanStatus.fromCode(status));
return this;
}
// required
public CarePlanBuilder buildIntent(CarePlan.CarePlanIntent intent) {
complexProperty.setIntent(intent);
return this;
}
// String overload
public CarePlanBuilder buildIntent(String intent) throws FHIRException {
complexProperty.setIntent(CarePlan.CarePlanIntent.fromCode(intent));
return this;
}
public CarePlanBuilder buildCategory(List<CodeableConcept> categories) {
complexProperty.setCategory(categories);
return this;
}
public CarePlanBuilder buildCategory(CodeableConcept category) {
if (!complexProperty.hasCategory()) {
complexProperty.setCategory(new ArrayList<>());
}
complexProperty.addCategory(category);
return this;
}
public CarePlanBuilder buildTitle(String title) {
complexProperty.setTitle(title);
return this;
}
public CarePlanBuilder buildDescription(String description) {
complexProperty.setDescription(description);
return this;
}
// required
public CarePlanBuilder buildSubject(Reference reference) {
complexProperty.setSubject(reference);
return this;
}
public CarePlanBuilder buildContext(Reference reference) {
complexProperty.setContext(reference);
return this;
}
public CarePlanBuilder buildPeriod(Period period) {
complexProperty.setPeriod(period);
return this;
}
public CarePlanBuilder buildAuthor(List<Reference> references) {
complexProperty.setAuthor(references);
return this;
}
public CarePlanBuilder buildAuthor(Reference reference) {
if (!complexProperty.hasAuthor()) {
complexProperty.setAuthor(new ArrayList<>());
}
complexProperty.addAuthor(reference);
return this;
}
public CarePlanBuilder buildCareTeam(List<Reference> careTeams) {
complexProperty.setCareTeam(careTeams);
return this;
}
public CarePlanBuilder buildCareTeam(Reference careTeam) {
if (!complexProperty.hasCareTeam()) {
complexProperty.setCareTeam(new ArrayList<>());
}
complexProperty.addCareTeam(careTeam);
return this;
}
public CarePlanBuilder buildAddresses(List<Reference> addresses) {
complexProperty.setAddresses(addresses);
return this;
}
public CarePlanBuilder buildAddresses(Reference address) {
if (!complexProperty.hasAddresses()) {
complexProperty.setAddresses(new ArrayList<>());
}
complexProperty.addAddresses(address);
return this;
}
public CarePlanBuilder buildSupportingInfo(List<Reference> supportingInfo) {
complexProperty.setSupportingInfo(supportingInfo);
return this;
}
public CarePlanBuilder buildSupportingInfo(Reference supportingInfo) {
if (!complexProperty.hasSupportingInfo()) {
complexProperty.setSupportingInfo(new ArrayList<>());
}
complexProperty.addSupportingInfo(supportingInfo);
return this;
}
public CarePlanBuilder buildGoal(List<Reference> goals) {
complexProperty.setGoal(goals);
return this;
}
public CarePlanBuilder buildGoal(Reference goal) {
if (!complexProperty.hasGoal()) {
complexProperty.setGoal(new ArrayList<>());
}
complexProperty.addGoal(goal);
return this;
}
public CarePlanBuilder buildActivity(List<CarePlan.CarePlanActivityComponent> activities) {
complexProperty.setActivity(activities);
return this;
}
public CarePlanBuilder buildActivity(CarePlan.CarePlanActivityComponent activity) {
if (!complexProperty.hasActivity()) {
complexProperty.setActivity(Collections.singletonList(new CarePlan.CarePlanActivityComponent()));
}
complexProperty.getActivity().add(activity);
return this;
}
public CarePlanBuilder buildNotes(List<Annotation> notes) {
complexProperty.setNote(notes);
return this;
}
public CarePlanBuilder buildNotes(Annotation note) {
if (!complexProperty.hasNote()) {
complexProperty.setNote(new ArrayList<>());
}
complexProperty.addNote(note);
return this;
}
public CarePlanBuilder buildLanguage(String language) {
complexProperty.setLanguage(language);
return this;
}
}

View File

@ -1,33 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Coding;
import java.util.ArrayList;
import java.util.List;
public class CodeableConceptBuilder extends BaseBuilder<CodeableConcept> {
public CodeableConceptBuilder() {
super(new CodeableConcept());
}
public CodeableConceptBuilder buildCoding(List<Coding> coding) {
complexProperty.setCoding(coding);
return this;
}
public CodeableConceptBuilder buildCoding(Coding coding) {
if (!complexProperty.hasCoding()) {
complexProperty.setCoding(new ArrayList<>());
}
complexProperty.addCoding(coding);
return this;
}
public CodeableConceptBuilder buildText(String text) {
complexProperty.setText(text);
return this;
}
}

View File

@ -1,35 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.Coding;
public class CodingBuilder extends BaseBuilder<Coding> {
public CodingBuilder() {
super(new Coding());
}
public CodingBuilder buildSystem(String system) {
complexProperty.setSystem(system);
return this;
}
public CodingBuilder buildVersion(String version) {
complexProperty.setVersion(version);
return this;
}
public CodingBuilder buildCode(String code) {
complexProperty.setCode(code);
return this;
}
public CodingBuilder buildDisplay(String display) {
complexProperty.setDisplay(display);
return this;
}
public CodingBuilder buildUserSelected(boolean selected) {
complexProperty.setUserSelected(selected);
return this;
}
}

View File

@ -1,49 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.CodeableConcept;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.Period;
import org.hl7.fhir.dstu3.model.Reference;
import org.hl7.fhir.exceptions.FHIRException;
public class IdentifierBuilder extends BaseBuilder<Identifier> {
public IdentifierBuilder() {
super(new Identifier());
}
public IdentifierBuilder buildUse(Identifier.IdentifierUse use) {
complexProperty.setUse(use);
return this;
}
public IdentifierBuilder buildUse(String use) throws FHIRException {
complexProperty.setUse(Identifier.IdentifierUse.fromCode(use));
return this;
}
public IdentifierBuilder buildType(CodeableConcept type) {
complexProperty.setType(type);
return this;
}
public IdentifierBuilder buildSystem(String system) {
complexProperty.setSystem(system);
return this;
}
public IdentifierBuilder buildValue(String value) {
complexProperty.setValue(value);
return this;
}
public IdentifierBuilder buildPeriod(Period period) {
complexProperty.setPeriod(period);
return this;
}
public IdentifierBuilder buildAssigner(Reference assigner) {
complexProperty.setAssigner(assigner);
return this;
}
}

View File

@ -1,18 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.opencds.cqf.cql.runtime.DateTime;
import java.util.Date;
public class JavaDateBuilder extends BaseBuilder<Date> {
public JavaDateBuilder() {
super(new Date());
}
public JavaDateBuilder buildFromDateTime(DateTime dateTime) {
org.joda.time.DateTime dt = new org.joda.time.DateTime(dateTime.getPartial());
complexProperty = dt.toDate();
return this;
}
}

View File

@ -1,22 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.Period;
import java.util.Date;
public class PeriodBuilder extends BaseBuilder<Period> {
public PeriodBuilder() {
super(new Period());
}
public PeriodBuilder buildStart(Date start) {
complexProperty.setStart(start);
return this;
}
public PeriodBuilder buildEnd(Date end) {
complexProperty.setEnd(end);
return this;
}
}

View File

@ -1,26 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.Identifier;
import org.hl7.fhir.dstu3.model.Reference;
public class ReferenceBuilder extends BaseBuilder<Reference> {
public ReferenceBuilder() {
super(new Reference());
}
public ReferenceBuilder buildReference(String reference) {
complexProperty.setReference(reference);
return this;
}
public ReferenceBuilder buildIdentifier(Identifier identifier) {
complexProperty.setIdentifier(identifier);
return this;
}
public ReferenceBuilder buildDisplay(String display) {
complexProperty.setDisplay(display);
return this;
}
}

View File

@ -1,47 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.Enumerations;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.hl7.fhir.exceptions.FHIRException;
public class ValueSetBuider extends BaseBuilder<ValueSet> {
public ValueSetBuider(ValueSet complexProperty) {
super(complexProperty);
}
public ValueSetBuider buildId(String id) {
complexProperty.setId(id);
return this;
}
public ValueSetBuider buildUrl(String url) {
complexProperty.setUrl(url);
return this;
}
public ValueSetBuider buildTitle(String title) {
complexProperty.setTitle(title);
return this;
}
public ValueSetBuider buildStatus() {
complexProperty.setStatus(Enumerations.PublicationStatus.DRAFT);
return this;
}
public ValueSetBuider buildStatus(String status) throws FHIRException {
complexProperty.setStatus(Enumerations.PublicationStatus.fromCode(status));
return this;
}
public ValueSetBuider buildStatus(Enumerations.PublicationStatus status) {
complexProperty.setStatus(status);
return this;
}
public ValueSetBuider buildCompose(ValueSet.ValueSetComposeComponent compose) {
complexProperty.setCompose(compose);
return this;
}
}

View File

@ -1,22 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.ValueSet;
import java.util.List;
public class ValueSetComposeBuilder extends BaseBuilder<ValueSet.ValueSetComposeComponent> {
public ValueSetComposeBuilder(ValueSet.ValueSetComposeComponent complexProperty) {
super(complexProperty);
}
public ValueSetComposeBuilder buildIncludes(List<ValueSet.ConceptSetComponent> includes) {
complexProperty.setInclude(includes);
return this;
}
public ValueSetComposeBuilder buildIncludes(ValueSet.ConceptSetComponent include) {
complexProperty.addInclude(include);
return this;
}
}

View File

@ -1,37 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.builders;
import org.hl7.fhir.dstu3.model.ValueSet;
import java.util.List;
public class ValueSetIncludesBuilder extends BaseBuilder<ValueSet.ConceptSetComponent> {
public ValueSetIncludesBuilder(ValueSet.ConceptSetComponent complexProperty) {
super(complexProperty);
}
public ValueSetIncludesBuilder buildSystem(String system) {
complexProperty.setSystem(system);
return this;
}
public ValueSetIncludesBuilder buildVersion(String version) {
complexProperty.setVersion(version);
return this;
}
public ValueSetIncludesBuilder buildConcept(List<ValueSet.ConceptReferenceComponent> concepts) {
complexProperty.setConcept(concepts);
return this;
}
public ValueSetIncludesBuilder buildConcept(ValueSet.ConceptReferenceComponent concept) {
complexProperty.addConcept(concept);
return this;
}
public ValueSetIncludesBuilder buildConcept(String code, String display) {
complexProperty.addConcept(new ValueSet.ConceptReferenceComponent().setCode(code).setDisplay(display));
return this;
}
}

View File

@ -1,353 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import ca.uhn.fhir.context.FhirContext;
import com.google.gson.*;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.json.simple.JSONObject;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Christopher on 5/4/2017.
*/
public class CdsCard {
private String summary;
private String detail;
private String indicator;
public boolean hasSummary() {
return this.summary != null && !this.summary.isEmpty();
}
public String getSummary() {
return this.summary;
}
public CdsCard setSummary(String summary) {
this.summary = summary;
return this;
}
public boolean hasDetail() {
return this.detail != null && !this.detail.isEmpty();
}
public String getDetail() {
return this.detail;
}
public CdsCard setDetail(String detail) {
this.detail = detail;
return this;
}
public boolean hasIndicator() {
return this.indicator != null && !this.indicator.isEmpty();
}
public String getIndicator() {
return this.detail;
}
public CdsCard setIndicator(String indicator) {
this.indicator = indicator;
return this;
}
private Source source;
public static class Source {
private String label;
private String url;
public boolean hasLabel() {
return this.label != null && !this.label.isEmpty();
}
public String getLabel() {
return this.label;
}
public CdsCard.Source setLabel(String label) {
this.label = label;
return this;
}
public boolean hasUrl() {
return this.url != null && !this.url.isEmpty();
}
public String getUrl() {
return this.url;
}
public CdsCard.Source setUrl(String url) {
this.url = url;
return this;
}
}
public boolean hasSource() {
return source.hasLabel() || source.hasUrl();
}
public Source getSource() {
return this.source;
}
public CdsCard setSource(Source source) {
this.source = source;
return this;
}
private List<Suggestions> suggestions;
public static class Suggestions {
private String label;
private String uuid;
private List<Action> actions;
public boolean hasLabel() {
return this.label != null && !this.label.isEmpty();
}
public String getLabel() {
return this.label;
}
public CdsCard.Suggestions setLabel(String label) {
this.label = label;
return this;
}
public boolean hasUuid() {
return this.uuid != null && !this.uuid.isEmpty();
}
public String getUuid() {
return this.uuid;
}
public CdsCard.Suggestions setUuid(String uuid) {
this.uuid = uuid;
return this;
}
public boolean hasActions() {
return this.actions != null && !this.actions.isEmpty();
}
public List<Action> getActions() {
return this.actions;
}
public CdsCard.Suggestions setActions(List<Action> actions) {
this.actions = actions;
return this;
}
public static class Action {
enum ActionType {create, update, delete}
private ActionType type;
private String description;
private IBaseResource resource;
public boolean hasType() {
return this.type != null;
}
public ActionType getType() {
return this.type;
}
public Action setType(ActionType type) {
this.type = type;
return this;
}
public boolean hasDescription() {
return this.description != null && !this.description.isEmpty();
}
public String getDescription() {
return this.description;
}
public Action setDescription(String description) {
this.description = description;
return this;
}
public boolean hasResource() {
return this.resource != null;
}
public IBaseResource getResource() {
return this.resource;
}
public Action setResource(IBaseResource resource) {
this.resource = resource;
return this;
}
}
}
public boolean hasSuggestions() {
return this.suggestions != null && !this.suggestions.isEmpty();
}
public List<Suggestions> getSuggestions() {
return this.suggestions;
}
public CdsCard setSuggestions(List<Suggestions> suggestions) {
this.suggestions = suggestions;
return this;
}
private List<Links> links;
public static class Links {
private String label;
private String url;
private String type;
public boolean hasLabel() {
return this.label != null && !this.label.isEmpty();
}
public String getLabel() {
return this.label;
}
public CdsCard.Links setLabel(String label) {
this.label = label;
return this;
}
public boolean hasUrl() {
return this.url != null && !this.url.isEmpty();
}
public String getUrl() {
return this.url;
}
public CdsCard.Links setUrl(String url) {
this.url = url;
return this;
}
public boolean hasType() {
return this.type != null && !this.type.isEmpty();
}
public String getType() {
return this.type;
}
public CdsCard.Links setType(String type) {
this.type = type;
return this;
}
}
public boolean hasLinks() {
return this.links != null && !this.links.isEmpty();
}
public List<Links> getLinks() {
return this.links;
}
public CdsCard setLinks(List<Links> links) {
this.links = links;
return this;
}
public CdsCard() {
this.source = new Source();
this.suggestions = new ArrayList<>();
this.links = new ArrayList<>();
}
public JsonObject toJson() {
JsonObject card = new JsonObject();
if (hasSummary()) {
card.addProperty("summary", summary);
}
if (hasIndicator()) {
card.addProperty("indicator", indicator);
}
if (hasDetail()) {
card.addProperty("detail", detail);
}
// TODO: Source
if (hasSuggestions()) {
JsonArray suggestionArray = new JsonArray();
for (Suggestions suggestion : getSuggestions()) {
JsonObject suggestionObj = new JsonObject();
if (suggestion.hasLabel()) {
suggestionObj.addProperty("label", suggestion.getLabel());
}
if (suggestion.hasUuid()) {
suggestionObj.addProperty("uuid", suggestion.getUuid());
}
if (suggestion.hasActions()) {
JsonArray actionArray = new JsonArray();
for (Suggestions.Action action : suggestion.getActions()) {
JsonObject actionObj = new JsonObject();
if (action.hasDescription()) {
actionObj.addProperty("description", action.getDescription());
}
if (action.hasType()) {
actionObj.addProperty("type", action.getType().toString());
}
if (action.hasResource()) {
JsonElement res = new JsonParser().parse(FhirContext.forDstu3().newJsonParser().setPrettyPrint(true).encodeResourceToString(action.getResource()));
actionObj.add("resource", res);
}
actionArray.add(actionObj);
}
suggestionObj.add("actions", actionArray);
}
suggestionArray.add(suggestionObj);
}
card.add("suggestions", suggestionArray);
}
if (hasLinks()) {
JsonArray linksArray = new JsonArray();
for (Links linkElement : getLinks()) {
JsonObject link = new JsonObject();
if (linkElement.hasLabel()) {
link.addProperty("label", linkElement.getLabel());
}
if (linkElement.hasUrl()) {
link.addProperty("url", linkElement.getUrl());
}
if (linkElement.hasType()) {
link.addProperty("type", linkElement.getType());
}
linksArray.add(link);
}
card.add("links", linksArray);
}
return card;
}
// public JSONObject toJson() {
// JSONObject card = new JSONObject();
// if (hasSummary()) {
// card.put("summary", summary);
// }
// if (hasIndicator()) {
// card.put("indicator", indicator);
// }
// if (hasDetail()) {
// card.put("detail", detail);
// }
// // TODO: Source & Suggestions
// if (hasLinks()) {
// JSONArray linksArray = new JSONArray();
// for (Links linkElement : getLinks()) {
// JSONObject link = new JSONObject();
// if (linkElement.hasLabel()) {
// link.put("label", linkElement.getLabel());
// }
// if (linkElement.hasUrl()) {
// link.put("url", linkElement.getUrl());
// }
// if (linkElement.hasType()) {
// link.put("type", linkElement.getType());
// }
// linksArray.add(link);
// }
// card.put("links", linksArray);
// }
// return card;
// }
public JSONObject returnSuccess() {
JSONObject success = new JSONObject();
success.put("summary", "Success");
success.put("indicator", "success");
success.put("detail", "The MME is within the recommended range.");
return success;
}
}

View File

@ -1,70 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
/**
* Created by Christopher Schuler on 5/1/2017.
*/
public class CdsHooksHelper {
public static void DisplayDiscovery(HttpServletResponse response) throws IOException {
response.setContentType("application/json");
JSONObject jsonResponse = new JSONObject();
JSONArray jsonArray = new JSONArray();
JSONObject opioidGuidance = new JSONObject();
opioidGuidance.put("hook", "medication-prescribe");
opioidGuidance.put("name", "Opioid Morphine Milligram Equivalence (MME) Guidance Service");
opioidGuidance.put("description", "CDS Service that finds the MME of an opioid medication and provides guidance to the prescriber if the MME exceeds the recommended range.");
opioidGuidance.put("id", "cdc-opioid-guidance");
JSONObject prefetchContent = new JSONObject();
prefetchContent.put("medication", "MedicationOrder?patient={{Patient.id}}&status=active");
opioidGuidance.put("prefetch", prefetchContent);
jsonArray.add(opioidGuidance);
// JSONObject medicationPrescribe = new JSONObject();
// medicationPrescribe.put("hook", "medication-prescribe");
// medicationPrescribe.put("name", "User-defined medication-prescribe service");
// medicationPrescribe.put("description", "Enables user to define a CDS Hooks service using naming conventions");
// medicationPrescribe.put("id", "user-medication-prescribe");
//
// medicationPrescribe.put("prefetch", prefetchContent);
//
// jsonArray.add(medicationPrescribe);
//
JSONObject patientView = new JSONObject();
patientView.put("hook", "patient-view");
patientView.put("name", "Zika Virus Intervention");
patientView.put("description", "Identifies possible Zika exposure and offers suggestions for suggested actions for pregnant patients");
patientView.put("id", "zika-virus-intervention");
prefetchContent = new JSONObject();
prefetchContent.put("patient", "Patient/{{Patient.id}}");
patientView.put("prefetch", prefetchContent);
jsonArray.add(patientView);
jsonResponse.put("services", jsonArray);
response.getWriter().println(getPrettyJson(jsonResponse.toJSONString()));
}
public static String getPrettyJson(String uglyJson) {
Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser parser = new JsonParser();
JsonElement element = parser.parse(uglyJson);
return gson.toJson(element);
}
}

View File

@ -1,158 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import com.google.gson.*;
import ca.uhn.fhir.jpa.cqf.ruler.exceptions.MissingHookException;
import java.io.IOException;
import java.io.Reader;
public class CdsHooksRequest {
private JsonObject requestJson;
private String hook;
private String hookInstance;
private String fhirServerEndpoint;
// TODO
//private Object oauth;
private String redirectEndpoint;
private String userReference; // this is really a Reference (Resource/ID)
private String patientId;
private String encounterId;
private JsonArray context;
private JsonObject prefetch;
public CdsHooksRequest(Reader cdsHooksRequest) throws IOException {
JsonParser parser = new JsonParser();
this.requestJson = parser.parse(cdsHooksRequest).getAsJsonObject();
this.hook = requestJson.getAsJsonPrimitive("hook").getAsString();
if (this.hook == null || this.hook.isEmpty()) {
throw new MissingHookException("The CDS Service call must contain the hook that triggered its initiation.");
}
}
public String getHook() {
return this.hook;
}
public String getHookInstance() {
if (hookInstance == null) {
String temp = requestJson.getAsJsonPrimitive("hookInstance").getAsString();
this.hookInstance = temp == null ? "" : temp;
}
return hookInstance;
}
public String getFhirServerEndpoint() {
if (fhirServerEndpoint == null) {
String temp = requestJson.getAsJsonPrimitive("fhirServer").getAsString();
this.fhirServerEndpoint = temp == null || temp.isEmpty() ? "http://measure.eval.kanvix.com/cqf-ruler/baseDstu3" : temp;
}
return fhirServerEndpoint;
}
public String getRedirectEndpoint() {
if (redirectEndpoint == null) {
String temp = requestJson.getAsJsonPrimitive("redirect").getAsString();
this.redirectEndpoint = temp == null ? "" : temp;
}
return redirectEndpoint;
}
public String getUserReference() {
if (userReference == null) {
String temp = requestJson.getAsJsonPrimitive("user").getAsString();
this.userReference = temp == null ? "" : temp;
}
return userReference;
}
public String getPatientId() {
if (patientId == null) {
String temp = requestJson.getAsJsonPrimitive("patient").getAsString();
this.patientId = temp == null ? "" : temp;
}
return patientId;
}
public String getEncounterId() {
if (encounterId == null) {
String temp = requestJson.getAsJsonPrimitive("encounter").getAsString();
this.encounterId = temp == null ? "" : temp;
}
return encounterId;
}
public JsonArray getContext() {
if (context == null) {
JsonArray temp = requestJson.getAsJsonArray("context");
this.context = temp == null ? new JsonArray() : temp;
}
return context;
}
/*
Prefetch format:
"prefetch": {
"medication": { // for medication-prescribe and order-review
"response": {},
"resources": []
},
"diagnosticOrders": { // for order-review
"response": {},
"resources": []
},
"deviceUseRequests": { // for order-review
"response": {},
"resources": []
},
"procedureRequests": { // for order-review
"response": {},
"resources": []
},
"supplyRequests": { // for order-review
"response": {},
"resources": []
},
"patientToGreet": { // for patient-view
"response": {},
"resource": {}
}
}
*/
public JsonObject getPrefetch() {
if (prefetch == null) {
JsonObject temp = requestJson.getAsJsonObject("prefetch");
this.prefetch = temp == null ? new JsonObject() : temp;
}
return prefetch;
}
public void setPrefetch(JsonObject prefetch) {
this.prefetch = prefetch;
}
// Convenience method
// Populates resources array for sub-element of prefetch i.e. "supplyRequests" for order-review hook
// TODO - this won't do for patient-view
public void setPrefetch(Bundle prefetchBundle, String sub) {
JsonObject subJson = new JsonObject();
JsonArray resources = new JsonArray();
for (Bundle.Entry entry : prefetchBundle.getEntry()) {
JsonParser parser = new JsonParser();
JsonObject resource = parser.parse(FhirContext.forDstu2().newJsonParser().encodeResourceToString(entry.getResource())).getAsJsonObject();
resources.add(resource);
}
subJson.add("resources", resources);
this.prefetch.add(sub, subJson);
}
}

View File

@ -1,122 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import ca.uhn.fhir.model.primitive.IdDt;
import org.hl7.fhir.dstu3.model.*;
import org.opencds.cqf.cql.data.fhir.BaseFhirDataProvider;
import org.opencds.cqf.cql.execution.Context;
import javax.xml.namespace.QName;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public abstract class CdsRequestProcessor implements Processor {
CdsHooksRequest request;
PlanDefinition planDefinition;
LibraryResourceProvider libraryResourceProvider;
CdsRequestProcessor(CdsHooksRequest request, PlanDefinition planDefinition, LibraryResourceProvider libraryResourceProvider) {
this.request = request;
this.planDefinition = planDefinition;
this.libraryResourceProvider = libraryResourceProvider;
}
List<CdsCard> resolveActions(Context executionContext) {
List<CdsCard> cards = new ArrayList<>();
walkAction(executionContext, cards, planDefinition.getAction());
return cards;
}
private void walkAction(Context executionContext, List<CdsCard> cards, List<PlanDefinition.PlanDefinitionActionComponent> actions) {
for (PlanDefinition.PlanDefinitionActionComponent action : actions) {
boolean conditionsMet = true;
for (PlanDefinition.PlanDefinitionActionConditionComponent condition: action.getCondition()) {
if (condition.getKind() == PlanDefinition.ActionConditionKind.APPLICABILITY) {
if (!condition.hasExpression()) {
continue;
}
Object result = executionContext.resolveExpressionRef(condition.getExpression()).getExpression().evaluate(executionContext);
if (!(result instanceof Boolean)) {
continue;
}
if (!(Boolean) result) {
conditionsMet = false;
}
}
}
if (conditionsMet) {
/*
Cases:
Definition element provides guidance for action
Nested actions
Standardized CQL (when first 2 aren't present)
*/
if (action.hasDefinition()) {
if (action.getDefinition().getReferenceElement().getResourceType().equals("ActivityDefinition")) {
BaseFhirDataProvider provider = (BaseFhirDataProvider) executionContext.resolveDataProvider(new QName("http://hl7.org/fhir", ""));
Parameters inParams = new Parameters();
inParams.addParameter().setName("patient").setValue(new StringType(request.getPatientId()));
Parameters outParams = provider.getFhirClient()
.operation()
.onInstance(new IdDt("ActivityDefinition", action.getDefinition().getReferenceElement().getIdPart()))
.named("$apply")
.withParameters(inParams)
.useHttpGet()
.execute();
List<Parameters.ParametersParameterComponent> response = outParams.getParameter();
Resource resource = response.get(0).getResource();
if (resource == null) {
continue;
}
// TODO - currently only have suggestions that create resources - implement delete and update.
CdsCard card = new CdsCard();
card.setIndicator("info");
CdsCard.Suggestions suggestion = new CdsCard.Suggestions();
suggestion.setActions(
Collections.singletonList(
new CdsCard.Suggestions.Action()
.setType(CdsCard.Suggestions.Action.ActionType.create)
.setResource(resource)
)
);
card.getSuggestions().add(suggestion);
cards.add(card);
}
else {
// PlanDefinition $apply
// TODO
// TODO - suggestion to create CarePlan
}
}
else if (action.hasAction()) {
walkAction(executionContext, cards, action.getAction());
}
// TODO - dynamicValues
else {
CdsCard card = new CdsCard();
card.setSummary((String) executionContext.resolveExpressionRef("getSummary").getExpression().evaluate(executionContext));
card.setDetail((String) executionContext.resolveExpressionRef("getDetail").getExpression().evaluate(executionContext));
card.setIndicator((String) executionContext.resolveExpressionRef("getIndicator").getExpression().evaluate(executionContext));
cards.add(card);
}
}
}
}
}

View File

@ -1,121 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.hl7.fhir.dstu3.model.MedicationRequest;
import org.hl7.fhir.dstu3.model.PlanDefinition;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibrarySourceProvider;
import org.opencds.cqf.cql.data.fhir.BaseFhirDataProvider;
import org.opencds.cqf.cql.data.fhir.FhirDataProviderStu3;
import org.opencds.cqf.cql.execution.Context;
import org.opencds.cqf.cql.execution.LibraryLoader;
import org.opencds.cqf.cql.terminology.fhir.FhirTerminologyProvider;
import ca.uhn.fhir.jpa.cqf.ruler.exceptions.MissingContextException;
import ca.uhn.fhir.jpa.cqf.ruler.helpers.Dstu2ToStu3;
import java.util.ArrayList;
import java.util.List;
public class MedicationPrescribeProcessor extends CdsRequestProcessor {
MedicationRequest contextPrescription;
List<MedicationRequest> activePrescriptions;
private ModelManager modelManager;
private ModelManager getModelManager() {
if (modelManager == null) {
modelManager = new ModelManager();
}
return modelManager;
}
private LibraryManager libraryManager;
private LibraryManager getLibraryManager() {
if (libraryManager == null) {
libraryManager = new LibraryManager(getModelManager());
libraryManager.getLibrarySourceLoader().clearProviders();
libraryManager.getLibrarySourceLoader().registerProvider(getLibrarySourceProvider());
}
return libraryManager;
}
private LibraryLoader libraryLoader;
private LibraryLoader getLibraryLoader() {
if (libraryLoader == null) {
libraryLoader = new STU3LibraryLoader(libraryResourceProvider, getLibraryManager(), getModelManager());
}
return libraryLoader;
}
private STU3LibrarySourceProvider librarySourceProvider;
private STU3LibrarySourceProvider getLibrarySourceProvider() {
if (librarySourceProvider == null) {
librarySourceProvider = new STU3LibrarySourceProvider(libraryResourceProvider);
}
return librarySourceProvider;
}
public MedicationPrescribeProcessor(CdsHooksRequest request, PlanDefinition planDefinition, LibraryResourceProvider libraryResourceProvider)
throws FHIRException
{
super(request, planDefinition, libraryResourceProvider);
this.activePrescriptions = new ArrayList<>();
resolveContextPrescription();
resolveActivePrescriptions();
}
@Override
public List<CdsCard> process() {
// TODO - need a better way to determine library id
Library library = getLibraryLoader().load(new org.cqframework.cql.elm.execution.VersionedIdentifier().withId("medication-prescribe"));
BaseFhirDataProvider dstu3Provider = new FhirDataProviderStu3().setEndpoint(request.getFhirServerEndpoint());
// TODO - assuming terminology service is same as data provider - not a great assumption...
dstu3Provider.setTerminologyProvider(new FhirTerminologyProvider().withEndpoint(request.getFhirServerEndpoint()));
dstu3Provider.setExpandValueSets(true);
Context executionContext = new Context(library);
executionContext.registerLibraryLoader(getLibraryLoader());
executionContext.registerDataProvider("http://hl7.org/fhir", dstu3Provider);
executionContext.setExpressionCaching(true);
executionContext.setParameter(null, "Orders", activePrescriptions);
return resolveActions(executionContext);
}
private void resolveContextPrescription() throws FHIRException {
if (request.getContext().size() == 0) {
throw new MissingContextException("The medication-prescribe request requires the context to contain a prescription order.");
}
String resourceName = request.getContext().get(0).getAsJsonObject().getAsJsonPrimitive("resourceType").getAsString();
this.contextPrescription = getMedicationRequest(resourceName, FhirContext.forDstu2().newJsonParser().parseResource(request.getContext().get(0).toString()));
}
private void resolveActivePrescriptions() throws FHIRException {
this.activePrescriptions.add(contextPrescription); // include the context prescription
String resourceName;
Bundle bundle = (Bundle) FhirContext.forDstu2().newJsonParser().parseResource(request.getPrefetch().getAsJsonObject("medication").getAsJsonObject("resource").toString());
for (Bundle.Entry entry : bundle.getEntry()) {
this.activePrescriptions.add(getMedicationRequest(entry.getResource().getResourceName(), entry.getResource()));
}
}
private MedicationRequest getMedicationRequest(String resourceName, IBaseResource resource) throws FHIRException {
if (resourceName.equals("MedicationOrder")) {
MedicationOrder order = (MedicationOrder) resource;
return Dstu2ToStu3.resolveMedicationRequest(order);
}
return (MedicationRequest) resource;
}
}

View File

@ -1,115 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelInfoLoader;
import org.cqframework.cql.cql2elm.ModelInfoProvider;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.hl7.elm.r1.VersionedIdentifier;
import org.hl7.elm_modelinfo.r1.ModelInfo;
import org.hl7.fhir.dstu3.model.PlanDefinition;
import org.hl7.fhir.exceptions.FHIRException;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibrarySourceProvider;
import org.opencds.cqf.cql.data.fhir.BaseFhirDataProvider;
import org.opencds.cqf.cql.data.fhir.FhirDataProviderStu3;
import org.opencds.cqf.cql.execution.Context;
import org.opencds.cqf.cql.execution.LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.omtk.OmtkDataProvider;
import javax.xml.bind.JAXB;
import java.io.File;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Collections;
import java.util.List;
public class OpioidGuidanceProcessor extends MedicationPrescribeProcessor {
private ModelManager modelManager;
private ModelManager getModelManager() {
if (modelManager == null) {
modelManager = new ModelManager();
ModelInfoProvider infoProvider = () -> {
Path p = Paths.get("src/main/resources/cds/OMTK-modelinfo-0.1.0.xml").toAbsolutePath();
return JAXB.unmarshal(new File(p.toString()), ModelInfo.class);
};
ModelInfoLoader.registerModelInfoProvider(new VersionedIdentifier().withId("OMTK").withVersion("0.1.0"), infoProvider);
}
return modelManager;
}
private LibraryManager libraryManager;
private LibraryManager getLibraryManager() {
if (libraryManager == null) {
libraryManager = new LibraryManager(getModelManager());
libraryManager.getLibrarySourceLoader().clearProviders();
libraryManager.getLibrarySourceLoader().registerProvider(getLibrarySourceProvider());
}
return libraryManager;
}
private LibraryLoader libraryLoader;
private LibraryLoader getLibraryLoader() {
if (libraryLoader == null) {
libraryLoader = new STU3LibraryLoader(libraryResourceProvider, getLibraryManager(), getModelManager());
}
return libraryLoader;
}
private STU3LibrarySourceProvider librarySourceProvider;
private STU3LibrarySourceProvider getLibrarySourceProvider() {
if (librarySourceProvider == null) {
librarySourceProvider = new STU3LibrarySourceProvider(libraryResourceProvider);
}
return librarySourceProvider;
}
public OpioidGuidanceProcessor(CdsHooksRequest request, PlanDefinition planDefinition, LibraryResourceProvider libraryResourceProvider)
throws FHIRException
{
super(request, planDefinition, libraryResourceProvider);
}
@Override
public List<CdsCard> process() {
// read opioid library
Library library = getLibraryLoader().load(new org.cqframework.cql.elm.execution.VersionedIdentifier().withId("OpioidCdsStu3").withVersion("0.1.0"));
// resolve data providers
// the db file is issued to properly licensed implementers -- see README for more info
String path = Paths.get("src/main/resources/cds/OpioidManagementTerminologyKnowledge.db").toAbsolutePath().toString().replace("\\", "/");
String connString = "jdbc:sqlite://" + path;
OmtkDataProvider omtkProvider = new OmtkDataProvider(connString);
BaseFhirDataProvider dstu3Provider = new FhirDataProviderStu3().setEndpoint(request.getFhirServerEndpoint());
Context executionContext = new Context(library);
executionContext.registerLibraryLoader(getLibraryLoader());
executionContext.registerDataProvider("http://org.opencds/opioid-cds", omtkProvider);
executionContext.registerDataProvider("http://hl7.org/fhir", dstu3Provider);
executionContext.setExpressionCaching(true);
// executionContext.setEnableTraceLogging(true);
executionContext.setParameter(null, "Orders", activePrescriptions);
List<CdsCard> cards = resolveActions(executionContext);
if (cards.isEmpty()) {
cards.add(
new CdsCard()
.setSummary("Success")
.setDetail("Prescription satisfies recommendation #5 of the cdc opioid guidance.")
.setIndicator("info")
.setLinks(
Collections.singletonList(
new CdsCard.Links()
.setLabel("CDC Recommendations for prescribing opioids")
.setUrl("https://guidelines.gov/summaries/summary/50153/cdc-guideline-for-prescribing-opioids-for-chronic-pain---united-states-2016#420")
)
)
);
}
return cards;
}
}

View File

@ -1,93 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.hl7.fhir.dstu3.model.PlanDefinition;
import org.hl7.fhir.dstu3.model.ProcedureRequest;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibrarySourceProvider;
import org.opencds.cqf.cql.data.fhir.BaseFhirDataProvider;
import org.opencds.cqf.cql.data.fhir.FhirDataProviderStu3;
import org.opencds.cqf.cql.execution.Context;
import org.opencds.cqf.cql.execution.LibraryLoader;
import org.opencds.cqf.cql.terminology.fhir.FhirTerminologyProvider;
import ca.uhn.fhir.jpa.cqf.ruler.exceptions.MissingContextException;
import java.util.List;
public class OrderReviewProcessor extends CdsRequestProcessor {
private ProcedureRequest contextOrder;
private ModelManager modelManager;
private ModelManager getModelManager() {
if (modelManager == null) {
modelManager = new ModelManager();
}
return modelManager;
}
private LibraryManager libraryManager;
private LibraryManager getLibraryManager() {
if (libraryManager == null) {
libraryManager = new LibraryManager(getModelManager());
libraryManager.getLibrarySourceLoader().clearProviders();
libraryManager.getLibrarySourceLoader().registerProvider(getLibrarySourceProvider());
}
return libraryManager;
}
private LibraryLoader libraryLoader;
private LibraryLoader getLibraryLoader() {
if (libraryLoader == null) {
libraryLoader = new STU3LibraryLoader(libraryResourceProvider, getLibraryManager(), getModelManager());
}
return libraryLoader;
}
private STU3LibrarySourceProvider librarySourceProvider;
private STU3LibrarySourceProvider getLibrarySourceProvider() {
if (librarySourceProvider == null) {
librarySourceProvider = new STU3LibrarySourceProvider(libraryResourceProvider);
}
return librarySourceProvider;
}
public OrderReviewProcessor(CdsHooksRequest request, PlanDefinition planDefinition, LibraryResourceProvider libraryResourceProvider) {
super(request, planDefinition, libraryResourceProvider);
resolveOrder();
}
@Override
public List<CdsCard> process() {
// TODO - need a better way to determine library id
Library library = getLibraryLoader().load(new org.cqframework.cql.elm.execution.VersionedIdentifier().withId("OrderReview"));
BaseFhirDataProvider dstu3Provider = new FhirDataProviderStu3().setEndpoint(request.getFhirServerEndpoint());
// TODO - assuming terminology service is same as data provider - not a great assumption...
dstu3Provider.setTerminologyProvider(new FhirTerminologyProvider().withEndpoint(request.getFhirServerEndpoint()));
dstu3Provider.setExpandValueSets(true);
Context executionContext = new Context(library);
executionContext.registerLibraryLoader(getLibraryLoader());
executionContext.registerDataProvider("http://hl7.org/fhir", dstu3Provider);
executionContext.registerTerminologyProvider(dstu3Provider.getTerminologyProvider());
executionContext.setContextValue("Patient", request.getPatientId());
executionContext.setParameter(null, "Order", contextOrder);
executionContext.setExpressionCaching(true);
return resolveActions(executionContext);
}
private void resolveOrder() {
if (request.getContext().size() == 0) {
throw new MissingContextException("The order-review request requires the context to contain an order.");
}
// Assuming STU3 here as per the example here: http://cds-hooks.org/#radiology-appropriateness
this.contextOrder = (ProcedureRequest) FhirContext.forDstu3().newJsonParser().parseResource(request.getContext().get(0).toString());
}
}

View File

@ -1,77 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.hl7.fhir.dstu3.model.PlanDefinition;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibrarySourceProvider;
import org.opencds.cqf.cql.data.fhir.BaseFhirDataProvider;
import org.opencds.cqf.cql.data.fhir.FhirDataProviderStu3;
import org.opencds.cqf.cql.execution.Context;
import org.opencds.cqf.cql.execution.LibraryLoader;
import org.opencds.cqf.cql.terminology.fhir.FhirTerminologyProvider;
import java.util.List;
public class PatientViewProcessor extends CdsRequestProcessor {
private ModelManager modelManager;
private ModelManager getModelManager() {
if (modelManager == null) {
modelManager = new ModelManager();
}
return modelManager;
}
private LibraryManager libraryManager;
private LibraryManager getLibraryManager() {
if (libraryManager == null) {
libraryManager = new LibraryManager(getModelManager());
libraryManager.getLibrarySourceLoader().clearProviders();
libraryManager.getLibrarySourceLoader().registerProvider(getLibrarySourceProvider());
}
return libraryManager;
}
private LibraryLoader libraryLoader;
private LibraryLoader getLibraryLoader() {
if (libraryLoader == null) {
libraryLoader = new STU3LibraryLoader(libraryResourceProvider, getLibraryManager(), getModelManager());
}
return libraryLoader;
}
private STU3LibrarySourceProvider librarySourceProvider;
private STU3LibrarySourceProvider getLibrarySourceProvider() {
if (librarySourceProvider == null) {
librarySourceProvider = new STU3LibrarySourceProvider(libraryResourceProvider);
}
return librarySourceProvider;
}
public PatientViewProcessor(CdsHooksRequest request, PlanDefinition planDefinition, LibraryResourceProvider libraryResourceProvider) {
super(request, planDefinition, libraryResourceProvider);
}
@Override
public List<CdsCard> process() {
// TODO - need a better way to determine library id
Library library = getLibraryLoader().load(new org.cqframework.cql.elm.execution.VersionedIdentifier().withId("patient-view"));
BaseFhirDataProvider dstu3Provider = new FhirDataProviderStu3().setEndpoint(request.getFhirServerEndpoint());
// TODO - assuming terminology service is same as data provider - not a great assumption...
dstu3Provider.setTerminologyProvider(new FhirTerminologyProvider().withEndpoint(request.getFhirServerEndpoint()));
dstu3Provider.setExpandValueSets(true);
Context executionContext = new Context(library);
executionContext.registerLibraryLoader(getLibraryLoader());
executionContext.registerDataProvider("http://hl7.org/fhir", dstu3Provider);
executionContext.registerTerminologyProvider(dstu3Provider.getTerminologyProvider());
executionContext.setContextValue("Patient", request.getPatientId());
executionContext.setExpressionCaching(true);
return resolveActions(executionContext);
}
}

View File

@ -1,7 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.cds;
import java.util.List;
public interface Processor {
List<CdsCard> process();
}

View File

@ -1,137 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.config;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.Properties;
/**
* Created by Chris Schuler on 12/11/2016.
*/
@Configuration
@EnableTransactionManagement()
public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
// retVal.setSubscriptionEnabled(true);
// retVal.setSubscriptionPollDelay(5000);
// retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
return retVal;
}
// PostgreSQL config
// @Bean(destroyMethod = "close")
// public DataSource dataSource() {
// BasicDataSource retVal = new BasicDataSource();
// retVal.setDriver(new org.postgresql.Driver());
// retVal.setUrl("jdbc:postgresql://localhost:5432/fhir");
// retVal.setUsername("hapi");
// retVal.setPassword("hapi");
// return retVal;
// }
// Derby config
@Bean(destroyMethod = "close")
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
retVal.setUrl("jdbc:derby:directory:target/jpaserver_derby_files;create=true");
retVal.setUsername("");
retVal.setPassword("");
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("HAPI_PU");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
return retVal;
}
// PostgreSQL config
// private Properties jpaProperties() {
// Properties extraProperties = new Properties();
// extraProperties.put("hibernate.dialect", org.hibernate.dialect.PostgreSQL94Dialect.class.getName());
// extraProperties.put("hibernate.format_sql", "true");
// extraProperties.put("hibernate.show_sql", "false");
// extraProperties.put("hibernate.hbm2ddl.auto", "update");
// extraProperties.put("hibernate.jdbc.batch_size", "20");
// extraProperties.put("hibernate.cache.use_query_cache", "false");
// extraProperties.put("hibernate.cache.use_second_level_cache", "false");
// extraProperties.put("hibernate.cache.use_structured_entries", "false");
// extraProperties.put("hibernate.cache.use_minimal_puts", "false");
// extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
// extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
// extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
//// extraProperties.put("hibernate.search.default.worker.execution", "async");
// return extraProperties;
// }
// Derby config
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.dialect", org.hibernate.dialect.DerbyTenSevenDialect.class.getName());
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.jdbc.batch_size", "20");
extraProperties.put("hibernate.cache.use_query_cache", "false");
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
extraProperties.put("hibernate.cache.use_structured_entries", "false");
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
extraProperties.put("hibernate.search.default.directory_provider", "filesystem");
extraProperties.put("hibernate.search.default.indexBase", "target/lucenefiles");
extraProperties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
// extraProperties.put("hibernate.search.default.worker.execution", "async");
return extraProperties;
}
public IServerInterceptor loggingInterceptor() {
LoggingInterceptor retVal = new LoggingInterceptor();
retVal.setLoggerName("fhirtest.access");
retVal.setMessageFormat(
"Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]");
retVal.setLogExceptions(true);
retVal.setErrorMessageFormat("ERROR - ${requestVerb} ${requestUrl}");
return retVal;
}
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor responseHighlighterInterceptor() {
return new ResponseHighlighterInterceptor();
}
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
return new SubscriptionsRequireManualActivationInterceptorDstu3();
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
}

View File

@ -1,33 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.config;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.to.FhirTesterMvcConfig;
import ca.uhn.fhir.to.TesterConfig;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
/**
* Created by Chris Schuler on 12/11/2016.
*/
@Configuration
@Import(FhirTesterMvcConfig.class)
public class FhirTesterConfigDstu3 {
@Bean
public TesterConfig testerConfig() {
TesterConfig retVal = new TesterConfig();
retVal
.addServer()
.withId("home")
.withFhirVersion(FhirVersionEnum.DSTU3)
.withBaseUrl("${serverBase}/baseDstu3")
.withName("Local Tester")
.addServer()
.withId("hapi")
.withFhirVersion(FhirVersionEnum.DSTU3)
.withBaseUrl("http://fhirtest.uhn.ca/baseDstu3")
.withName("Public HAPI Test Server");
return retVal;
}
}

View File

@ -1,108 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.config;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.CqlTranslatorException;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.cqframework.cql.elm.execution.VersionedIdentifier;
import org.hl7.fhir.dstu3.model.IdType;
import org.opencds.cqf.cql.execution.LibraryLoader;
import javax.xml.bind.JAXBException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import static ca.uhn.fhir.jpa.cqf.ruler.helpers.LibraryHelper.errorsToString;
import static ca.uhn.fhir.jpa.cqf.ruler.helpers.LibraryHelper.readLibrary;
import static ca.uhn.fhir.jpa.cqf.ruler.helpers.LibraryHelper.translateLibrary;
/**
* Created by Christopher on 1/11/2017.
*/
public class STU3LibraryLoader implements LibraryLoader {
private LibraryManager libraryManager;
private ModelManager modelManager;
private LibraryResourceProvider provider;
private Map<String, Library> libraries = new HashMap<>();
public Map<String, Library> getLibraries() {
return this.libraries;
}
public STU3LibraryLoader(LibraryResourceProvider provider, LibraryManager libraryManager, ModelManager modelManager) {
this.libraryManager = libraryManager;
this.modelManager = modelManager;
this.provider = provider;
}
private Library resolveLibrary(VersionedIdentifier libraryIdentifier) {
if (libraryIdentifier == null) {
throw new IllegalArgumentException("Library identifier is null.");
}
if (libraryIdentifier.getId() == null) {
throw new IllegalArgumentException("Library identifier id is null.");
}
Library library = libraries.get(libraryIdentifier.getId());
if (library != null && libraryIdentifier.getVersion() != null
&& !libraryIdentifier.getVersion().equals(library.getIdentifier().getVersion())) {
throw new IllegalArgumentException(String.format("Could not load library %s, version %s because version %s is already loaded.",
libraryIdentifier.getId(), libraryIdentifier.getVersion(), library.getIdentifier().getVersion()));
}
else {
library = loadLibrary(libraryIdentifier);
libraries.put(libraryIdentifier.getId(), library);
}
return library;
}
private Library loadLibrary(VersionedIdentifier libraryIdentifier) {
IdType id = new IdType(libraryIdentifier.getId());
org.hl7.fhir.dstu3.model.Library library = provider.getDao().read(id);
InputStream is = null;
for (org.hl7.fhir.dstu3.model.Attachment content : library.getContent()) {
is = new ByteArrayInputStream(content.getData());
if (content.getContentType().equals("application/elm+xml")) {
return readLibrary(is);
}
else if (content.getContentType().equals("text/cql")) {
return translateLibrary(is, libraryManager, modelManager);
}
}
org.hl7.elm.r1.VersionedIdentifier identifier = new org.hl7.elm.r1.VersionedIdentifier()
.withId(libraryIdentifier.getId())
.withSystem(libraryIdentifier.getSystem())
.withVersion(libraryIdentifier.getVersion());
ArrayList<CqlTranslatorException> errors = new ArrayList<>();
org.hl7.elm.r1.Library translatedLibrary = libraryManager.resolveLibrary(identifier, errors).getLibrary();
if (errors.size() > 0) {
throw new IllegalArgumentException(errorsToString(errors));
}
try {
return readLibrary(new ByteArrayInputStream(CqlTranslator.fromStream(is == null ? new ByteArrayInputStream(new byte[]{}) : is, modelManager, libraryManager).convertToXml(translatedLibrary).getBytes(StandardCharsets.UTF_8)));
} catch (JAXBException | IOException e) {
throw new IllegalArgumentException(String.format("Errors occurred translating library %s%s.",
identifier.getId(), identifier.getVersion() != null ? ("-" + identifier.getVersion()) : ""));
}
}
@Override
public Library load(VersionedIdentifier versionedIdentifier) {
return resolveLibrary(versionedIdentifier);
}
}

View File

@ -1,35 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.config;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import org.cqframework.cql.cql2elm.LibrarySourceProvider;
import org.hl7.elm.r1.VersionedIdentifier;
import org.hl7.fhir.dstu3.model.IdType;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
/**
* Created by Christopher on 1/12/2017.
*/
public class STU3LibrarySourceProvider implements LibrarySourceProvider {
private LibraryResourceProvider provider;
public STU3LibrarySourceProvider(LibraryResourceProvider provider) {
this.provider = provider;
}
@Override
public InputStream getLibrarySource(VersionedIdentifier versionedIdentifier) {
IdType id = new IdType(versionedIdentifier.getId());
org.hl7.fhir.dstu3.model.Library lib = provider.getDao().read(id);
for (org.hl7.fhir.dstu3.model.Attachment content : lib.getContent()) {
if (content.getContentType().equals("text/cql")) {
return new ByteArrayInputStream(content.getData());
}
}
throw new IllegalArgumentException(String.format("Library %s%s does not contain CQL source content.", versionedIdentifier.getId(),
versionedIdentifier.getVersion() != null ? ("-" + versionedIdentifier.getVersion()) : ""));
}
}

View File

@ -1,8 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.exceptions;
public class ActivityDefinitionApplyException extends RuntimeException {
public ActivityDefinitionApplyException(String message) {
super(message);
}
}

View File

@ -1,9 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.exceptions;
public class InvalidHookException extends RuntimeException {
public InvalidHookException(String message) {
super(message);
}
}

View File

@ -1,9 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.exceptions;
public class MissingContextException extends RuntimeException {
public MissingContextException(String message) {
super(message);
}
}

View File

@ -1,9 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.exceptions;
public class MissingHookException extends RuntimeException {
public MissingHookException(String message) {
super(message);
}
}

View File

@ -1,46 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.helpers;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
public class DateHelper {
// Helper class to resolve period dates
public static Date resolveRequestDate(String date, boolean start) {
// split it up - support dashes or slashes
String[] dissect = date.contains("-") ? date.split("-") : date.split("/");
List<Integer> 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.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();
}
}

View File

@ -1,84 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.helpers;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.SimpleQuantityDt;
import ca.uhn.fhir.model.dstu2.resource.MedicationOrder;
import ca.uhn.fhir.model.primitive.BooleanDt;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import java.util.ArrayList;
import java.util.List;
public class Dstu2ToStu3 {
// MedicationRequest
public static MedicationRequest resolveMedicationRequest(MedicationOrder order) throws FHIRException {
/*
* Required fields:
* MedicationOrder -> MedicationRequest
* medication -> medication
* dosageInstruction (Backbone) -> Dosage (Element)
*/
return new MedicationRequest()
.setStatus(MedicationRequest.MedicationRequestStatus.fromCode(order.getStatus()))
.setMedication(convertToCodeableConcept((CodeableConceptDt) order.getMedication()))
.setDosageInstruction(convertToDosage(order.getDosageInstruction()));
}
private static CodeableConcept convertToCodeableConcept(CodeableConceptDt conceptDt) {
CodeableConcept concept = new CodeableConcept().setText(conceptDt.getText() == null ? "" : conceptDt.getText());
concept.setId(conceptDt.getElementSpecificId());
List<Coding> codes = new ArrayList<>();
for (CodingDt code : conceptDt.getCoding()) {
codes.add(new Coding()
.setCode(code.getCode())
.setSystem(code.getSystem())
.setDisplay(code.getDisplay())
.setVersion(code.getVersion())
);
}
return concept.setCoding(codes);
}
private static List<Dosage> convertToDosage(List<MedicationOrder.DosageInstruction> instructions) throws FHIRException {
List<Dosage> dosages = new ArrayList<>();
for (MedicationOrder.DosageInstruction dosageInstruction : instructions) {
Dosage dosage = new Dosage();
dosage.setText(dosageInstruction.getText());
dosage.setAsNeeded(dosageInstruction.getAsNeeded() == null ? new BooleanType(true) : new BooleanType(((BooleanDt) dosageInstruction.getAsNeeded()).getValue()));
Integer frequency = dosageInstruction.getTiming().getRepeat().getFrequency();
Integer frequencyMax = dosageInstruction.getTiming().getRepeat().getFrequencyMax();
Timing.TimingRepeatComponent repeat = new Timing.TimingRepeatComponent();
if (frequency != null) {
repeat.setFrequency(frequency);
}
if (frequencyMax != null) {
repeat.setFrequencyMax(frequencyMax);
}
repeat.setPeriod(dosageInstruction.getTiming().getRepeat().getPeriod())
.setPeriodUnit(Timing.UnitsOfTime.fromCode(dosageInstruction.getTiming().getRepeat().getPeriodUnits()));
Timing timing = new Timing();
timing.setRepeat(repeat);
dosage.setTiming(timing);
SimpleQuantityDt quantityDt = (SimpleQuantityDt) dosageInstruction.getDose();
dosage.setDose(new SimpleQuantity()
.setValue(quantityDt.getValue())
.setUnit(quantityDt.getUnit())
.setCode(quantityDt.getCode())
.setSystem(quantityDt.getSystem())
);
dosages.add(dosage);
}
return dosages;
}
}

View File

@ -1,40 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.helpers;
import org.opencds.cqf.cql.execution.Context;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Resource;
/**
* Created by Bryn on 5/7/2016.
*/
public class FhirMeasureBundler {
// Adds the resources returned from the given expressions to a bundle
public Bundle bundle(Context context, String... expressionNames) {
Bundle bundle = new Bundle();
bundle.setType(Bundle.BundleType.COLLECTION);
for (String expressionName : expressionNames) {
Object result = context.resolveExpressionRef(expressionName).evaluate(context);
for (Object element : (Iterable)result) {
Bundle.BundleEntryComponent entry = new Bundle.BundleEntryComponent();
entry.setResource((Resource)element);
entry.setFullUrl(((Resource)element).getId());
bundle.getEntry().add(entry);
}
}
return bundle;
}
public Bundle bundle(Iterable<Resource> resources) {
Bundle bundle = new Bundle();
bundle.setType(Bundle.BundleType.COLLECTION);
for (Resource resource : resources) {
Bundle.BundleEntryComponent entry = new Bundle.BundleEntryComponent();
entry.setResource(resource);
entry.setFullUrl(resource.getId());
bundle.getEntry().add(entry);
}
return bundle;
}
}

View File

@ -1,177 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.helpers;
import org.hl7.fhir.dstu3.model.*;
import org.opencds.cqf.cql.execution.Context;
import org.opencds.cqf.cql.runtime.DateTime;
import org.opencds.cqf.cql.runtime.Interval;
import java.util.*;
/**
* Created by Bryn on 5/7/2016.
*/
public class FhirMeasureEvaluator {
private MeasureReport resolveGroupings(MeasureReport report, Measure measure, Context context)
{
HashMap<String,Resource> resources = new HashMap<>();
// for each measure group
for (Measure.MeasureGroupComponent group : measure.getGroup()) {
MeasureReport.MeasureReportGroupComponent reportGroup = new MeasureReport.MeasureReportGroupComponent();
// TODO: Do I need to do this copy? Will HAPI FHIR do this automatically?
reportGroup.setIdentifier(group.getIdentifier().copy());
report.getGroup().add(reportGroup);
for (Measure.MeasureGroupPopulationComponent population : group.getPopulation()) {
// evaluate the criteria expression, should return true/false, translate to 0/1 for report
Object result = context.resolveExpressionRef(population.getCriteria()).evaluate(context);
int count = 0;
if (result instanceof Boolean) {
count = (Boolean)result ? 1 : 0;
}
else if (result instanceof Iterable) {
for (Object item : (Iterable)result) {
count++;
if (item instanceof Resource) {
resources.put(((Resource)item).getId(), (Resource)item);
}
}
}
MeasureReport.MeasureReportGroupPopulationComponent populationReport = new MeasureReport.MeasureReportGroupPopulationComponent();
populationReport.setCount(count);
populationReport.setCode(population.getCode());
reportGroup.getPopulation().add(populationReport);
}
}
ArrayList<String> expressionNames = new ArrayList<>();
// HACK: Hijacking Supplemental data to specify the evaluated resources
// In reality, this should be specified explicitly, but I'm not sure what else to do here....
for (Measure.MeasureSupplementalDataComponent supplementalData : measure.getSupplementalData()) {
expressionNames.add(supplementalData.getCriteria());
}
// TODO: Need to return both the MeasureReport and the EvaluatedResources Bundle
FhirMeasureBundler bundler = new FhirMeasureBundler();
//String[] expressionNameArray = new String[expressionNames.size()];
//expressionNameArray = expressionNames.toArray(expressionNameArray);
//org.hl7.fhir.dstu3.model.Bundle evaluatedResources = bundler.bundle(context, expressionNameArray);
org.hl7.fhir.dstu3.model.Bundle evaluatedResources = bundler.bundle(resources.values());
evaluatedResources.setId(UUID.randomUUID().toString());
//String jsonString = fhirClient.getFhirContext().newJsonParser().encodeResourceToString(evaluatedResources);
//ca.uhn.fhir.rest.api.MethodOutcome result = fhirClient.create().resource(evaluatedResources).execute();
report.setEvaluatedResources(new Reference('#' + evaluatedResources.getId()));
report.addContained(evaluatedResources);
return report;
}
// Patient Evaluation
public MeasureReport evaluate(Context context, Measure measure, Patient patient, Date periodStart, Date periodEnd) {
MeasureReport report = new MeasureReport();
report.setMeasure(new Reference(measure));
report.setPatient(new Reference(patient));
Period reportPeriod = new Period();
reportPeriod.setStart(periodStart);
reportPeriod.setEnd(periodEnd);
report.setPeriod(reportPeriod);
report.setType(MeasureReport.MeasureReportType.INDIVIDUAL);
Interval measurementPeriod = new Interval(DateTime.fromJavaDate(periodStart), true, DateTime.fromJavaDate(periodEnd), true);
context.setParameter(null, "Measurement Period", measurementPeriod);
return resolveGroupings(report, measure, context);
}
public MeasureReport evaluate(Context context, Measure measure, Patient patient, Interval measurementPeriod) {
return evaluate(context, measure, patient, (Date)measurementPeriod.getStart(), (Date)measurementPeriod.getEnd());
}
// Population evaluation
// public MeasureReport evaluate(Context context, Measure measure, List<Patient> patients,
// Interval measurementPeriod, MeasureReport.MeasureReportType type)
// {
// MeasureReport report = new MeasureReport();
// report.setMeasure(new Reference(measure));
// Period reportPeriod = new Period();
// reportPeriod.setStart((Date) measurementPeriod.getStart());
// reportPeriod.setEnd((Date) measurementPeriod.getEnd());
// report.setPeriod(reportPeriod);
// report.setType(type);
//
// return resolveGroupings(report, measure, context, patients);
// }
public MeasureReport evaluate(Context context, Measure measure, List<Patient> population,
Interval measurementPeriod, MeasureReport.MeasureReportType type)
{
MeasureReport report = new MeasureReport();
report.setMeasure(new Reference(measure));
Period reportPeriod = new Period();
reportPeriod.setStart((Date) measurementPeriod.getStart());
reportPeriod.setEnd((Date) measurementPeriod.getEnd());
report.setPeriod(reportPeriod);
report.setType(type);
context.setParameter(null, "Measurement Period", measurementPeriod);
HashMap<String,Resource> resources = new HashMap<>();
// for each measure group
for (Measure.MeasureGroupComponent group : measure.getGroup()) {
MeasureReport.MeasureReportGroupComponent reportGroup = new MeasureReport.MeasureReportGroupComponent();
reportGroup.setIdentifier(group.getIdentifier());
report.getGroup().add(reportGroup);
for (Measure.MeasureGroupPopulationComponent pop : group.getPopulation()) {
int count = 0;
// Worried about performance here with big populations...
for (Patient patient : population) {
context.setContextValue("Patient", patient);
Object result = context.resolveExpressionRef(pop.getCriteria()).evaluate(context);
if (result instanceof Boolean) {
count += (Boolean) result ? 1 : 0;
}
else if (result instanceof Iterable) {
for (Object item : (Iterable) result) {
count++;
if (item instanceof Resource) {
resources.put(((Resource) item).getId(), (Resource) item);
}
}
}
}
MeasureReport.MeasureReportGroupPopulationComponent populationReport = new MeasureReport.MeasureReportGroupPopulationComponent();
populationReport.setCount(count);
populationReport.setCode(pop.getCode());
/*
TODO - it is a reference to a list...
Probably want to create the list and POST it, then include a reference to it.
*/
// if (patients != null) {
// ListResource list = new ListResource();
// populationReport.setPatients();
// }
reportGroup.getPopulation().add(populationReport);
}
}
ArrayList<String> expressionNames = new ArrayList<>();
// HACK: Hijacking Supplemental data to specify the evaluated resources
// In reality, this should be specified explicitly, but I'm not sure what else to do here....
for (Measure.MeasureSupplementalDataComponent supplementalData : measure.getSupplementalData()) {
expressionNames.add(supplementalData.getCriteria());
}
FhirMeasureBundler bundler = new FhirMeasureBundler();
org.hl7.fhir.dstu3.model.Bundle evaluatedResources = bundler.bundle(resources.values());
evaluatedResources.setId(UUID.randomUUID().toString());
report.setEvaluatedResources(new Reference('#' + evaluatedResources.getId()));
report.addContained(evaluatedResources);
return report;
}
}

View File

@ -1,81 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.helpers;
import org.cqframework.cql.cql2elm.CqlTranslator;
import org.cqframework.cql.cql2elm.CqlTranslatorException;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.cqframework.cql.elm.tracking.TrackBack;
import org.opencds.cqf.cql.execution.CqlLibraryReader;
import javax.xml.bind.JAXBException;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
/**
* Created by Christopher on 1/11/2017.
*/
public class LibraryHelper {
public static Library readLibrary(InputStream xmlStream) {
try {
return CqlLibraryReader.read(xmlStream);
} catch (IOException | JAXBException e) {
throw new IllegalArgumentException("Error encountered while reading ELM xml: " + e.getMessage());
}
}
public static String errorsToString(Iterable<CqlTranslatorException> exceptions) {
ArrayList<String> errors = new ArrayList<>();
for (CqlTranslatorException error : exceptions) {
TrackBack tb = error.getLocator();
String lines = tb == null ? "[n/a]" : String.format("%s[%d:%d, %d:%d]",
(tb.getLibrary() != null ? tb.getLibrary().getId() + (tb.getLibrary().getVersion() != null
? ("-" + tb.getLibrary().getVersion()) : "") : ""),
tb.getStartLine(), tb.getStartChar(), tb.getEndLine(), tb.getEndChar());
errors.add(lines + error.getMessage());
}
return errors.toString();
}
public static CqlTranslator getTranslator(String cql, LibraryManager libraryManager, ModelManager modelManager) {
return getTranslator(new ByteArrayInputStream(cql.getBytes(StandardCharsets.UTF_8)), libraryManager, modelManager);
}
public static CqlTranslator getTranslator(InputStream cqlStream, LibraryManager libraryManager, ModelManager modelManager) {
ArrayList<CqlTranslator.Options> options = new ArrayList<>();
options.add(CqlTranslator.Options.EnableDateRangeOptimization);
options.add(CqlTranslator.Options.EnableAnnotations);
options.add(CqlTranslator.Options.EnableDetailedErrors);
CqlTranslator translator;
try {
translator = CqlTranslator.fromStream(cqlStream, modelManager, libraryManager,
options.toArray(new CqlTranslator.Options[options.size()]));
} catch (IOException e) {
throw new IllegalArgumentException(String.format("Errors occurred translating library: %s", e.getMessage()));
}
if (translator.getErrors().size() > 0) {
throw new IllegalArgumentException(errorsToString(translator.getErrors()));
}
return translator;
}
public static Library translateLibrary(String cql, LibraryManager libraryManager, ModelManager modelManager) {
return translateLibrary(new ByteArrayInputStream(cql.getBytes(StandardCharsets.UTF_8)), libraryManager, modelManager);
}
public static Library translateLibrary(InputStream cqlStream, LibraryManager libraryManager, ModelManager modelManager) {
CqlTranslator translator = getTranslator(cqlStream, libraryManager, modelManager);
return readLibrary(new ByteArrayInputStream(translator.toXml().getBytes(StandardCharsets.UTF_8)));
}
public static Library translateLibrary(CqlTranslator translator) {
return readLibrary(new ByteArrayInputStream(translator.toXml().getBytes(StandardCharsets.UTF_8)));
}
}

View File

@ -1,211 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.helpers;
import ca.uhn.fhir.context.FhirContext;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.hl7.fhir.dstu3.model.*;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
public class XlsxToValueSet {
// Default indexes and output directory path
private static boolean valueSet = true;
private static int startLine = 0;
private static int oidCol = 0;
private static int systemCol = 1;
private static int versionCol = 2;
private static int codeCol = 3;
private static int displayCol = 4;
private static int urlCol = 1;
private static String outDir = "src/main/resources/valuesets/";
private static final String validFlags = "-b (line to start conversion)\n-o (oid column index)\n-s (code system column index)\n-v (version column index)\n-c (code column index)\n-d (display column index)\n-u (url column index) only used for CodeSystem conversion";
private static Map<String, ValueSet> valuesets = new HashMap<>();
private static Map<String, CodeSystem> codeSystems = new HashMap<>();
private static void populateOidVs(String oid) {
ValueSet vs = new ValueSet();
vs.setId(oid);
vs.setStatus(Enumerations.PublicationStatus.DRAFT);
valuesets.put(oid, vs);
}
private static void populateOidCs(String oid) {
CodeSystem cs = new CodeSystem();
cs.setId(oid);
cs.setStatus(Enumerations.PublicationStatus.DRAFT);
cs.setContent(CodeSystem.CodeSystemContentMode.EXAMPLE);
codeSystems.put(oid, cs);
}
private static String getNextCellString(Cell cell) {
cell.setCellType(CellType.STRING);
return cell.getStringCellValue();
}
// default format: oid ... system ... version ... code ... display
private static void resolveRowVs(Row row) {
String oid = getNextCellString(row.getCell(oidCol));
if (!valuesets.containsKey(oid)) {
populateOidVs(oid);
}
String system = getNextCellString(row.getCell(systemCol));
String version = getNextCellString(row.getCell(versionCol));
String code = getNextCellString(row.getCell(codeCol));
String display = getNextCellString(row.getCell(displayCol));
ValueSet.ValueSetComposeComponent vscc = valuesets.get(oid).getCompose();
ValueSet.ConceptSetComponent component = new ValueSet.ConceptSetComponent();
component.setSystem(system).setVersion(version);
component.addConcept(new ValueSet.ConceptReferenceComponent().setCode(code).setDisplay(display));
vscc.addInclude(component);
}
// default format: oid ... url ... version ... code ... display
private static void resolveRowCs(Row row) {
String oid = getNextCellString(row.getCell(oidCol));
if (!codeSystems.containsKey(oid)) {
populateOidCs(oid);
}
String url = getNextCellString(row.getCell(urlCol));
String version = getNextCellString(row.getCell(versionCol));
String code = getNextCellString(row.getCell(codeCol));
String display = getNextCellString(row.getCell(displayCol));
CodeSystem cs = codeSystems.get(oid);
cs.setUrl(url).setVersion(version);
cs.getConcept().add(new CodeSystem.ConceptDefinitionComponent().setCode(code).setDisplay(display));
}
private static Bundle valuesetBundle() {
Bundle temp = new Bundle();
for (String key : valuesets.keySet())
temp.addEntry(new Bundle.BundleEntryComponent().setResource(valuesets.get(key)));
return temp;
}
private static Bundle codesystemBundle() {
Bundle temp = new Bundle();
for (String key : codeSystems.keySet())
temp.addEntry(new Bundle.BundleEntryComponent().setResource(codeSystems.get(key)));
return temp;
}
// library function use
public static Bundle convertCs(Workbook workbook, String[] args) {
resolveArgs(args);
Iterator<Row> rowIterator = workbook.getSheetAt(0).iterator();
int currentRow = 0;
while (currentRow++ != startLine) {
rowIterator.next();
}
while (rowIterator.hasNext()) {
resolveRowCs(rowIterator.next());
}
return codesystemBundle();
}
public static Bundle convertCs(String[] args) {
return convertCs(getWorkbook(args[0]), args);
}
public static Bundle convertVs(Workbook workbook, String[] args) {
resolveArgs(args);
Iterator<Row> rowIterator = workbook.getSheetAt(0).iterator();
int currentRow = 0;
while (currentRow++ != startLine) {
rowIterator.next();
}
while (rowIterator.hasNext()) {
resolveRowVs(rowIterator.next());
}
return valuesetBundle();
}
public static Bundle convertVs(String[] args) {
return convertVs(getWorkbook(args[0]), args);
}
public static Workbook getWorkbook(String workbookPath) {
Workbook workbook = null;
try {
FileInputStream spreadsheetStream = new FileInputStream(new File(workbookPath));
workbook = new XSSFWorkbook(spreadsheetStream);
} catch (IOException e) {
e.printStackTrace();
}
return workbook;
}
private static void resolveArgs(String[] args) {
for (String arg : args) {
String[] flagAndValue = arg.split("=");
switch (flagAndValue[0]) {
case "-b": startLine = Integer.parseInt(flagAndValue[1]); break;
case "-o": oidCol = Integer.parseInt(flagAndValue[1]); break;
case "-s": systemCol = Integer.parseInt(flagAndValue[1]); break;
case "-v": versionCol = Integer.parseInt(flagAndValue[1]); break;
case "-c": codeCol = Integer.parseInt(flagAndValue[1]); break;
case "-d": displayCol = Integer.parseInt(flagAndValue[1]); break;
case "-u": urlCol = Integer.parseInt(flagAndValue[1]); break;
case "-outDir": outDir = flagAndValue[1]; break;
case "-cs": valueSet = false; break;
default:
if (flagAndValue[0].startsWith("-")) {
throw new IllegalArgumentException(String.format("Invalid flag: %s\n%s", flagAndValue[0], validFlags));
}
break;
}
}
}
public static void main(String[] args) throws IOException {
if (args.length < 1) {
System.err.println("Path to excel file is required");
return;
}
if (args.length > 1) {
resolveArgs(args);
}
Bundle temp = valueSet ? convertVs(args) : convertCs(args);
FhirContext context = FhirContext.forDstu3();
for (Bundle.BundleEntryComponent component : temp.getEntry()) {
File f = new File(outDir + component.getResource().getId() + ".json");
if (f.createNewFile()) {
PrintWriter writer = new PrintWriter(f);
writer.println(context.newJsonParser().setPrettyPrint(true).encodeResourceToString(component.getResource()));
writer.println();
writer.close();
}
}
}
}

View File

@ -1,157 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.omtk;
import org.opencds.cqf.cql.data.DataProvider;
import org.opencds.cqf.cql.runtime.Code;
import org.opencds.cqf.cql.runtime.Interval;
import java.math.BigDecimal;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
* Created by Bryn on 4/24/2017.
*/
public class OmtkDataProvider implements DataProvider {
public static final String RXNORM = "http://www.nlm.nih.gov/research/umls/rxnorm";
public OmtkDataProvider(String connectionString) {
if (connectionString == null) {
throw new IllegalArgumentException("connectionString is null");
}
this.connectionString = connectionString;
}
private String connectionString;
private java.sql.Connection connection;
private java.sql.Connection getConnection() {
if (connection == null) {
connection = getNewConnection();
}
try {
if (!connection.isValid(0)) {
connection = getNewConnection();
}
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
return connection;
}
private java.sql.Connection getNewConnection() {
try {
return DriverManager.getConnection(connectionString);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
public Iterable<Object> retrieve(String context, Object contextValue, String dataType, String templateId,
String codePath, Iterable<Code> codes, String valueSet, String datePath,
String dateLowPath, String dateHighPath, Interval dateRange) {
java.sql.Statement statement = null;
try {
statement = getConnection().createStatement();
// TODO: Construct the SELECT statement based on the code path
// TODO: Throw an error if an attempt is made to limit based on date range
StringBuilder select = new StringBuilder();
select.append(String.format("SELECT * FROM %s", dataType));
if (codePath != null) {
StringBuilder codeList = new StringBuilder();
boolean plural = false;
for (Code code : codes) {
if (codeList.length() > 0) {
codeList.append(", ");
plural = true;
}
codeList.append(code.getCode()); // TODO: Need to handle the case when code is a string type...
}
if (plural) {
select.append(String.format(" WHERE %s IN ( %s )", codePath, codeList.toString()));
}
else {
select.append(String.format(" WHERE %S = %s", codePath, codeList.toString()));
}
}
if (datePath != null) {
throw new UnsupportedOperationException("OmtkDataProvider does not support filtering by date range.");
}
java.sql.ResultSet rs = statement.executeQuery(select.toString());
return new OmtkDataWrapper(rs);
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
@Override
public String getPackageName() {
return "ca.uhn.fhir.jpaca.uhn.fhir.jpa.cqf.ruler.omtk";
}
@Override
public void setPackageName(String s) {
}
@Override
public Object resolvePath(Object target, String path) {
if (target == null) {
return null;
}
if (target instanceof OmtkRow) {
OmtkRow row = (OmtkRow)target;
return mapType(row.getValue(path), path);
}
throw new UnsupportedOperationException(String.format("Could not retrieve value of property %s from object of type %s.",
path, target.getClass().getName()));
}
@Override
public Class resolveType(String typeName) {
throw new UnsupportedOperationException("OmtkProvider does not support write.");
}
@Override
public Class resolveType(Object o) {
throw new UnsupportedOperationException("OmtkProvider does not support write.");
}
@Override
public Object createInstance(String s) {
throw new UnsupportedOperationException("OmtkProvider does not support write.");
}
@Override
public void setValue(Object target, String path, Object value) {
throw new UnsupportedOperationException("OmtkProvider does not support write.");
}
private Object mapType(Object type, String path) {
// not all integers are codes
if (path.equals("STRENGTH_VALUE")) {
return new BigDecimal(type.toString());
}
if (type instanceof Double) {
return new BigDecimal((Double) type);
}
else if (type instanceof Integer) {
return new Code().withCode(type.toString()).withSystem("http://www.nlm.nih.gov/research/umls/rxnorm");
}
return type;
}
}

View File

@ -1,124 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.omtk;
import org.opencds.cqf.cql.runtime.Code;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.NoSuchElementException;
/**
* Created by Bryn on 4/24/2017.
*/
public class OmtkDataWrapper implements Iterable<Object> {
// TODO: Lifecycle management.... assuming GC for now
private ResultSet rs;
public OmtkDataWrapper(ResultSet rs) {
if (rs == null) {
throw new IllegalArgumentException("rs is null");
}
this.rs = rs;
}
/**
* Returns an iterator over elements of type {@code T}.
*
* @return an Iterator.
*/
@Override
public Iterator<Object> iterator() {
return new OmtkDataWrapperIterator();
}
private class OmtkDataWrapperIterator implements Iterator<Object> {
public OmtkDataWrapperIterator() {
try {
hasNext = rs.next();
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
private boolean hasNext = false;
/**
* Returns {@code true} if the iteration has more elements.
* (In other words, returns {@code true} if {@link #next} would
* return an element rather than throwing an exception.)
*
* @return {@code true} if the iteration has more elements
*/
@Override
public boolean hasNext() {
return hasNext;
}
/**
* Returns the next element in the iteration.
*
* @return the next element in the iteration
* @throws NoSuchElementException if the iteration has no more elements
*/
@Override
public Object next() {
if (!hasNext) {
throw new NoSuchElementException();
}
Object result = getRowData();
try {
hasNext = rs.next();
} catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
return result;
}
/**
* Removes from the underlying collection the last element returned
* by this iterator (optional operation). This method can be called
* only once per call to {@link #next}. The behavior of an iterator
* is unspecified if the underlying collection is modified while the
* iteration is in progress in any way other than by calling this
* method.
*
* @throws UnsupportedOperationException if the {@code remove}
* operation is not supported by this iterator
* @throws IllegalStateException if the {@code next} method has not
* yet been called, or the {@code remove} method has already
* been called after the last call to the {@code next}
* method
* @implSpec The default implementation throws an instance of
* {@link UnsupportedOperationException} and performs no other action.
*/
@Override
public void remove() {
throw new UnsupportedOperationException();
}
private Object getRowData() {
try {
java.sql.ResultSetMetaData metadata = rs.getMetaData();
OmtkRow row = new OmtkRow();
for (int i = 1; i <= metadata.getColumnCount(); i++) {
if (metadata.getColumnName(i).endsWith("_RXCUI")) {
row.setValue(metadata.getColumnName(i), new Code().withCode(((Integer)rs.getInt(i)).toString())
.withSystem(OmtkDataProvider.RXNORM));
}
row.setValue(metadata.getColumnName(i), rs.getObject(i));
}
return row;
}
catch (SQLException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
}

View File

@ -1,21 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.omtk;
import java.util.HashMap;
import java.util.Map;
/**
* Created by Bryn on 4/24/2017.
*/
public class OmtkRow {
private Map<String, Object> data = new HashMap<String, Object>();
public Object getValue(String key) {
return data.get(key);
}
public void setValue(String key, Object value) {
data.put(key, value);
}
}

View File

@ -1,148 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.providers;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import ca.uhn.fhir.rest.server.IResourceProvider;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.hl7.fhir.dstu3.model.*;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibrarySourceProvider;
import org.opencds.cqf.cql.data.fhir.FhirDataProviderStu3;
import org.opencds.cqf.cql.execution.Context;
import org.opencds.cqf.cql.execution.LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.helpers.LibraryHelper;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* Created by Bryn on 1/16/2017.
*/
public class CqlExecutionProvider {
private JpaDataProvider provider;
public CqlExecutionProvider(Collection<IResourceProvider> providers) {
this.provider = new JpaDataProvider(providers);
}
private ModelManager modelManager;
private ModelManager getModelManager() {
if (modelManager == null) {
modelManager = new ModelManager();
}
return modelManager;
}
private LibraryManager libraryManager;
private LibraryManager getLibraryManager() {
if (libraryManager == null) {
libraryManager = new LibraryManager(getModelManager());
libraryManager.getLibrarySourceLoader().clearProviders();
libraryManager.getLibrarySourceLoader().registerProvider(getLibrarySourceProvider());
}
return libraryManager;
}
private LibraryLoader libraryLoader;
private LibraryLoader getLibraryLoader() {
if (libraryLoader == null) {
libraryLoader = new STU3LibraryLoader(getLibraryResourceProvider(), getLibraryManager(), getModelManager());
}
return libraryLoader;
}
private STU3LibrarySourceProvider librarySourceProvider;
private STU3LibrarySourceProvider getLibrarySourceProvider() {
if (librarySourceProvider == null) {
librarySourceProvider = new STU3LibrarySourceProvider(getLibraryResourceProvider());
}
return librarySourceProvider;
}
private LibraryResourceProvider getLibraryResourceProvider() {
return (LibraryResourceProvider)provider.resolveResourceProvider("Library");
}
public static Iterable<Reference> getLibraryReferences(DomainResource instance) {
List<Reference> references = new ArrayList<>();
if (instance instanceof ActivityDefinition) {
references.addAll(((ActivityDefinition)instance).getLibrary());
}
else if (instance instanceof PlanDefinition) {
references.addAll(((PlanDefinition)instance).getLibrary());
}
else if (instance instanceof Measure) {
references.addAll(((Measure)instance).getLibrary());
}
for (Extension extension : instance.getExtensionsByUrl("http://hl7.org/fhir/StructureDefinition/cqif-library"))
{
Type value = extension.getValue();
if (value instanceof Reference) {
references.add((Reference)value);
}
else {
throw new RuntimeException("Library extension does not have a value of type reference");
}
}
return references;
}
private String buildIncludes(Iterable<Reference> references) {
StringBuilder builder = new StringBuilder();
for (Reference reference : references) {
if (builder.length() > 0) {
builder.append(" ");
}
// TODO: Would be nice not to have to resolve the reference here and just be able to specify the include...
Library library = getLibraryResourceProvider().getDao().read(new IdType(reference.getReference()));
builder.append("include ");
// TODO: This assumes the libraries resource id is the same as the library name, need to work this out better
builder.append(library.getIdElement().getIdPart());
if (library.getVersion() != null) {
builder.append(" version '");
builder.append(library.getVersion());
builder.append("'");
}
builder.append(" called ");
builder.append(library.getIdElement().getIdPart());
}
return builder.toString();
}
/* Evaluates the given CQL expression in the context of the given resource */
/* If the resource has a library extension, or a library element, that library is loaded into the context for the expression */
public Object evaluateInContext(DomainResource instance, String cql, String patientId) {
Iterable<Reference> libraries = getLibraryReferences(instance);
// Provide the instance as the value of the '%context' parameter, as well as the value of a parameter named the same as the resource
// This enables expressions to access the resource by root, as well as through the %context attribute
String source = String.format("library LocalLibrary using FHIR version '3.0.0' include FHIRHelpers version '3.0.0' called FHIRHelpers %s parameter %s %s parameter \"%%context\" %s define Expression: %s",
buildIncludes(libraries), instance.fhirType(), instance.fhirType(), instance.fhirType(), cql);
// String source = String.format("library LocalLibrary using FHIR version '1.8' include FHIRHelpers version '1.8' called FHIRHelpers %s parameter %s %s parameter \"%%context\" %s define Expression: %s",
// buildIncludes(libraries), instance.fhirType(), instance.fhirType(), instance.fhirType(), cql);
org.cqframework.cql.elm.execution.Library library = LibraryHelper.translateLibrary(source, getLibraryManager(), getModelManager());
Context context = new Context(library);
context.setParameter(null, instance.fhirType(), instance);
context.setParameter(null, "%context", instance);
context.setExpressionCaching(true);
context.registerLibraryLoader(getLibraryLoader());
context.setContextValue("Patient", patientId);
context.registerDataProvider("http://hl7.org/fhir", new FhirDataProviderStu3().setEndpoint("http://localhost:8080/cqf-ruler/baseDstu3"));
return context.resolveExpressionRef("Expression").evaluate(context);
}
}

View File

@ -1,462 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.providers;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.dstu3.JpaResourceProviderDstu3;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import ca.uhn.fhir.jpa.cqf.ruler.exceptions.ActivityDefinitionApplyException;
import java.util.*;
/**
* Created by Bryn on 1/16/2017.
*/
public class FHIRActivityDefinitionResourceProvider extends JpaResourceProviderDstu3<ActivityDefinition> {
private JpaDataProvider provider;
private CqlExecutionProvider executionProvider;
public FHIRActivityDefinitionResourceProvider(Collection<IResourceProvider> providers) {
this.provider = new JpaDataProvider(providers);
this.executionProvider = new CqlExecutionProvider(providers);
}
@Operation(name = "$apply", idempotent = true)
public Resource apply(@IdParam IdType theId, @RequiredParam(name="patient") String patientId,
@OptionalParam(name="encounter") String encounterId,
@OptionalParam(name="practitioner") String practitionerId,
@OptionalParam(name="organization") String organizationId,
@OptionalParam(name="userType") String userType,
@OptionalParam(name="userLanguage") String userLanguage,
@OptionalParam(name="userTaskContext") String userTaskContext,
@OptionalParam(name="setting") String setting,
@OptionalParam(name="settingContext") String settingContext)
throws InternalErrorException, FHIRException, ClassNotFoundException, IllegalAccessException,
InstantiationException, ActivityDefinitionApplyException
{
ActivityDefinition activityDefinition = this.getDao().read(theId);
Resource result = null;
try {
// This is a little hacky...
result = (Resource) Class.forName("org.hl7.fhir.dstu3.model." + activityDefinition.getKind().toCode()).newInstance();
}
catch (Exception e) {
e.printStackTrace();
throw new FHIRException("Could not find org.hl7.fhir.dstu3.model." + activityDefinition.getKind().toCode());
}
switch (result.fhirType()) {
case "ProcedureRequest":
result = resolveProcedureRequest(activityDefinition, patientId, practitionerId, organizationId);
break;
case "MedicationRequest":
result = resolveMedicationRequest(activityDefinition, patientId);
break;
case "SupplyRequest":
result = resolveSupplyRequest(activityDefinition, practitionerId, organizationId);
break;
case "Procedure":
result = resolveProcedure(activityDefinition, patientId);
break;
case "DiagnosticReport":
result = resolveDiagnosticReport(activityDefinition, patientId);
break;
case "Communication":
result = resolveCommunication(activityDefinition, patientId);
break;
}
// TODO: Apply expression extensions on any element?
for (ActivityDefinition.ActivityDefinitionDynamicValueComponent dynamicValue : activityDefinition.getDynamicValue())
{
if (dynamicValue.getExpression() != null) {
/*
TODO: Passing the activityDefinition as context here because that's what will have the libraries,
but perhaps the "context" here should be the result resource?
*/
Object value =
executionProvider.evaluateInContext(activityDefinition, dynamicValue.getExpression(), patientId);
// TODO need to verify type... yay
if (value instanceof Boolean) {
value = new BooleanType((Boolean) value);
}
this.provider.setValue(result, dynamicValue.getPath(), value);
}
}
return result;
}
private ProcedureRequest resolveProcedureRequest(ActivityDefinition activityDefinition, String patientId,
String practitionerId, String organizationId)
throws ActivityDefinitionApplyException
{
// status, intent, code, and subject are required
ProcedureRequest procedureRequest = new ProcedureRequest();
procedureRequest.setStatus(ProcedureRequest.ProcedureRequestStatus.DRAFT);
procedureRequest.setIntent(ProcedureRequest.ProcedureRequestIntent.ORDER);
procedureRequest.setSubject(new Reference(patientId));
if (practitionerId != null) {
procedureRequest.setRequester(
new ProcedureRequest.ProcedureRequestRequesterComponent()
.setAgent(new Reference(practitionerId))
);
}
else if (organizationId != null) {
procedureRequest.setRequester(
new ProcedureRequest.ProcedureRequestRequesterComponent()
.setAgent(new Reference(organizationId))
);
}
if (activityDefinition.hasExtension()) {
procedureRequest.setExtension(activityDefinition.getExtension());
}
if (activityDefinition.hasCode()) {
procedureRequest.setCode(activityDefinition.getCode());
}
// code can be set as a dynamicValue
else if (!activityDefinition.hasCode() && !activityDefinition.hasDynamicValue()) {
throw new ActivityDefinitionApplyException("Missing required code property");
}
if (activityDefinition.hasBodySite()) {
procedureRequest.setBodySite( activityDefinition.getBodySite());
}
if (activityDefinition.hasProduct()) {
throw new ActivityDefinitionApplyException("Product does not map to "+activityDefinition.getKind());
}
if (activityDefinition.hasDosage()) {
throw new ActivityDefinitionApplyException("Dosage does not map to "+activityDefinition.getKind());
}
return procedureRequest;
}
private MedicationRequest resolveMedicationRequest(ActivityDefinition activityDefinition, String patientId)
throws ActivityDefinitionApplyException
{
// intent, medication, and subject are required
MedicationRequest medicationRequest = new MedicationRequest();
medicationRequest.setIntent(MedicationRequest.MedicationRequestIntent.ORDER);
medicationRequest.setSubject(new Reference(patientId));
if (activityDefinition.hasProduct()) {
medicationRequest.setMedication( activityDefinition.getProduct());
}
else {
throw new ActivityDefinitionApplyException("Missing required product property");
}
if (activityDefinition.hasDosage()) {
medicationRequest.setDosageInstruction( activityDefinition.getDosage());
}
if (activityDefinition.hasBodySite()) {
throw new ActivityDefinitionApplyException("Bodysite does not map to " + activityDefinition.getKind());
}
if (activityDefinition.hasCode()) {
throw new ActivityDefinitionApplyException("Code does not map to " + activityDefinition.getKind());
}
if (activityDefinition.hasQuantity()) {
throw new ActivityDefinitionApplyException("Quantity does not map to " + activityDefinition.getKind());
}
return medicationRequest;
}
private SupplyRequest resolveSupplyRequest(ActivityDefinition activityDefinition, String practionerId,
String organizationId) throws ActivityDefinitionApplyException
{
SupplyRequest supplyRequest = new SupplyRequest();
if (practionerId != null) {
supplyRequest.setRequester(
new SupplyRequest.SupplyRequestRequesterComponent()
.setAgent(new Reference(practionerId))
);
}
if (organizationId != null) {
supplyRequest.setRequester(
new SupplyRequest.SupplyRequestRequesterComponent()
.setAgent(new Reference(organizationId))
);
}
if (activityDefinition.hasQuantity()){
supplyRequest.setOrderedItem(
new SupplyRequest.SupplyRequestOrderedItemComponent()
.setQuantity( activityDefinition.getQuantity())
);
}
else {
throw new ActivityDefinitionApplyException("Missing required orderedItem.quantity property");
}
if (activityDefinition.hasCode()) {
supplyRequest.getOrderedItem().setItem(activityDefinition.getCode());
}
if (activityDefinition.hasProduct()) {
throw new ActivityDefinitionApplyException("Product does not map to "+activityDefinition.getKind());
}
if (activityDefinition.hasDosage()) {
throw new ActivityDefinitionApplyException("Dosage does not map to "+activityDefinition.getKind());
}
if (activityDefinition.hasBodySite()) {
throw new ActivityDefinitionApplyException("Bodysite does not map to "+activityDefinition.getKind());
}
return supplyRequest;
}
private Procedure resolveProcedure(ActivityDefinition activityDefinition, String patientId) {
Procedure procedure = new Procedure();
// TODO - set the appropriate status
procedure.setStatus(Procedure.ProcedureStatus.UNKNOWN);
procedure.setSubject(new Reference(patientId));
if (activityDefinition.hasCode()) {
procedure.setCode(activityDefinition.getCode());
}
if (activityDefinition.hasBodySite()) {
procedure.setBodySite(activityDefinition.getBodySite());
}
return procedure;
}
private DiagnosticReport resolveDiagnosticReport(ActivityDefinition activityDefinition, String patientId) {
DiagnosticReport diagnosticReport = new DiagnosticReport();
diagnosticReport.setStatus(DiagnosticReport.DiagnosticReportStatus.UNKNOWN);
diagnosticReport.setSubject(new Reference(patientId));
if (activityDefinition.hasCode()) {
diagnosticReport.setCode(activityDefinition.getCode());
}
else {
throw new ActivityDefinitionApplyException("Missing required ActivityDefinition.code property for DiagnosticReport");
}
if (activityDefinition.hasRelatedArtifact()) {
List<Attachment> presentedFormAttachments = new ArrayList<>();
for (RelatedArtifact artifact : activityDefinition.getRelatedArtifact()) {
Attachment attachment = new Attachment();
if (artifact.hasUrl()) {
attachment.setUrl(artifact.getUrl());
}
if (artifact.hasDisplay()) {
attachment.setTitle(artifact.getDisplay());
}
presentedFormAttachments.add(attachment);
}
diagnosticReport.setPresentedForm(presentedFormAttachments);
}
return diagnosticReport;
}
private Communication resolveCommunication(ActivityDefinition activityDefinition, String patientId) {
Communication communication = new Communication();
communication.setStatus(Communication.CommunicationStatus.UNKNOWN);
communication.setSubject(new Reference(patientId));
if (activityDefinition.hasCode()) {
communication.setReasonCode(Collections.singletonList(activityDefinition.getCode()));
}
if (activityDefinition.hasRelatedArtifact()) {
for (RelatedArtifact artifact : activityDefinition.getRelatedArtifact()) {
if (artifact.hasUrl()) {
Attachment attachment = new Attachment().setUrl(artifact.getUrl());
if (artifact.hasDisplay()) {
attachment.setTitle(artifact.getDisplay());
}
Communication.CommunicationPayloadComponent payload = new Communication.CommunicationPayloadComponent();
payload.setContent(artifact.hasDisplay() ? attachment.setTitle(artifact.getDisplay()) : attachment);
communication.setPayload(Collections.singletonList(payload));
}
// TODO - other relatedArtifact types
}
}
return communication;
}
@Search(allowUnknownParams=true)
public IBundleProvider search(
javax.servlet.http.HttpServletRequest theServletRequest,
RequestDetails theRequestDetails,
@Description(shortDefinition="Search the contents of the resource's data using a fulltext search")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT)
StringAndListParam theFtContent,
@Description(shortDefinition="Search the contents of the resource's narrative using a fulltext search")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TEXT)
StringAndListParam theFtText,
@Description(shortDefinition="Search for resources which have the given tag")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TAG)
TokenAndListParam theSearchForTag,
@Description(shortDefinition="Search for resources which have the given security labels")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_SECURITY)
TokenAndListParam theSearchForSecurity,
@Description(shortDefinition="Search for resources which have the given profile")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_PROFILE)
UriAndListParam theSearchForProfile,
@Description(shortDefinition="Return resources linked to by the given target")
@OptionalParam(name="_has")
HasAndListParam theHas,
@Description(shortDefinition="The ID of the resource")
@OptionalParam(name="_id")
TokenAndListParam the_id,
@Description(shortDefinition="The language of the resource")
@OptionalParam(name="_language")
StringAndListParam the_language,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="composed-of", targetTypes={ } )
ReferenceAndListParam theComposed_of,
@Description(shortDefinition="The activity definition publication date")
@OptionalParam(name="date")
DateRangeParam theDate,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="depends-on", targetTypes={ } )
ReferenceAndListParam theDepends_on,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="derived-from", targetTypes={ } )
ReferenceAndListParam theDerived_from,
@Description(shortDefinition="The description of the activity definition")
@OptionalParam(name="description")
StringAndListParam theDescription,
@Description(shortDefinition="The time during which the activity definition is intended to be in use")
@OptionalParam(name="effective")
DateRangeParam theEffective,
@Description(shortDefinition="External identifier for the activity definition")
@OptionalParam(name="identifier")
TokenAndListParam theIdentifier,
@Description(shortDefinition="Intended jurisdiction for the activity definition")
@OptionalParam(name="jurisdiction")
TokenAndListParam theJurisdiction,
@Description(shortDefinition="Computationally friendly name of the activity definition")
@OptionalParam(name="name")
StringAndListParam theName,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="predecessor", targetTypes={ } )
ReferenceAndListParam thePredecessor,
@Description(shortDefinition="Name of the publisher of the activity definition")
@OptionalParam(name="publisher")
StringAndListParam thePublisher,
@Description(shortDefinition="The current status of the activity definition")
@OptionalParam(name="status")
TokenAndListParam theStatus,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="successor", targetTypes={ } )
ReferenceAndListParam theSuccessor,
@Description(shortDefinition="The human-friendly name of the activity definition")
@OptionalParam(name="title")
StringAndListParam theTitle,
@Description(shortDefinition="Topics associated with the module")
@OptionalParam(name="topic")
TokenAndListParam theTopic,
@Description(shortDefinition="The uri that identifies the activity definition")
@OptionalParam(name="url")
UriAndListParam theUrl,
@Description(shortDefinition="The business version of the activity definition")
@OptionalParam(name="version")
TokenAndListParam theVersion,
@RawParam
Map<String, List<String>> theAdditionalRawParams,
@IncludeParam(reverse=true)
Set<Include> theRevIncludes,
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
@OptionalParam(name="_lastUpdated")
DateRangeParam theLastUpdated,
@IncludeParam(allow= {
"ActivityDefinition:composed-of" , "ActivityDefinition:depends-on" , "ActivityDefinition:derived-from" , "ActivityDefinition:predecessor" , "ActivityDefinition:successor" , "ActivityDefinition:composed-of" , "ActivityDefinition:depends-on" , "ActivityDefinition:derived-from" , "ActivityDefinition:predecessor" , "ActivityDefinition:successor" , "ActivityDefinition:composed-of" , "ActivityDefinition:depends-on" , "ActivityDefinition:derived-from" , "ActivityDefinition:predecessor" , "ActivityDefinition:successor" , "ActivityDefinition:composed-of" , "ActivityDefinition:depends-on" , "ActivityDefinition:derived-from" , "ActivityDefinition:predecessor" , "ActivityDefinition:successor" , "ActivityDefinition:composed-of" , "ActivityDefinition:depends-on" , "ActivityDefinition:derived-from" , "ActivityDefinition:predecessor" , "ActivityDefinition:successor" , "*"
})
Set<Include> theIncludes,
@Sort
SortSpec theSort,
@ca.uhn.fhir.rest.annotation.Count
Integer theCount
) {
startRequest(theServletRequest);
try {
SearchParameterMap paramMap = new SearchParameterMap();
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, theFtContent);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, theFtText);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TAG, theSearchForTag);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_SECURITY, theSearchForSecurity);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_PROFILE, theSearchForProfile);
paramMap.add("_has", theHas);
paramMap.add("_id", the_id);
paramMap.add("_language", the_language);
paramMap.add("composed-of", theComposed_of);
paramMap.add("date", theDate);
paramMap.add("depends-on", theDepends_on);
paramMap.add("derived-from", theDerived_from);
paramMap.add("description", theDescription);
paramMap.add("effective", theEffective);
paramMap.add("identifier", theIdentifier);
paramMap.add("jurisdiction", theJurisdiction);
paramMap.add("name", theName);
paramMap.add("predecessor", thePredecessor);
paramMap.add("publisher", thePublisher);
paramMap.add("status", theStatus);
paramMap.add("successor", theSuccessor);
paramMap.add("title", theTitle);
paramMap.add("topic", theTopic);
paramMap.add("url", theUrl);
paramMap.add("version", theVersion);
paramMap.setRevIncludes(theRevIncludes);
paramMap.setLastUpdated(theLastUpdated);
paramMap.setIncludes(theIncludes);
paramMap.setSort(theSort);
paramMap.setCount(theCount);
// paramMap.setRequestDetails(theRequestDetails);
getDao().translateRawParameters(theAdditionalRawParams, paramMap);
return getDao().search(paramMap, theRequestDetails);
} finally {
endRequest(theServletRequest);
}
}
}

View File

@ -1,494 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.providers;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.dstu3.JpaResourceProviderDstu3;
import ca.uhn.fhir.jpa.rp.dstu3.CodeSystemResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.PatientResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.ValueSetResourceProvider;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.cqframework.cql.cql2elm.LibraryManager;
import org.cqframework.cql.cql2elm.ModelManager;
import org.cqframework.cql.elm.execution.Library;
import org.cqframework.cql.elm.execution.VersionedIdentifier;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import org.hl7.fhir.instance.model.api.IBaseResource;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibraryLoader;
import ca.uhn.fhir.jpa.cqf.ruler.config.STU3LibrarySourceProvider;
import org.opencds.cqf.cql.execution.Context;
import org.opencds.cqf.cql.execution.LibraryLoader;
import org.opencds.cqf.cql.runtime.Interval;
import org.opencds.cqf.cql.terminology.TerminologyProvider;
import org.opencds.cqf.cql.terminology.fhir.FhirTerminologyProvider;
import ca.uhn.fhir.jpa.cqf.ruler.helpers.DateHelper;
import ca.uhn.fhir.jpa.cqf.ruler.helpers.FhirMeasureEvaluator;
import java.util.*;
/*
IN periodStart 1..1 date
The start of the measurement period. In keeping with the semantics of the date parameter used in the FHIR search operation, the period will start at the beginning of the period implied by the supplied timestamp. E.g. a value of 2014 would set the period start to be 2014-01-01T00:00:00 inclusive
IN periodEnd 1..1 date
The end of the measurement period. The period will end at the end of the period implied by the supplied timestamp. E.g. a value of 2014 would set the period end to be 2014-12-31T23:59:59 inclusive
IN measure 0..1 Reference
The measure to evaluate. This parameter is only required when the operation is invoked on the resource type, it is not used when invoking the operation on a Measure instance
IN reportType 0..1 code
The type of measure report, patient, patient-list, or population. If not specified, a default value of patient will be used if the patient parameter is supplied, otherwise, population will be used
IN patient 0..1 Reference
Patient to evaluate against. If not specified, the measure will be evaluated for all patients that meet the requirements of the measure. If specified, only the referenced patient will be evaluated
IN practitioner 0..1 Reference
Practitioner to evaluate. If specified, the measure will be evaluated only for patients whose primary practitioner is the identified practitioner
IN lastReceivedOn 0..1 dateTime
The date the results of this measure were last received. This parameter is only valid for patient-level reports and is used to indicate when the last time a result for this patient was received. This information can be used to limit the set of resources returned for a patient-level report
OUT return 1..1 MeasureReport
The results of the measure calculation. See the MeasureReport resource for a complete description of the output of this operation
*/
public class FHIRMeasureResourceProvider extends JpaResourceProviderDstu3<Measure> {
private JpaDataProvider provider;
private TerminologyProvider terminologyProvider;
private Context context;
private Interval measurementPeriod;
private MeasureReport report = new MeasureReport();
private FhirMeasureEvaluator evaluator = new FhirMeasureEvaluator();
public FHIRMeasureResourceProvider(Collection<IResourceProvider> providers) {
this.provider = new JpaDataProvider(providers);
}
private LibraryResourceProvider getLibraryResourceProvider() {
return (LibraryResourceProvider)provider.resolveResourceProvider("Library");
}
private ModelManager modelManager;
private ModelManager getModelManager() {
if (modelManager == null) {
modelManager = new ModelManager();
}
return modelManager;
}
private LibraryManager libraryManager;
private LibraryManager getLibraryManager() {
if (libraryManager == null) {
libraryManager = new LibraryManager(getModelManager());
libraryManager.getLibrarySourceLoader().clearProviders();
libraryManager.getLibrarySourceLoader().registerProvider(getLibrarySourceProvider());
}
return libraryManager;
}
private LibraryLoader libraryLoader;
private LibraryLoader getLibraryLoader() {
if (libraryLoader == null) {
libraryLoader = new STU3LibraryLoader(getLibraryResourceProvider(), getLibraryManager(), getModelManager());
}
return libraryLoader;
}
private STU3LibrarySourceProvider librarySourceProvider;
private STU3LibrarySourceProvider getLibrarySourceProvider() {
if (librarySourceProvider == null) {
librarySourceProvider = new STU3LibrarySourceProvider(getLibraryResourceProvider());
}
return librarySourceProvider;
}
/*
This is not "pure" FHIR.
The "source", "user", "pass", and "primaryLibraryName" parameters were added to simplify the operation.
*/
@Operation(name = "$evaluate", idempotent = true)
public MeasureReport evaluateMeasure(
@IdParam IdType theId,
@OptionalParam(name="reportType") String reportType,
@OptionalParam(name="patient") String patientId,
@OptionalParam(name="practitioner") String practitioner,
@OptionalParam(name="lastReceivedOn") String lastReceivedOn,
@RequiredParam(name="startPeriod") String startPeriod,
@RequiredParam(name="endPeriod") String endPeriod,
@OptionalParam(name="source") String source,
@OptionalParam(name="user") String user,
@OptionalParam(name="pass") String pass,
@OptionalParam(name="primaryLibraryName") String primaryLibraryName) throws InternalErrorException, FHIRException
{
Measure measure = this.getDao().read(theId);
// load libraries referenced in measure
// TODO: need better way to determine primary library
// - for now using a name convention: <measure ID>-library or primaryLibraryName param
Library primary = null;
for (Reference ref : measure.getLibrary()) {
VersionedIdentifier vid = new VersionedIdentifier().withId(ref.getReference());
Library temp = getLibraryLoader().load(vid);
if (vid.getId().equals(measure.getIdElement().getIdPart() + "-logic")
|| vid.getId().equals("Library/" + measure.getIdElement().getIdPart() + "-logic")
|| (primaryLibraryName != null && temp.getIdentifier().getId().equals(primaryLibraryName)))
{
primary = temp;
context = new Context(primary);
}
}
if (primary == null) {
throw new IllegalArgumentException(
"Primary library not found.\nFollow the naming conventions <measureID>-library or specify primary library in request."
);
}
if (((STU3LibraryLoader)getLibraryLoader()).getLibraries().isEmpty()) {
throw new IllegalArgumentException(String.format("Could not load library source for libraries referenced in %s measure.", measure.getId()));
}
// Prep - defining the context, measurementPeriod, terminology provider, and data provider
context.registerLibraryLoader(getLibraryLoader());
measurementPeriod =
new Interval(
DateHelper.resolveRequestDate(startPeriod, true), true,
DateHelper.resolveRequestDate(endPeriod, false), true
);
if (source == null) {
JpaResourceProviderDstu3<ValueSet> vs = (ValueSetResourceProvider) provider.resolveResourceProvider("ValueSet");
JpaResourceProviderDstu3<CodeSystem> cs = (CodeSystemResourceProvider) provider.resolveResourceProvider("CodeSystem");
terminologyProvider = new JpaTerminologyProvider(vs, cs);
}
else {
terminologyProvider = user == null || pass == null ? new FhirTerminologyProvider().withEndpoint(source)
: new FhirTerminologyProvider().withBasicAuth(user, pass).withEndpoint(source);
}
provider.setTerminologyProvider(terminologyProvider);
provider.setExpandValueSets(true);
context.registerDataProvider("http://hl7.org/fhir", provider);
// determine the report type (patient, patient-list, or population (summary))
if (reportType != null) {
switch (reportType) {
case "patient": return evaluatePatientMeasure(measure, patientId);
case "patient-list": return evaluatePatientListMeasure(measure, practitioner);
case "population": return evaluatePopulationMeasure(measure);
case "summary": return evaluatePopulationMeasure(measure);
default:
throw new IllegalArgumentException("Invalid report type " + reportType);
}
}
// default behavior
else {
if (patientId != null) return evaluatePatientMeasure(measure, patientId);
if (practitioner != null) return evaluatePatientListMeasure(measure, practitioner);
return evaluatePopulationMeasure(measure);
}
}
private void validateReport() {
if (report == null) {
throw new InternalErrorException("MeasureReport is null");
}
if (report.getEvaluatedResources() == null) {
throw new InternalErrorException("EvaluatedResources is null");
}
}
private MeasureReport evaluatePatientMeasure(Measure measure, String patientId) {
if (patientId == null) {
throw new IllegalArgumentException("Patient id must be provided for patient type measure evaluation");
}
Patient patient = ((PatientResourceProvider) provider.resolveResourceProvider("Patient")).getDao().read(new IdType(patientId));
if (patient == null) {
throw new InternalErrorException("Patient is null");
}
context.setContextValue("Patient", patientId);
report = evaluator.evaluate(context, measure, patient, measurementPeriod);
validateReport();
return report;
}
private MeasureReport evaluatePatientListMeasure(Measure measure, String practitioner) {
SearchParameterMap map = new SearchParameterMap();
map.add("general-practitioner", new ReferenceParam(practitioner));
IBundleProvider patientProvider = ((PatientResourceProvider) provider.resolveResourceProvider("Patient")).getDao().search(map);
List<IBaseResource> patientList = patientProvider.getResources(0, patientProvider.size());
if (patientList.isEmpty()) {
throw new IllegalArgumentException("No patients were found with practitioner reference " + practitioner);
}
List<Patient> patients = new ArrayList<>();
patientList.forEach(x -> patients.add((Patient) x));
// context.setContextValue("Population", patients);
report = evaluator.evaluate(context, measure, patients, measurementPeriod, MeasureReport.MeasureReportType.PATIENTLIST);
validateReport();
return report;
}
private MeasureReport evaluatePopulationMeasure(Measure measure) {
IBundleProvider patientProvider = ((PatientResourceProvider) provider.resolveResourceProvider("Patient")).getDao().search(new SearchParameterMap());
List<IBaseResource> population = patientProvider.getResources(0, patientProvider.size());
if (population.isEmpty()) {
throw new IllegalArgumentException("No patients were found in the data provider at endpoint " + provider.getEndpoint());
}
List<Patient> patients = new ArrayList<>();
population.forEach(x -> patients.add((Patient) x));
report = evaluator.evaluate(context, measure, patients, measurementPeriod, MeasureReport.MeasureReportType.SUMMARY);
validateReport();
return report;
}
@Operation(name = "$data-requirements", idempotent = true)
public org.hl7.fhir.dstu3.model.Library dataRequirements(@IdParam IdType theId,
@RequiredParam(name="startPeriod") String startPeriod,
@RequiredParam(name="endPeriod") String endPeriod)
throws InternalErrorException, FHIRException
{
Measure measure = this.getDao().read(theId);
// NOTE: This assumes there is only one library and it is the primary library for the measure.
org.hl7.fhir.dstu3.model.Library libraryResource =
getLibraryResourceProvider()
.getDao()
.read(new IdType(measure.getLibraryFirstRep().getReference()));
// TODO: what are the period params for? Library.effectivePeriod?
List<RelatedArtifact> dependencies = new ArrayList<>();
for (RelatedArtifact dependency : libraryResource.getRelatedArtifact()) {
if (dependency.getType().toCode().equals("depends-on")) {
dependencies.add(dependency);
}
}
List<Coding> typeCoding = new ArrayList<>();
typeCoding.add(new Coding().setCode("module-definition"));
org.hl7.fhir.dstu3.model.Library library =
new org.hl7.fhir.dstu3.model.Library().setType(new CodeableConcept().setCoding(typeCoding));
if (!dependencies.isEmpty()) {
library.setRelatedArtifact(dependencies);
}
return library
.setDataRequirement(libraryResource.getDataRequirement())
.setParameter(libraryResource.getParameter());
}
@Search(allowUnknownParams=true)
public IBundleProvider search(
javax.servlet.http.HttpServletRequest theServletRequest,
RequestDetails theRequestDetails,
@Description(shortDefinition="Search the contents of the resource's data using a fulltext search")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT)
StringAndListParam theFtContent,
@Description(shortDefinition="Search the contents of the resource's narrative using a fulltext search")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TEXT)
StringAndListParam theFtText,
@Description(shortDefinition="Search for resources which have the given tag")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TAG)
TokenAndListParam theSearchForTag,
@Description(shortDefinition="Search for resources which have the given security labels")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_SECURITY)
TokenAndListParam theSearchForSecurity,
@Description(shortDefinition="Search for resources which have the given profile")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_PROFILE)
UriAndListParam theSearchForProfile,
@Description(shortDefinition="Return resources linked to by the given target")
@OptionalParam(name="_has")
HasAndListParam theHas,
@Description(shortDefinition="The ID of the resource")
@OptionalParam(name="_id")
TokenAndListParam the_id,
@Description(shortDefinition="The language of the resource")
@OptionalParam(name="_language")
StringAndListParam the_language,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="composed-of", targetTypes={ } )
ReferenceAndListParam theComposed_of,
@Description(shortDefinition="The measure publication date")
@OptionalParam(name="date")
DateRangeParam theDate,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="depends-on", targetTypes={ } )
ReferenceAndListParam theDepends_on,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="derived-from", targetTypes={ } )
ReferenceAndListParam theDerived_from,
@Description(shortDefinition="The description of the measure")
@OptionalParam(name="description")
StringAndListParam theDescription,
@Description(shortDefinition="The time during which the measure is intended to be in use")
@OptionalParam(name="effective")
DateRangeParam theEffective,
@Description(shortDefinition="External identifier for the measure")
@OptionalParam(name="identifier")
TokenAndListParam theIdentifier,
@Description(shortDefinition="Intended jurisdiction for the measure")
@OptionalParam(name="jurisdiction")
TokenAndListParam theJurisdiction,
@Description(shortDefinition="Computationally friendly name of the measure")
@OptionalParam(name="name")
StringAndListParam theName,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="predecessor", targetTypes={ } )
ReferenceAndListParam thePredecessor,
@Description(shortDefinition="Name of the publisher of the measure")
@OptionalParam(name="publisher")
StringAndListParam thePublisher,
@Description(shortDefinition="The current status of the measure")
@OptionalParam(name="status")
TokenAndListParam theStatus,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="successor", targetTypes={ } )
ReferenceAndListParam theSuccessor,
@Description(shortDefinition="The human-friendly name of the measure")
@OptionalParam(name="title")
StringAndListParam theTitle,
@Description(shortDefinition="Topics associated with the module")
@OptionalParam(name="topic")
TokenAndListParam theTopic,
@Description(shortDefinition="The uri that identifies the measure")
@OptionalParam(name="url")
UriAndListParam theUrl,
@Description(shortDefinition="The business version of the measure")
@OptionalParam(name="version")
TokenAndListParam theVersion,
@RawParam
Map<String, List<String>> theAdditionalRawParams,
@IncludeParam(reverse=true)
Set<Include> theRevIncludes,
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
@OptionalParam(name="_lastUpdated")
DateRangeParam theLastUpdated,
@IncludeParam(allow= {
"Measure:composed-of",
"Measure:depends-on",
"Measure:derived-from",
"Measure:predecessor",
"Measure:successor",
"Measure:composed-of",
"Measure:depends-on",
"Measure:derived-from",
"Measure:predecessor",
"Measure:successor",
"Measure:composed-of",
"Measure:depends-on",
"Measure:derived-from",
"Measure:predecessor",
"Measure:successor",
"Measure:composed-of",
"Measure:depends-on",
"Measure:derived-from",
"Measure:predecessor",
"Measure:successor",
"Measure:composed-of",
"Measure:depends-on",
"Measure:derived-from",
"Measure:predecessor",
"Measure:successor",
"*"
})
Set<Include> theIncludes,
@Sort
SortSpec theSort,
@ca.uhn.fhir.rest.annotation.Count
Integer theCount
) {
startRequest(theServletRequest);
try {
SearchParameterMap paramMap = new SearchParameterMap();
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, theFtContent);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, theFtText);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TAG, theSearchForTag);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_SECURITY, theSearchForSecurity);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_PROFILE, theSearchForProfile);
paramMap.add("_has", theHas);
paramMap.add("_id", the_id);
paramMap.add("_language", the_language);
paramMap.add("composed-of", theComposed_of);
paramMap.add("date", theDate);
paramMap.add("depends-on", theDepends_on);
paramMap.add("derived-from", theDerived_from);
paramMap.add("description", theDescription);
paramMap.add("effective", theEffective);
paramMap.add("identifier", theIdentifier);
paramMap.add("jurisdiction", theJurisdiction);
paramMap.add("name", theName);
paramMap.add("predecessor", thePredecessor);
paramMap.add("publisher", thePublisher);
paramMap.add("status", theStatus);
paramMap.add("successor", theSuccessor);
paramMap.add("title", theTitle);
paramMap.add("topic", theTopic);
paramMap.add("url", theUrl);
paramMap.add("version", theVersion);
paramMap.setRevIncludes(theRevIncludes);
paramMap.setLastUpdated(theLastUpdated);
paramMap.setIncludes(theIncludes);
paramMap.setSort(theSort);
paramMap.setCount(theCount);
// paramMap.setRequestDetails(theRequestDetails);
getDao().translateRawParameters(theAdditionalRawParams, paramMap);
return getDao().search(paramMap, theRequestDetails);
} finally {
endRequest(theServletRequest);
}
}
}

View File

@ -1,295 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.providers;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.dstu3.JpaResourceProviderDstu3;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.rest.annotation.*;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.api.server.RequestDetails;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.IResourceProvider;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import ca.uhn.fhir.jpa.cqf.ruler.builders.CarePlanBuilder;
import ca.uhn.fhir.jpa.cqf.ruler.builders.JavaDateBuilder;
import org.opencds.cqf.cql.runtime.DateTime;
import javax.xml.bind.JAXBException;
import java.io.IOException;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class FHIRPlanDefinitionResourceProvider extends JpaResourceProviderDstu3<PlanDefinition> {
private JpaDataProvider provider;
private CqlExecutionProvider executionProvider;
public FHIRPlanDefinitionResourceProvider(Collection<IResourceProvider> providers) {
this.provider = new JpaDataProvider(providers);
this.executionProvider = new CqlExecutionProvider(providers);
}
@Operation(name = "$apply", idempotent = true)
public CarePlan applyPlanDefinition(
@IdParam IdType theId,
@RequiredParam(name="patient") String patientId,
@OptionalParam(name="encounter") String encounterId,
@OptionalParam(name="practitioner") String practitionerId,
@OptionalParam(name="organization") String organizationId,
@OptionalParam(name="userType") String userType,
@OptionalParam(name="userLanguage") String userLanguage,
@OptionalParam(name="userTaskContext") String userTaskContext,
@OptionalParam(name="setting") String setting,
@OptionalParam(name="settingContext") String settingContext)
throws IOException, JAXBException, FHIRException
{
PlanDefinition planDefinition = this.getDao().read(theId);
if (planDefinition == null) {
throw new IllegalArgumentException("Couldn't find PlanDefintion " + theId);
}
CarePlanBuilder builder = new CarePlanBuilder();
builder
.buildDefinition(new Reference(planDefinition.getIdElement().getIdPart()))
.buildSubject(new Reference(patientId))
.buildStatus(CarePlan.CarePlanStatus.DRAFT);
if (encounterId != null) builder.buildContext(new Reference(encounterId));
if (practitionerId != null) builder.buildAuthor(new Reference(practitionerId));
if (organizationId != null) builder.buildAuthor(new Reference(organizationId));
if (userLanguage != null) builder.buildLanguage(userLanguage);
return resolveActions(planDefinition, builder, patientId);
}
private CarePlan resolveActions(PlanDefinition planDefinition, CarePlanBuilder builder,
String patientId) throws FHIRException
{
for (PlanDefinition.PlanDefinitionActionComponent action : planDefinition.getAction())
{
// TODO - Apply input/output dataRequirements?
if (meetsConditions(planDefinition, patientId, action)) {
return resolveDynamicValues(planDefinition, builder.build(), patientId, action);
}
}
return builder.build();
}
public Boolean meetsConditions(PlanDefinition planDefinition, String patientId,
PlanDefinition.PlanDefinitionActionComponent action)
{
for (PlanDefinition.PlanDefinitionActionConditionComponent condition: action.getCondition()) {
// TODO start
// TODO stop
if (condition.getKind() == PlanDefinition.ActionConditionKind.APPLICABILITY) {
if (!condition.getLanguage().equals("text/cql")) {
// TODO - log this
continue;
}
if (!condition.hasExpression()) {
// TODO - log this
continue;
}
String cql = condition.getExpression();
Object result = executionProvider.evaluateInContext(planDefinition, cql, patientId);
if (!(result instanceof Boolean)) {
// TODO - log this
// maybe try an int value check (i.e. 0 or 1)?
continue;
}
if (!(Boolean) result) {
return false;
}
}
}
return true;
}
private CarePlan resolveDynamicValues(PlanDefinition planDefinition, CarePlan carePlan, String patientId,
PlanDefinition.PlanDefinitionActionComponent action) throws FHIRException
{
for (PlanDefinition.PlanDefinitionActionDynamicValueComponent dynamicValue: action.getDynamicValue())
{
if (dynamicValue.hasExpression()) {
Object result =
executionProvider
.evaluateInContext(planDefinition, dynamicValue.getExpression(), patientId);
if (dynamicValue.hasPath() && dynamicValue.getPath().equals("$this"))
{
carePlan = (CarePlan) result;
}
else {
// TODO - likely need more date tranformations
if (result instanceof DateTime) {
result =
new JavaDateBuilder()
.buildFromDateTime((DateTime) result)
.build();
}
else if (result instanceof String) {
result = new StringType((String) result);
}
provider.setValue(carePlan, dynamicValue.getPath(), result);
}
}
}
return carePlan;
}
@Search(allowUnknownParams=true)
public IBundleProvider search(
javax.servlet.http.HttpServletRequest theServletRequest,
RequestDetails theRequestDetails,
@Description(shortDefinition="Search the contents of the resource's data using a fulltext search")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT)
StringAndListParam theFtContent,
@Description(shortDefinition="Search the contents of the resource's narrative using a fulltext search")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TEXT)
StringAndListParam theFtText,
@Description(shortDefinition="Search for resources which have the given tag")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_TAG)
TokenAndListParam theSearchForTag,
@Description(shortDefinition="Search for resources which have the given security labels")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_SECURITY)
TokenAndListParam theSearchForSecurity,
@Description(shortDefinition="Search for resources which have the given profile")
@OptionalParam(name=ca.uhn.fhir.rest.api.Constants.PARAM_PROFILE)
UriAndListParam theSearchForProfile,
@Description(shortDefinition="Return resources linked to by the given target")
@OptionalParam(name="_has")
HasAndListParam theHas,
@Description(shortDefinition="The ID of the resource")
@OptionalParam(name="_id")
TokenAndListParam the_id,
@Description(shortDefinition="The language of the resource")
@OptionalParam(name="_language")
StringAndListParam the_language,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="composed-of", targetTypes={ } )
ReferenceAndListParam theComposed_of,
@Description(shortDefinition="The plan definition publication date")
@OptionalParam(name="date")
DateRangeParam theDate,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="depends-on", targetTypes={ } )
ReferenceAndListParam theDepends_on,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="derived-from", targetTypes={ } )
ReferenceAndListParam theDerived_from,
@Description(shortDefinition="The description of the plan definition")
@OptionalParam(name="description")
StringAndListParam theDescription,
@Description(shortDefinition="The time during which the plan definition is intended to be in use")
@OptionalParam(name="effective")
DateRangeParam theEffective,
@Description(shortDefinition="External identifier for the plan definition")
@OptionalParam(name="identifier")
TokenAndListParam theIdentifier,
@Description(shortDefinition="Intended jurisdiction for the plan definition")
@OptionalParam(name="jurisdiction")
TokenAndListParam theJurisdiction,
@Description(shortDefinition="Computationally friendly name of the plan definition")
@OptionalParam(name="name")
StringAndListParam theName,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="predecessor", targetTypes={ } )
ReferenceAndListParam thePredecessor,
@Description(shortDefinition="Name of the publisher of the plan definition")
@OptionalParam(name="publisher")
StringAndListParam thePublisher,
@Description(shortDefinition="The current status of the plan definition")
@OptionalParam(name="status")
TokenAndListParam theStatus,
@Description(shortDefinition="What resource is being referenced")
@OptionalParam(name="successor", targetTypes={ } )
ReferenceAndListParam theSuccessor,
@Description(shortDefinition="The human-friendly name of the plan definition")
@OptionalParam(name="title")
StringAndListParam theTitle,
@Description(shortDefinition="Topics associated with the module")
@OptionalParam(name="topic")
TokenAndListParam theTopic,
@Description(shortDefinition="The uri that identifies the plan definition")
@OptionalParam(name="url")
UriAndListParam theUrl,
@Description(shortDefinition="The business version of the plan definition")
@OptionalParam(name="version")
TokenAndListParam theVersion,
@RawParam
Map<String, List<String>> theAdditionalRawParams,
@IncludeParam(reverse=true)
Set<Include> theRevIncludes,
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
@OptionalParam(name="_lastUpdated")
DateRangeParam theLastUpdated,
@IncludeParam(allow= {
"PlanDefinition:composed-of" , "PlanDefinition:depends-on" , "PlanDefinition:derived-from" , "PlanDefinition:predecessor" , "PlanDefinition:successor" , "PlanDefinition:composed-of" , "PlanDefinition:depends-on" , "PlanDefinition:derived-from" , "PlanDefinition:predecessor" , "PlanDefinition:successor" , "PlanDefinition:composed-of" , "PlanDefinition:depends-on" , "PlanDefinition:derived-from" , "PlanDefinition:predecessor" , "PlanDefinition:successor" , "PlanDefinition:composed-of" , "PlanDefinition:depends-on" , "PlanDefinition:derived-from" , "PlanDefinition:predecessor" , "PlanDefinition:successor" , "PlanDefinition:composed-of" , "PlanDefinition:depends-on" , "PlanDefinition:derived-from" , "PlanDefinition:predecessor" , "PlanDefinition:successor" , "*"
})
Set<Include> theIncludes,
@Sort
SortSpec theSort,
@ca.uhn.fhir.rest.annotation.Count
Integer theCount
) {
startRequest(theServletRequest);
try {
SearchParameterMap paramMap = new SearchParameterMap();
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, theFtContent);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, theFtText);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_TAG, theSearchForTag);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_SECURITY, theSearchForSecurity);
paramMap.add(ca.uhn.fhir.rest.api.Constants.PARAM_PROFILE, theSearchForProfile);
paramMap.add("_has", theHas);
paramMap.add("_id", the_id);
paramMap.add("_language", the_language);
paramMap.add("composed-of", theComposed_of);
paramMap.add("date", theDate);
paramMap.add("depends-on", theDepends_on);
paramMap.add("derived-from", theDerived_from);
paramMap.add("description", theDescription);
paramMap.add("effective", theEffective);
paramMap.add("identifier", theIdentifier);
paramMap.add("jurisdiction", theJurisdiction);
paramMap.add("name", theName);
paramMap.add("predecessor", thePredecessor);
paramMap.add("publisher", thePublisher);
paramMap.add("status", theStatus);
paramMap.add("successor", theSuccessor);
paramMap.add("title", theTitle);
paramMap.add("topic", theTopic);
paramMap.add("url", theUrl);
paramMap.add("version", theVersion);
paramMap.setRevIncludes(theRevIncludes);
paramMap.setLastUpdated(theLastUpdated);
paramMap.setIncludes(theIncludes);
paramMap.setSort(theSort);
paramMap.setCount(theCount);
// paramMap.setRequestDetails(theRequestDetails);
getDao().translateRawParameters(theAdditionalRawParams, paramMap);
return getDao().search(paramMap, theRequestDetails);
} finally {
endRequest(theServletRequest);
}
}
}

View File

@ -1,127 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.providers;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.provider.dstu3.JpaResourceProviderDstu3;
import ca.uhn.fhir.rest.api.server.IBundleProvider;
import ca.uhn.fhir.rest.param.*;
import ca.uhn.fhir.rest.server.IResourceProvider;
import org.hl7.fhir.instance.model.api.IAnyResource;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.opencds.cqf.cql.data.fhir.FhirDataProviderStu3;
import org.opencds.cqf.cql.runtime.Code;
import org.opencds.cqf.cql.runtime.Interval;
import org.opencds.cqf.cql.terminology.ValueSetInfo;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
/**
* Created by Christopher Schuler on 7/17/2017.
*/
public class JpaDataProvider extends FhirDataProviderStu3 {
// need these to access the dao
private HashMap<String, IResourceProvider> providers;
public JpaDataProvider(Collection<IResourceProvider> providers) {
this.providers = new HashMap<>();
for (IResourceProvider i : providers) {
this.providers.put(i.getResourceType().getSimpleName(), i);
}
// NOTE: Defaults to STU3
setPackageName("org.hl7.fhir.dstu3.model");
setFhirContext(FhirContext.forDstu3());
}
public Iterable<Object> retrieve(String context, Object contextValue, String dataType, String templateId,
String codePath, Iterable<Code> codes, String valueSet, String datePath,
String dateLowPath, String dateHighPath, Interval dateRange)
{
SearchParameterMap map = new SearchParameterMap();
map.setLastUpdated(new DateRangeParam());
if (templateId != null && !templateId.equals("")) {
// do something?
}
if (valueSet != null && valueSet.startsWith("urn:oid:")) {
valueSet = valueSet.replace("urn:oid:", "");
}
if (codePath == null && (codes != null || valueSet != null)) {
throw new IllegalArgumentException("A code path must be provided when filtering on codes or a valueset.");
}
if (dataType == null) {
throw new IllegalArgumentException("A data type (i.e. Procedure, Valueset, etc...) must be specified for clinical data retrieval");
}
if (context != null && context.equals("Patient") && contextValue != null) {
ReferenceParam patientParam = new ReferenceParam(contextValue.toString());
map.add(getPatientSearchParam(dataType), patientParam);
}
if (codePath != null && !codePath.equals("")) {
if (terminologyProvider != null && expandValueSets) {
ValueSetInfo valueSetInfo = new ValueSetInfo().withId(valueSet);
codes = terminologyProvider.expand(valueSetInfo);
}
if (codes != null) {
TokenOrListParam codeParams = new TokenOrListParam();
for (Code code : codes) {
codeParams.addOr(new TokenParam(code.getSystem(), code.getCode()));
}
map.add(convertPathToSearchParam(codePath), codeParams);
}
}
if (dateRange != null) {
DateParam low = null;
DateParam high = null;
if (dateRange.getLow() != null) {
low = new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, convertPathToSearchParam(dateLowPath != null ? dateLowPath : datePath));
}
if (dateRange.getHigh() != null) {
high = new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, convertPathToSearchParam(dateHighPath != null ? dateHighPath : datePath));
}
DateRangeParam rangeParam;
if (low == null && high != null) {
rangeParam = new DateRangeParam(high);
}
else if (high == null && low != null) {
rangeParam = new DateRangeParam(low);
}
else {
rangeParam = new DateRangeParam(high, low);
}
map.add(convertPathToSearchParam(datePath), rangeParam);
}
JpaResourceProviderDstu3<? extends IAnyResource> jpaResProvider = resolveResourceProvider(dataType);
IBundleProvider bundleProvider = jpaResProvider.getDao().search(map);
List<IBaseResource> resourceList = bundleProvider.getResources(0, 50);
return resolveResourceList(resourceList);
}
public Iterable<Object> resolveResourceList(List<IBaseResource> resourceList) {
List<Object> ret = new ArrayList<>();
for (IBaseResource res : resourceList) {
Class clazz = res.getClass();
ret.add(clazz.cast(res));
}
// ret.addAll(resourceList);
return ret;
}
public JpaResourceProviderDstu3<? extends IAnyResource> resolveResourceProvider(String datatype) {
return (JpaResourceProviderDstu3<? extends IAnyResource>) providers.get(datatype);
}
}

View File

@ -1,58 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.providers;
import ca.uhn.fhir.jpa.provider.dstu3.JpaResourceProviderDstu3;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import org.hl7.fhir.dstu3.model.CodeSystem;
import org.hl7.fhir.dstu3.model.IdType;
import org.hl7.fhir.dstu3.model.ValueSet;
import org.opencds.cqf.cql.runtime.Code;
import org.opencds.cqf.cql.terminology.CodeSystemInfo;
import org.opencds.cqf.cql.terminology.TerminologyProvider;
import org.opencds.cqf.cql.terminology.ValueSetInfo;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Christopher Schuler on 7/17/2017.
*/
public class JpaTerminologyProvider implements TerminologyProvider {
private JpaResourceProviderDstu3<ValueSet> valueSetProvider;
private JpaResourceProviderDstu3<CodeSystem> codeSystemProvider;
public JpaTerminologyProvider(JpaResourceProviderDstu3<ValueSet> valueSetProvider, JpaResourceProviderDstu3<CodeSystem> codeSystemProvider) {
this.valueSetProvider = valueSetProvider;
this.codeSystemProvider = codeSystemProvider;
}
@Override
public boolean in(Code code, ValueSetInfo valueSet) throws ResourceNotFoundException {
for (Code c : expand(valueSet)) {
if (c == null) continue;
if (c.getCode().equals(code.getCode()) && c.getSystem().equals(code.getSystem())) {
return true;
}
}
return false;
}
@Override
public Iterable<Code> expand(ValueSetInfo valueSet) throws ResourceNotFoundException {
ValueSet vs = valueSetProvider.getDao().read(new IdType(valueSet.getId()));
List<Code> codes = new ArrayList<>();
for (ValueSet.ValueSetExpansionContainsComponent expansion : vs.getExpansion().getContains()) {
codes.add(new Code().withCode(expansion.getCode()).withSystem(expansion.getSystem()));
}
return codes;
}
@Override
public Code lookup(Code code, CodeSystemInfo codeSystem) throws ResourceNotFoundException {
CodeSystem cs = codeSystemProvider.getDao().read(new IdType(codeSystem.getId()));
for (CodeSystem.ConceptDefinitionComponent concept : cs.getConcept()) {
if (concept.getCode().equals(code.getCode()))
return code.withSystem(codeSystem.getId()).withDisplay(concept.getDisplay());
}
return code;
}
}

View File

@ -1,46 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.providers;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.CustomThymeleafNarrativeGenerator;
import org.hl7.fhir.instance.model.api.IBaseResource;
import java.io.*;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Created by Christopher on 2/4/2017.
*/
public class NarrativeProvider {
// args[0] == relative path to json resource -> i.e. measure/cms146.json
public static void main(String[] args) {
Path pathToResources = Paths.get("src/main/resources/narratives").toAbsolutePath();
Path pathToProp = pathToResources.resolve("narrative.properties");
String propFile = "file:" + pathToProp.toString();
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator(propFile);
FhirContext ctx = FhirContext.forDstu3();
ctx.setNarrativeGenerator(gen);
// examples are here: src/main/resources/narratives/examples
if (args.length < 1) { throw new IllegalArgumentException("provide a file name..."); }
Path pathToResource = pathToResources.resolve("examples/" + args[0]);
try {
IBaseResource res = ctx.newJsonParser().parseResource(new FileReader(pathToResource.toFile()));
String resource = ctx.newXmlParser().setPrettyPrint(true)
.encodeResourceToString(ctx.newJsonParser().setPrettyPrint(true).parseResource(new FileReader(pathToResource.toFile())));
try {
PrintWriter writer = new PrintWriter(new File(pathToResources.resolve("scratch.xml").toString()), "UTF-8");
writer.println(resource);
writer.println();
writer.close();
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}
}

View File

@ -1,150 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.servlet;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
import ca.uhn.fhir.jpa.rp.dstu3.ActivityDefinitionResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.MeasureResourceProvider;
import ca.uhn.fhir.jpa.rp.dstu3.PlanDefinitionResourceProvider;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import org.hl7.fhir.dstu3.model.Bundle;
import org.hl7.fhir.dstu3.model.Meta;
import ca.uhn.fhir.jpa.cqf.ruler.providers.FHIRActivityDefinitionResourceProvider;
import ca.uhn.fhir.jpa.cqf.ruler.providers.FHIRMeasureResourceProvider;
import ca.uhn.fhir.jpa.cqf.ruler.providers.FHIRPlanDefinitionResourceProvider;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import javax.servlet.ServletException;
import java.util.Collection;
import java.util.List;
/**
* Created by Chris Schuler on 12/11/2016.
*/
public class BaseServlet extends RestfulServer {
@SuppressWarnings("unchecked")
@Override
protected void initialize() throws ServletException {
super.initialize();
FhirVersionEnum fhirVersion = FhirVersionEnum.DSTU3;
setFhirContext(new FhirContext(fhirVersion));
// Get the spring context from the web container (it's declared in web.xml)
WebApplicationContext myAppCtx = ContextLoaderListener.getCurrentWebApplicationContext();
String resourceProviderBeanName = "myResourceProvidersDstu3";
List<IResourceProvider> beans = myAppCtx.getBean(resourceProviderBeanName, List.class);
setResourceProviders(beans);
Object systemProvider = myAppCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class);
setPlainProviders(systemProvider);
IFhirSystemDao<Bundle, Meta> systemDao = myAppCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao,
myAppCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription("Measure and Opioid Processing Server");
setServerConformanceProvider(confProvider);
FhirContext ctx = getFhirContext();
ctx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
setDefaultPrettyPrint(true);
setDefaultResponseEncoding(EncodingEnum.JSON);
setPagingProvider(myAppCtx.getBean(DatabaseBackedPagingProvider.class));
/*
* Enable CORS
*/
// CorsConfiguration config = new CorsConfiguration();
// CorsInterceptor corsInterceptor = new CorsInterceptor(config);
// config.addAllowedHeader("Origin");
// config.addAllowedHeader("Accept");
// config.addAllowedHeader("X-Requested-With");
// config.addAllowedHeader("Content-Type");
// config.addAllowedHeader("Access-Control-Request-Method");
// config.addAllowedHeader("Access-Control-Request-Headers");
// config.addAllowedOrigin("*");
// config.addExposedHeader("Location");
// config.addExposedHeader("Content-Location");
// config.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS"));
// registerInterceptor(corsInterceptor);
/*
* Load interceptors for the server from Spring (these are defined in FhirServerConfig.java)
*/
Collection<IServerInterceptor> interceptorBeans = myAppCtx.getBeansOfType(IServerInterceptor.class).values();
for (IServerInterceptor interceptor : interceptorBeans) {
this.registerInterceptor(interceptor);
}
// Measure processing
FHIRMeasureResourceProvider measureProvider = new FHIRMeasureResourceProvider(getResourceProviders());
MeasureResourceProvider jpaMeasureProvider = (MeasureResourceProvider) getProvider("Measure");
measureProvider.setDao(jpaMeasureProvider.getDao());
measureProvider.setContext(jpaMeasureProvider.getContext());
// PlanDefinition processing
FHIRPlanDefinitionResourceProvider planDefProvider = new FHIRPlanDefinitionResourceProvider(getResourceProviders());
PlanDefinitionResourceProvider jpaPlanDefProvider =
(PlanDefinitionResourceProvider) getProvider("PlanDefinition");
planDefProvider.setDao(jpaPlanDefProvider.getDao());
planDefProvider.setContext(jpaPlanDefProvider.getContext());
// ActivityDefinition processing
FHIRActivityDefinitionResourceProvider actDefProvider = new FHIRActivityDefinitionResourceProvider(getResourceProviders());
ActivityDefinitionResourceProvider jpaActDefProvider =
(ActivityDefinitionResourceProvider) getProvider("ActivityDefinition");
actDefProvider.setDao(jpaActDefProvider.getDao());
actDefProvider.setContext(jpaActDefProvider.getContext());
try {
unregisterProvider(jpaMeasureProvider);
unregisterProvider(jpaPlanDefProvider);
unregisterProvider(jpaActDefProvider);
} catch (Exception e) {
throw new ServletException("Unable to unregister provider: " + e.getMessage());
}
registerProvider(measureProvider);
registerProvider(planDefProvider);
registerProvider(actDefProvider);
// Register the logging interceptor
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
this.registerInterceptor(loggingInterceptor);
// The SLF4j logger "test.accesslog" will receive the logging events
loggingInterceptor.setLoggerName("logging.accesslog");
// This is the format for each line. A number of substitution variables may
// be used here. See the JavaDoc for LoggingInterceptor for information on
// what is available.
loggingInterceptor.setMessageFormat("Source[${remoteAddr}] Operation[${operationType} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}]");
//setServerAddressStrategy(new HardcodedServerAddressStrategy("http://mydomain.com/fhir/baseDstu2"));
//registerProvider(myAppCtx.getBean(TerminologyUploaderProviderDstu3.class));
}
public IResourceProvider getProvider(String name) {
for (IResourceProvider res : getResourceProviders()) {
if (res.getResourceType().getSimpleName().equals(name)) {
return res;
}
}
throw new IllegalArgumentException("This should never happen!");
}
}

View File

@ -1,180 +0,0 @@
package ca.uhn.fhir.jpa.cqf.ruler.servlet;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.rp.dstu3.LibraryResourceProvider;
import ca.uhn.fhir.model.primitive.IdDt;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import org.hl7.fhir.dstu3.model.*;
import org.hl7.fhir.exceptions.FHIRException;
import ca.uhn.fhir.jpa.cqf.ruler.cds.*;
import ca.uhn.fhir.jpa.cqf.ruler.providers.FHIRPlanDefinitionResourceProvider;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
/**
* Created by Christopher Schuler on 5/1/2017.
*/
@WebServlet(name = "cds-services")
public class CdsServicesServlet extends BaseServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// validate that we are dealing with JSON
if (!request.getContentType().equals("application/json")) {
throw new ServletException(String.format("Invalid content type %s. Please use application/json.", request.getContentType()));
}
CdsHooksRequest cdsHooksRequest = new CdsHooksRequest(request.getReader());
CdsRequestProcessor processor = null;
String service = request.getPathInfo().replace("/", "");
// PlanDefinition must have the same id as the cds service
// For example, {BASE}/cds-services/cdc-opioid-guidance -> PlanDefinition ID = cds-opioid-guidance
PlanDefinition planDefinition =
((FHIRPlanDefinitionResourceProvider) getProvider("PlanDefinition"))
.getDao()
.read(new IdDt(service));
// Custom cds services
if (request.getRequestURL().toString().endsWith("cdc-opioid-guidance")) {
resolveMedicationPrescribePrefetch(cdsHooksRequest);
try {
processor = new OpioidGuidanceProcessor(cdsHooksRequest, planDefinition, (LibraryResourceProvider) getProvider("Library"));
} catch (FHIRException e) {
e.printStackTrace();
}
}
else {
// User-defined cds services
// These are limited - no user-defined data/terminology providers
switch (cdsHooksRequest.getHook()) {
case "medication-prescribe":
resolveMedicationPrescribePrefetch(cdsHooksRequest);
try {
processor = new MedicationPrescribeProcessor(cdsHooksRequest, planDefinition, (LibraryResourceProvider) getProvider("Library"));
} catch (FHIRException e) {
e.printStackTrace();
}
break;
case "order-review":
// resolveOrderReviewPrefetch(cdsHooksRequest);
// TODO - currently only works for ProcedureRequest orders
processor = new OrderReviewProcessor(cdsHooksRequest, planDefinition, (LibraryResourceProvider) getProvider("Library"));
break;
case "patient-view":
processor = new PatientViewProcessor(cdsHooksRequest, planDefinition, (LibraryResourceProvider) getProvider("Library"));
break;
}
}
if (processor == null) {
throw new ServletException("Invalid cds service");
}
response.getWriter().println(toJsonResponse(processor.process()));
}
// If the EHR did not provide the prefetch resources, fetch them
// Assuming EHR is using DSTU2 resources here...
// This is a big drag on performance.
public void resolveMedicationPrescribePrefetch(CdsHooksRequest cdsHooksRequest) {
if (cdsHooksRequest.getPrefetch().size() == 0) {
String searchUrl = String.format("MedicationOrder?patient=%s&status=active", cdsHooksRequest.getPatientId());
ca.uhn.fhir.model.dstu2.resource.Bundle postfetch = FhirContext.forDstu2()
.newRestfulGenericClient(cdsHooksRequest.getFhirServerEndpoint())
.search()
.byUrl(searchUrl)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
cdsHooksRequest.setPrefetch(postfetch, "medication");
}
}
// This is especially inefficient as the search must be done for each Request resource (and then converted to stu3):
// MedicationOrder -> MedicationRequest, DiagnosticOrder or DeviceUseRequest -> ProcedureRequest, SupplyRequest
public void resolveOrderReviewPrefetch(CdsHooksRequest cdsHooksRequest) {
// TODO - clean this up
if (cdsHooksRequest.getPrefetch().size() == 0) {
String searchUrl = String.format("MedicationOrder?patient=%s&encounter=%s", cdsHooksRequest.getPatientId(), cdsHooksRequest.getEncounterId());
ca.uhn.fhir.model.dstu2.resource.Bundle postfetch = FhirContext.forDstu2()
.newRestfulGenericClient(cdsHooksRequest.getFhirServerEndpoint())
.search()
.byUrl(searchUrl)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
cdsHooksRequest.setPrefetch(postfetch, "medication");
searchUrl = String.format("DiagnosticOrder?patient=%s&encounter=%s", cdsHooksRequest.getPatientId(), cdsHooksRequest.getEncounterId());
ca.uhn.fhir.model.dstu2.resource.Bundle diagnosticOrders = FhirContext.forDstu2()
.newRestfulGenericClient(cdsHooksRequest.getFhirServerEndpoint())
.search()
.byUrl(searchUrl)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
cdsHooksRequest.setPrefetch(diagnosticOrders, "diagnosticOrders");
searchUrl = String.format("DeviceUseRequest?patient=%s&encounter=%s", cdsHooksRequest.getPatientId(), cdsHooksRequest.getEncounterId());
ca.uhn.fhir.model.dstu2.resource.Bundle deviceUseRequests = FhirContext.forDstu2()
.newRestfulGenericClient(cdsHooksRequest.getFhirServerEndpoint())
.search()
.byUrl(searchUrl)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
cdsHooksRequest.setPrefetch(deviceUseRequests, "deviceUseRequests");
searchUrl = String.format("ProcedureRequest?patient=%s&encounter=%s", cdsHooksRequest.getPatientId(), cdsHooksRequest.getEncounterId());
ca.uhn.fhir.model.dstu2.resource.Bundle procedureRequests = FhirContext.forDstu2()
.newRestfulGenericClient(cdsHooksRequest.getFhirServerEndpoint())
.search()
.byUrl(searchUrl)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
cdsHooksRequest.setPrefetch(procedureRequests, "procedureRequests");
searchUrl = String.format("SupplyRequest?patient=%s&encounter=%s", cdsHooksRequest.getPatientId(), cdsHooksRequest.getEncounterId());
ca.uhn.fhir.model.dstu2.resource.Bundle supplyRequests = FhirContext.forDstu2()
.newRestfulGenericClient(cdsHooksRequest.getFhirServerEndpoint())
.search()
.byUrl(searchUrl)
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.execute();
cdsHooksRequest.setPrefetch(supplyRequests, "supplyRequests");
}
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
if (!request.getRequestURL().toString().endsWith("cds-services")) {
throw new ServletException("This servlet is not configured to handle GET requests.");
}
CdsHooksHelper.DisplayDiscovery(response);
}
public String toJsonResponse(List<CdsCard> cards) {
JsonObject ret = new JsonObject();
JsonArray cardArray = new JsonArray();
for (CdsCard card : cards) {
cardArray.add(card.toJson());
}
ret.add("cards", cardArray);
Gson gson = new GsonBuilder().setPrettyPrinting().create();
return gson.toJson(ret);
}
}

View File

@ -1,67 +0,0 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns4:modelInfo name="OMTK" url="http://org.opencds/opioid-cds" targetQualifier="cdc" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:ns4="urn:hl7-org:elm-modelinfo:r1" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
version="0.1.0">
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_DOSE_FORM" baseType="System.Any" retrievable="true">
<ns4:element name="DOSE_FORM_RXCUI" type="System.Code"/>
<ns4:element name="DOSE_FORM_NAME" type="System.String"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_DOSE_FORM_GROUP" baseType="System.Any" retrievable="true">
<ns4:element name="DOSE_FORM_GROUP_RXCUI" type="System.Code"/>
<ns4:element name="DOSE_FORM_GROUP_NAME" type="System.String"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_DRUG" baseType="System.Any" retrievable="true">
<ns4:element name="DRUG_RXCUI" type="System.Code"/>
<ns4:element name="DRUG_TYPE" type="System.String"/>
<ns4:element name="DRUG_NAME" type="System.String"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_DRUG_DOSE_FORM" baseType="System.Any" retrievable="true">
<ns4:element name="DRUG_RXCUI" type="System.Code"/>
<ns4:element name="DOSE_FORM_RXCUI" type="System.Code"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_DRUG_DOSE_FORM_GROUP" baseType="System.Any" retrievable="true">
<ns4:element name="DRUG_RXCUI" type="System.Code"/>
<ns4:element name="DOSE_FORM_GROUP_RXCUI" type="System.Code"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_DRUG_WITH_INGREDIENT" baseType="System.Any" retrievable="true">
<ns4:element name="INGREDIENT_RXCUI" type="System.Code"/>
<ns4:element name="DRUG_RXCUI" type="System.Code"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_INGREDIENT" baseType="System.Any" retrievable="true">
<ns4:element name="INGREDIENT_RXCUI" type="System.Code"/>
<ns4:element name="INGREDIENT_NAME" type="System.String"/>
<ns4:element name="MANUALLY_ENTERED" type="System.Integer"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_INGREDIENT_FOR_SCDC" baseType="System.Any" retrievable="true">
<ns4:element name="SCDC_RXCUI" type="System.Code"/>
<ns4:element name="INGREDIENT_RXCUI" type="System.Code"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_INGREDIENT_TYPE" baseType="System.Any" retrievable="true">
<ns4:element name="INGREDIENT_RXCUI" type="System.Code"/>
<ns4:element name="INGREDIENT_TYPE" type="System.String"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_SCDC" baseType="System.Any" retrievable="true">
<ns4:element name="SCDC_RXCUI" type="System.Code"/>
<ns4:element name="SCDC_NAME" type="System.String"/>
<ns4:element name="STRENGTH" type="System.String"/>
<ns4:element name="STRENGTH_VALUE" type="System.Decimal"/>
<ns4:element name="STRENGTH_UNIT" type="System.String"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.MED_SCDC_FOR_DRUG" baseType="System.Any" retrievable="true">
<ns4:element name="DRUG_RXCUI" type="System.Code"/>
<ns4:element name="SCDC_RXCUI" type="System.Code"/>
<ns4:element name="UPDATE_DTM" type="System.DateTime"/>
</ns4:typeInfo>
<ns4:typeInfo xsi:type="ns4:ClassInfo" name="OMTK.NON_SURGICAL_OPIOID_TO_INCLUDE" baseType="System.Any" retrievable="true">
<ns4:element name="DRUG_RXCUI" type="System.Code"/>
</ns4:typeInfo>
</ns4:modelInfo>

View File

@ -1,16 +0,0 @@
<configuration scan="true" scanPeriod="30 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
<level>INFO</level>
</filter>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT" />
</root>
</configuration>

View File

@ -1,108 +0,0 @@
# Resource Loading
## Methods
### HTTP Client
There are 2 different methods of uploading resources using an HTTP client.
1. PUT or POST a single resource
PUT method is used to create a new resource with a specified ID or update an existing resource.
PUT [base]/baseDstu3/Practitioner/prac-123
```
{
"resourceType": "Practitioner",
"id": "prac-123",
"identifier": [
{
"system": "http://clinfhir.com/fhir/NamingSystem/practitioner",
"value": "z1z1kXlcn3bhaZRsg7izSA1PYZm1"
}
],
"telecom": [
{
"system": "email",
"value": "sruthi.v@collabnotes.com"
}
]
}
```
Successful response
```
{
"resourceType": "OperationOutcome",
"issue": [
{
"severity": "information",
"code": "informational",
"diagnostics": "Successfully created resource \"Practitioner/prac-123/_history/1\" in 32ms"
}
]
}
```
If the request results in an error, the "severity" will be specified as "error" and a message will be given in the "diagnostics" value field
POST method is used to create a new resource with a generated ID.
POST [base]/baseDstu3/Practitioner
```
{
"resourceType": "Practitioner",
"identifier": [
{
"system": "http://clinfhir.com/fhir/NamingSystem/practitioner",
"value": "z1z1kXlcn3bhaZRsg7izSA1PYZm1"
}
],
"telecom": [
{
"system": "email",
"value": "sruthi.v@collabnotes.com"
}
]
}
```
The response will be the same as the PUT method.
2. POST a transaction Bundle
The [transaction](http://hl7.org/implement/standards/fhir/http.html#transaction) operation loads all the resources within a transaction Bundle.
POST [base]/baseDstu3
```
{
"resourceType": "Bundle",
"id": "example-transaction",
"type": "transaction",
"entry": [
{
"resource": {
...
},
"request": {
"method": "PUT",
"url": "[base]/baseDstu3/Resource/ResourceID"
}
},
...
]
}
```
The response will be a Bundle containing the status and location for each uploaded resource if successful or an OperationOutcome if there were errors.
```
{
"resourceType": "Bundle",
"id": "...",
"type": "transaction-response",
"entry": [
{
"response": {
"status": "201 Created",
"location": "Resource/ResourceID/_history/1",
...
},
...
}
]
}
```

View File

@ -1,99 +0,0 @@
{
"resourceType": "ActivityDefinition",
"id": "citalopramPrescription",
"contained": [
{
"resourceType": "Medication",
"id": "citalopramMedication",
"code": {
"coding": [
{
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
"code": "200371"
}
],
"text": "citalopram"
},
"form": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "385055001",
"display": "Tablet dose form"
}
],
"text": "Tablet dose form"
},
"ingredient": [
{
"itemReference": {
"reference": "#citalopramSubstance"
},
"amount": {
"numerator": {
"value": 20,
"unit": "mg"
},
"denominator": {
"value": 1,
"unit": "{tbl}"
}
}
}
]
},
{
"resourceType": "Substance",
"id": "citalopramSubstance",
"code": {
"coding": [
{
"system": "http://www.nlm.nih.gov/research/umls/rxnorm",
"code": "2556"
}
],
"text": "citalopram"
}
}
],
"status": "draft",
"category": "drug",
"productReference": {
"reference": "#citalopramMedication"
},
"dosageInstruction": [
{
"text": "1 tablet oral 1 time daily",
"timing": {
"repeat": {
"frequency": 1,
"period": 1,
"periodUnit": "d"
}
},
"route": {
"coding": [
{
"code": "26643006",
"display": "Oral route (qualifier value)"
}
],
"text": "Oral route (qualifier value)"
},
"doseQuantity": {
"value": 1,
"unit": "{tbl}"
}
}
],
"dynamicValue": [
{
"path": "dispenseRequest.numberOfRepeatsAllowed",
"expression": "3"
},
{
"path": "dispenseRequest.quantity",
"expression": "30 '{tbl}'"
}
]
}

View File

@ -1,31 +0,0 @@
{
"resourceType": "ActivityDefinition",
"id": "example",
"status": "draft",
"description": "refer to primary care mental-health integrated care program for evaluation and treatment of mental health conditions now",
"category": "referral",
"code": {
"coding": [
{
"system": "http://snomed.info/sct",
"code": "306206005"
}
],
"text": "Referral to service (procedure)"
},
"timingTiming": {
"event": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/cqif-cqlExpression",
"valueString": "Now()"
}
]
}
]
},
"participantType": [
"practitioner"
]
}

View File

@ -1,33 +0,0 @@
{
"resourceType": "ActivityDefinition",
"id": "serum-zika-dengue-virus-igm",
"url": "http://example.org/ActivityDefinition/serum-zika-dengue-virus-igm",
"status": "draft",
"description": "Order Serum Zika and Dengue Virus IgM",
"relatedArtifact": [
{
"type": "documentation",
"display": "Explanation of diagnostic tests for Zika virus and which to use based on the patients clinical and exposure history.",
"url": "http://www.cdc.gov/zika/hc-providers/diagnostic.html"
}
],
"category": "diagnostic",
"code": {
"text": "Serum Zika and Dengue Virus IgM"
},
"timingTiming": {
"event": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/cqif-cqlExpression",
"valueString": "Now()"
}
]
}
]
},
"participantType": [
"practitioner"
]
}

View File

@ -1,38 +0,0 @@
{
"resourceType": "ActivityDefinition",
"id": "provide-mosquito-prevention-advice",
"url": "http://example.org/ActivityDefinition/provide-mosquito-prevention-advice",
"status": "draft",
"description": "Provide mosquito prevention advice",
"relatedArtifact": [
{
"type": "documentation",
"display": "Advice for patients about how to avoid Mosquito bites.",
"url": "http://www.cdc.gov/zika/prevention/index.html"
},
{
"type": "documentation",
"display": "Advice for patients about which mosquito repellents are effective and safe to use in pregnancy. [DEET, IF3535 and Picardin are safe during]",
"url": "https://www.epa.gov/insect-repellents/find-insect-repellent-right-you"
}
],
"category": "communication",
"code": {
"text": "Provide Mosquito Prevention Advice"
},
"timingTiming": {
"event": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/cqif-cqlExpression",
"valueString": "Now()"
}
]
}
]
},
"participantType": [
"practitioner"
]
}

View File

@ -1,31 +0,0 @@
{
"resourceType": "ActivityDefinition",
"id": "administer-zika-virus-exposure-assessment",
"url": "http://example.org/ActivityDefinition/administer-zika-virus-exposure-assessment",
"status": "draft",
"description": "Administer Zika Virus Exposure Assessment",
"category": "procedure",
"code": {
"coding": [
{
"system": "http://example.org/questionnaires",
"code": "zika-virus-exposure-assessment"
}
]
},
"timingTiming": {
"event": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/cqif-cqlExpression",
"valueString": "Now()"
}
]
}
]
},
"participantType": [
"practitioner"
]
}

View File

@ -1,8 +0,0 @@
{
"resourceType": "GuidanceResponse",
"id": "example",
"module": {
"reference": "ServiceDefinition/example"
},
"status": "success"
}

View File

@ -1,161 +0,0 @@
{
"resourceType": "Library",
"id": "library-cms146-example",
"identifier": [
{
"use": "official",
"value": "CMS146"
}
],
"version": "2.0.0",
"title": "Appropriate Testing for Children with Pharyngitis",
"type": {
"coding": [
{
"code": "logic-library"
}
]
},
"status": "draft",
"date": "2015-07-22",
"description": "Logic for CMS 146: Appropriate Testing for Children with Pharyngitis",
"relatedArtifact": [
{
"type": "depends-on",
"resource": {
"reference": "Library/library-quick-model-definition"
}
}
],
"dataRequirement": [
{
"type": "Condition",
"codeFilter": [
{
"path": "code",
"valueSetString": "Other Female Reproductive Conditions"
}
]
},
{
"type": "Patient"
},
{
"type": "Condition",
"codeFilter": [
{
"path": "category",
"valueCode": [
"diagnosis"
]
},
{
"path": "clinicalStatus",
"valueCode": [
"confirmed"
]
},
{
"path": "code",
"valueSetString": "2.16.840.1.113883.3.464.1003.102.12.1011"
}
]
},
{
"type": "Condition",
"codeFilter": [
{
"path": "category",
"valueCode": [
"diagnosis"
]
},
{
"path": "clinicalStatus",
"valueCode": [
"confirmed"
]
},
{
"path": "code",
"valueSetString": "2.16.840.1.113883.3.464.1003.102.12.1012"
}
]
},
{
"type": "Encounter",
"codeFilter": [
{
"path": "status",
"valueCode": [
"finished"
]
},
{
"path": "class",
"valueCode": [
"ambulatory"
]
},
{
"path": "type",
"valueSetString": "2.16.840.1.113883.3.464.1003.101.12.1061"
}
]
},
{
"type": "DiagnosticReport",
"codeFilter": [
{
"path": "diagnosis",
"valueSetString": "2.16.840.1.113883.3.464.1003.198.12.1012"
}
]
},
{
"type": "Medication",
"codeFilter": [
{
"path": "code",
"valueSetString": "2.16.840.1.113883.3.464.1003.196.12.1001"
}
]
},
{
"type": "MedicationRequest",
"codeFilter": [
{
"path": "status",
"valueCode": [
"active"
]
},
{
"path": "medication.code",
"valueSetString": "2.16.840.1.113883.3.464.1003.196.12.1001"
}
]
},
{
"type": "MedicationStatement",
"codeFilter": [
{
"path": "status",
"valueCode": [
"completed"
]
},
{
"path": "medication.code",
"valueSetString": "2.16.840.1.113883.3.464.1003.196.12.1001"
}
]
}
],
"content": [
{
"contentType": "text/cql",
"url": "http://cqlrepository.org/CMS146.cql"
}
]
}

Some files were not shown because too many files have changed in this diff Show More