Merge pull request #52 from hapifhir/rel_4_1_0

Release 4.1.0
This commit is contained in:
James Agnew
2019-11-13 05:23:16 -05:00
committed by GitHub
13 changed files with 399 additions and 139 deletions

View File

@@ -137,3 +137,18 @@ The server may be configured with subscription support by enabling properties in
* `subscription.email.enabled` - Enables email subscriptions. Note that you must also provide the connection details for a usable SMTP server. * `subscription.email.enabled` - Enables email subscriptions. Note that you must also provide the connection details for a usable SMTP server.
* `subscription.websocket.enabled` - Enables websocket subscriptions. With this enabled, your server will accept incoming websocket connections on the following URL (this example uses the default context path and port, you may need to tweak depending on your deployment environment): [ws://localhost:8080/hapi-fhir-jpaserver/websocket](ws://localhost:8080/hapi-fhir-jpaserver/websocket) * `subscription.websocket.enabled` - Enables websocket subscriptions. With this enabled, your server will accept incoming websocket connections on the following URL (this example uses the default context path and port, you may need to tweak depending on your deployment environment): [ws://localhost:8080/hapi-fhir-jpaserver/websocket](ws://localhost:8080/hapi-fhir-jpaserver/websocket)
# Using ElasticSearch
By default, the server will use embedded lucene indexes for terminology and fulltext indexing purposes. You can switch this to using lucene by editing the properties in [hapi.properties](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/hapi.properties)
For example:
```properties
elasticsearch.enabled=true
elasticsearch.rest_url=http://localhost:9200
elasticsearch.username=SomeUsername
elasticsearch.password=SomePassword
elasticsearch.required_index_status=YELLOW
elasticsearch.schema_management_strategy=CREATE
```

53
pom.xml
View File

@@ -11,10 +11,9 @@
<parent> <parent>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<version>4.0.3</version> <version>4.1.0</version>
</parent> </parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-starter</artifactId> <artifactId>hapi-fhir-jpaserver-starter</artifactId>
<prerequisites> <prerequisites>
@@ -73,14 +72,6 @@
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId> <artifactId>spring-jcl</artifactId>
</exclusion> </exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-elasticsearch</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion> <exclusion>
<groupId>commons-logging</groupId> <groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId> <artifactId>commons-logging</artifactId>
@@ -150,6 +141,48 @@
<artifactId>h2</artifactId> <artifactId>h2</artifactId>
</dependency> </dependency>
<!-- webjars -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>Eonasdan-bootstrap-datetimepicker</artifactId>
<version>4.17.43</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>font-awesome</artifactId>
<version>5.8.2</version>
</dependency>
<dependency>
<groupId>org.webjars.bower</groupId>
<artifactId>awesome-bootstrap-checkbox</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jstimezonedetect</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>select2</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>org.webjars.bower</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.webjars.bower</groupId>
<artifactId>moment</artifactId>
<version>2.15.1</version>
</dependency>
<!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. --> <!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. -->
<dependency> <dependency>
<groupId>org.eclipse.jetty</groupId> <groupId>org.eclipse.jetty</groupId>

View File

@@ -12,27 +12,17 @@
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir</artifactId> <artifactId>hapi-fhir</artifactId>
<<<<<<< HEAD <<<<<<< HEAD
<version>3.7.0</version> <version>4.1.0</version>
======= =======
<version>3.7.0-SNAPSHOT</version> <version>4.0.3</version>
>>>>>>> 18c85900e500863b2b24080da9fe5e11c6d0a434 >>>>>>> master
</parent> </parent>
<groupId>ca.uhn.hapi.fhir.demo</groupId>
<artifactId>hapi-fhir-jpaserver-starter</artifactId> <artifactId>hapi-fhir-jpaserver-starter</artifactId>
<packaging>war</packaging>
<name>HAPI FHIR JPA Server - Starter Project</name> <prerequisites>
<maven>3.5.0</maven>
<repositories> </prerequisites>
<repository>
<id>oss-snapshots</id>
<snapshots>
<enabled>true</enabled>
</snapshots>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<dependencies> <dependencies>
<dependency> <dependency>
@@ -48,9 +38,27 @@
<dependency> <dependency>
<groupId>mysql</groupId> <groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId> <artifactId>mysql-connector-java</artifactId>
<version>6.0.5</version> <version>8.0.11</version>
</dependency> </dependency>
<!-- Needed for Email subscriptions -->
<dependency>
<groupId>com.sun.mail</groupId>
<artifactId>javax.mail</artifactId>
<exclusions>
<exclusion>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
</dependency>
-->
<!-- This dependency includes the core HAPI-FHIR classes --> <!-- This dependency includes the core HAPI-FHIR classes -->
<dependency> <dependency>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
@@ -58,24 +66,21 @@
<version>${project.version}</version> <version>${project.version}</version>
</dependency> </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 --> <!-- This dependency includes the JPA server itself, which is packaged separately from the rest of HAPI FHIR -->
<dependency> <dependency>
<groupId>ca.uhn.hapi.fhir</groupId> <groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-jpaserver-base</artifactId> <artifactId>hapi-fhir-jpaserver-base</artifactId>
<version>${project.version}</version> <version>${project.version}</version>
</dependency> <exclusions>
<exclusion>
<dependency> <groupId>org.springframework</groupId>
<groupId>ca.uhn.hapi.fhir</groupId> <artifactId>spring-jcl</artifactId>
<artifactId>hapi-fhir-jpaserver-elasticsearch</artifactId> </exclusion>
<version>${project.version}</version> <exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- This dependency is used for the "FHIR Tester" web app overlay --> <!-- This dependency is used for the "FHIR Tester" web app overlay -->
@@ -115,17 +120,6 @@
</dependency> </dependency>
<!-- Used for CORS support --> <!-- 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. --> <!-- Spring Web is used to deploy the server to a web container. -->
<dependency> <dependency>
<groupId>org.springframework</groupId> <groupId>org.springframework</groupId>
@@ -136,21 +130,61 @@
<dependency> <dependency>
<groupId>org.apache.commons</groupId> <groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId> <artifactId>commons-dbcp2</artifactId>
<exclusions>
<exclusion>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</exclusion>
</exclusions>
</dependency> </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 <!-- This example uses H2 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 for your database platform. -->
<dependency> <dependency>
<groupId>org.apache.derby</groupId> <groupId>com.h2database</groupId>
<artifactId>derby</artifactId> <artifactId>h2</artifactId>
</dependency>
<!-- webjars -->
<dependency>
<groupId>org.webjars</groupId>
<artifactId>bootstrap</artifactId>
<version>3.3.7</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.derby</groupId> <groupId>org.webjars</groupId>
<artifactId>derbynet</artifactId> <artifactId>Eonasdan-bootstrap-datetimepicker</artifactId>
<version>4.17.43</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.derby</groupId> <groupId>org.webjars</groupId>
<artifactId>derbyclient</artifactId> <artifactId>font-awesome</artifactId>
<version>5.8.2</version>
</dependency>
<dependency>
<groupId>org.webjars.bower</groupId>
<artifactId>awesome-bootstrap-checkbox</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>jstimezonedetect</artifactId>
<version>1.0.6</version>
</dependency>
<dependency>
<groupId>org.webjars</groupId>
<artifactId>select2</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>org.webjars.bower</groupId>
<artifactId>jquery</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>org.webjars.bower</groupId>
<artifactId>moment</artifactId>
<version>2.15.1</version>
</dependency> </dependency>
<!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. --> <!-- The following dependencies are only needed for automated unit tests, you do not neccesarily need them to run the example. -->
@@ -184,6 +218,7 @@
<artifactId>jetty-webapp</artifactId> <artifactId>jetty-webapp</artifactId>
<scope>test</scope> <scope>test</scope>
</dependency> </dependency>
<!--
<dependency> <dependency>
<groupId>com.helger</groupId> <groupId>com.helger</groupId>
<artifactId>ph-schematron</artifactId> <artifactId>ph-schematron</artifactId>
@@ -194,6 +229,7 @@
</exclusion> </exclusion>
</exclusions> </exclusions>
</dependency> </dependency>
-->
<!-- <!--
For some reason JavaDoc crashed during site generation unless we have this dependency For some reason JavaDoc crashed during site generation unless we have this dependency
@@ -204,31 +240,49 @@
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-test-utilities</artifactId>
<version>${project.version}</version>
<scope>test</scope>
</dependency>
</dependencies> </dependencies>
<packaging>war</packaging>
<name>HAPI FHIR JPA Server - Starter Project</name>
<repositories>
<repository>
<id>oss-snapshots</id>
<snapshots>
<enabled>false</enabled>
</snapshots>
<url>https://oss.sonatype.org/content/repositories/snapshots/</url>
</repository>
</repositories>
<build> <build>
<!-- Tells Maven to name the generated WAR file as hapi-fhir-jpaserver.war --> <!-- Tells Maven to name the generated WAR file as hapi-fhir-jpaserver.war -->
<finalName>hapi-fhir-jpaserver</finalName> <finalName>hapi-fhir-jpaserver</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>
<version>9.4.8.v20180619</version>
<configuration>
<webApp>
<contextPath>/hapi-fhir-jpaserver</contextPath>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
</webApp>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<plugins> <plugins>
<!-- 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. -->
<plugin>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>9.4.8.v20180619</version>
<configuration>
<webApp>
<contextPath>/hapi-fhir-jpaserver</contextPath>
<allowDuplicateFragmentNames>true</allowDuplicateFragmentNames>
</webApp>
</configuration>
</plugin>
<!-- Tell Maven which Java source version you want to use --> <!-- Tell Maven which Java source version you want to use -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@@ -259,15 +313,6 @@
</configuration> </configuration>
</plugin> </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 --> <!-- This is to run the integration tests -->
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
@@ -285,6 +330,100 @@
</executions> </executions>
</plugin> </plugin>
<plugin>
<groupId>org.basepom.maven</groupId>
<artifactId>duplicate-finder-maven-plugin</artifactId>
<executions>
<execution>
<id>default</id>
<phase>verify</phase>
<goals>
<goal>check</goal>
</goals>
<inherited>true</inherited>
</execution>
</executions>
<configuration>
<failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
<checkTestClasspath>false</checkTestClasspath>
<!--
<printEqualFiles>false</printEqualFiles>
<failBuildInCaseOfDifferentContentConflict>true</failBuildInCaseOfDifferentContentConflict>
<failBuildInCaseOfEqualContentConflict>true</failBuildInCaseOfEqualContentConflict>
<failBuildInCaseOfConflict>true</failBuildInCaseOfConflict>
<checkCompileClasspath>true</checkCompileClasspath>
<checkRuntimeClasspath>false</checkRuntimeClasspath>
<skip>false</skip>
<quiet>false</quiet>
<preferLocal>true</preferLocal>
<useResultFile>true</useResultFile>
<resultFileMinClasspathCount>2</resultFileMinClasspathCount>
<resultFile>${project.build.directory}/duplicate-finder-result.xml</resultFile>
-->
<!--
<ignoredDependencies>
<dependency>
<groupId>javax.el</groupId>
<artifactId>javax.el-api</artifactId>
</dependency>
<dependency>
<groupId>javax.mail</groupId>
<artifactId>javax.mail-api</artifactId>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>javax.activation-api</artifactId>
</dependency>
<dependency>
<groupId>com.helger</groupId>
<artifactId>ph-schematron</artifactId>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
</dependency>
<dependency>
<groupId>org.jscience</groupId>
<artifactId>jscience</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jcl</artifactId>
</dependency>
<dependency>
<groupId>com.google.code.findbugs</groupId>
<artifactId>annotations</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbynet</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derbyclient</artifactId>
</dependency>
<dependency>
<groupId>org.checkerframework</groupId>
<artifactId>checker-compat-qual</artifactId>
</dependency>
</ignoredDependencies>
-->
<ignoredResourcePatterns>
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
<ignoredResourcePattern>.*\.html$</ignoredResourcePattern>
</ignoredResourcePatterns>
</configuration>
</plugin>
</plugins> </plugins>
</build> </build>

View File

@@ -4,7 +4,7 @@ import ca.uhn.fhir.jpa.binstore.DatabaseBlobBinaryStorageSvcImpl;
import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc; import ca.uhn.fhir.jpa.binstore.IBinaryStorageSvc;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.model.entity.ModelConfig; import ca.uhn.fhir.jpa.model.entity.ModelConfig;
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionDeliveryHandlerFactory; import ca.uhn.fhir.jpa.subscription.module.channel.SubscriptionDeliveryHandlerFactory;
import ca.uhn.fhir.jpa.subscription.module.subscriber.email.IEmailSender; import ca.uhn.fhir.jpa.subscription.module.subscriber.email.IEmailSender;
import ca.uhn.fhir.jpa.subscription.module.subscriber.email.JavaMailEmailSender; import ca.uhn.fhir.jpa.subscription.module.subscriber.email.JavaMailEmailSender;
import org.apache.commons.dbcp2.BasicDataSource; import org.apache.commons.dbcp2.BasicDataSource;

View File

@@ -43,7 +43,7 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e); throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
} }
retVal.setJpaProperties(HapiProperties.getProperties()); retVal.setJpaProperties(HapiProperties.getJpaProperties());
return retVal; return retVal;
} }

View File

@@ -43,7 +43,7 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e); throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
} }
retVal.setJpaProperties(HapiProperties.getProperties()); retVal.setJpaProperties(HapiProperties.getJpaProperties());
return retVal; return retVal;
} }

View File

@@ -43,7 +43,7 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e); throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
} }
retVal.setJpaProperties(HapiProperties.getProperties()); retVal.setJpaProperties(HapiProperties.getJpaProperties());
return retVal; return retVal;
} }

View File

@@ -1,7 +1,6 @@
package ca.uhn.fhir.jpa.starter; package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.jpa.config.BaseJavaConfigR4;
import ca.uhn.fhir.jpa.config.BaseJavaConfigR5; import ca.uhn.fhir.jpa.config.BaseJavaConfigR5;
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider; import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Autowired;
@@ -44,7 +43,7 @@ public class FhirServerConfigR5 extends BaseJavaConfigR5 {
throw new ConfigurationException("Could not set the data source due to a configuration issue", e); throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
} }
retVal.setJpaProperties(HapiProperties.getProperties()); retVal.setJpaProperties(HapiProperties.getJpaProperties());
return retVal; return retVal;
} }

View File

@@ -2,9 +2,13 @@ package ca.uhn.fhir.jpa.starter;
import ca.uhn.fhir.context.ConfigurationException; import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirVersionEnum; import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder;
import ca.uhn.fhir.rest.api.EncodingEnum; import ca.uhn.fhir.rest.api.EncodingEnum;
import ca.uhn.fhir.rest.server.ETagSupportEnum; import ca.uhn.fhir.rest.server.ETagSupportEnum;
import com.google.common.annotations.VisibleForTesting; import com.google.common.annotations.VisibleForTesting;
import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus;
import org.hibernate.search.elasticsearch.cfg.IndexSchemaManagementStrategy;
import org.jetbrains.annotations.NotNull;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.InputStream; import java.io.InputStream;
@@ -62,13 +66,18 @@ public class HapiProperties {
private static final String VALIDATE_RESPONSES_ENABLED = "validation.responses.enabled"; private static final String VALIDATE_RESPONSES_ENABLED = "validation.responses.enabled";
private static final String FILTER_SEARCH_ENABLED = "filter_search.enabled"; private static final String FILTER_SEARCH_ENABLED = "filter_search.enabled";
private static final String GRAPHQL_ENABLED = "graphql.enabled"; private static final String GRAPHQL_ENABLED = "graphql.enabled";
private static Properties properties; private static final String BULK_EXPORT_ENABLED = "bulk.export.enabled";
private static Properties ourProperties;
public static boolean isElasticSearchEnabled() {
return HapiProperties.getPropertyBoolean("elasticsearch.enabled", false);
}
/* /*
* Force the configuration to be reloaded * Force the configuration to be reloaded
*/ */
public static void forceReload() { public static void forceReload() {
properties = null; ourProperties = null;
getProperties(); getProperties();
} }
@@ -81,12 +90,40 @@ public class HapiProperties {
getProperties().setProperty(theKey, theValue); getProperties().setProperty(theKey, theValue);
} }
public static Properties getProperties() { public static Properties getJpaProperties() {
if (properties == null) { Properties retVal = loadProperties();
if (isElasticSearchEnabled()) {
ElasticsearchHibernatePropertiesBuilder builder = new ElasticsearchHibernatePropertiesBuilder();
builder.setRequiredIndexStatus(getPropertyEnum("elasticsearch.required_index_status", ElasticsearchIndexStatus.class, ElasticsearchIndexStatus.YELLOW));
builder.setRestUrl(getProperty("elasticsearch.rest_url"));
builder.setUsername(getProperty("elasticsearch.username"));
builder.setPassword(getProperty("elasticsearch.password"));
builder.setIndexSchemaManagementStrategy(getPropertyEnum("elasticsearch.schema_management_strateg", IndexSchemaManagementStrategy.class, IndexSchemaManagementStrategy.CREATE));
builder.setDebugRefreshAfterWrite(getPropertyBoolean("elasticsearch.debug.refresh_after_write", false));
builder.setDebugPrettyPrintJsonLog(getPropertyBoolean("elasticsearch.debug.pretty_print_json_log", false));
builder.apply(retVal);
}
return retVal;
}
private static Properties getProperties() {
if (ourProperties == null) {
Properties properties = loadProperties();
HapiProperties.ourProperties = properties;
}
return ourProperties;
}
@NotNull
private static Properties loadProperties() {
// Load the configurable properties file // Load the configurable properties file
Properties properties;
try (InputStream in = HapiProperties.class.getClassLoader().getResourceAsStream(HAPI_PROPERTIES)) { try (InputStream in = HapiProperties.class.getClassLoader().getResourceAsStream(HAPI_PROPERTIES)) {
HapiProperties.properties = new Properties(); properties = new Properties();
HapiProperties.properties.load(in); properties.load(in);
} catch (Exception e) { } catch (Exception e) {
throw new ConfigurationException("Could not load HAPI properties", e); throw new ConfigurationException("Could not load HAPI properties", e);
} }
@@ -95,8 +132,6 @@ public class HapiProperties {
if (overrideProps != null) { if (overrideProps != null) {
properties.putAll(overrideProps); properties.putAll(overrideProps);
} }
}
return properties; return properties;
} }
@@ -399,5 +434,18 @@ public class HapiProperties {
public static boolean getEnableIndexMissingFields() { public static boolean getEnableIndexMissingFields() {
return HapiProperties.getBooleanProperty(ENABLE_INDEX_MISSING_FIELDS, false); return HapiProperties.getBooleanProperty(ENABLE_INDEX_MISSING_FIELDS, false);
} }
private static boolean getPropertyBoolean(String thePropertyName, boolean theDefaultValue) {
String value = getProperty(thePropertyName, Boolean.toString(theDefaultValue));
return Boolean.parseBoolean(value);
}
private static <T extends Enum> T getPropertyEnum(String thePropertyName, Class<T> theEnumType, T theDefaultValue) {
String value = getProperty(thePropertyName, theDefaultValue.name());
return (T) Enum.valueOf(theEnumType, value);
}
public static boolean getBulkExportEnabled() {
return HapiProperties.getBooleanProperty(BULK_EXPORT_ENABLED, true);
}
} }

View File

@@ -5,11 +5,16 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster; import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
import ca.uhn.fhir.interceptor.api.IInterceptorService; import ca.uhn.fhir.interceptor.api.IInterceptorService;
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor; import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
import ca.uhn.fhir.jpa.bulk.BulkDataExportProvider;
import ca.uhn.fhir.jpa.dao.DaoConfig; import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.DaoRegistry; import ca.uhn.fhir.jpa.dao.DaoRegistry;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao; import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor; import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
import ca.uhn.fhir.jpa.provider.*; import ca.uhn.fhir.jpa.provider.GraphQLProvider;
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
import ca.uhn.fhir.jpa.provider.TerminologyUploaderProvider;
import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3; import ca.uhn.fhir.jpa.provider.dstu3.JpaConformanceProviderDstu3;
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3; import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4; import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
@@ -24,7 +29,11 @@ import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator; import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy; import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
import ca.uhn.fhir.rest.server.RestfulServer; import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.*; import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseValidatingInterceptor;
import ca.uhn.fhir.validation.IValidatorModule; import ca.uhn.fhir.validation.IValidatorModule;
import ca.uhn.fhir.validation.ResultSeverityEnum; import ca.uhn.fhir.validation.ResultSeverityEnum;
import java.util.HashSet; import java.util.HashSet;
@@ -273,6 +282,9 @@ public class JpaRestfulServer extends RestfulServer {
// Validation // Validation
IValidatorModule validatorModule; IValidatorModule validatorModule;
switch (fhirVersion) { switch (fhirVersion) {
case DSTU2:
validatorModule = appCtx.getBean("myInstanceValidatorDstu2", IValidatorModule.class);
break;
case DSTU3: case DSTU3:
validatorModule = appCtx.getBean("myInstanceValidatorDstu3", IValidatorModule.class); validatorModule = appCtx.getBean("myInstanceValidatorDstu3", IValidatorModule.class);
break; break;
@@ -282,6 +294,9 @@ public class JpaRestfulServer extends RestfulServer {
case R5: case R5:
validatorModule = appCtx.getBean("myInstanceValidatorR5", IValidatorModule.class); validatorModule = appCtx.getBean("myInstanceValidatorR5", IValidatorModule.class);
break; break;
// These versions are not supported by HAPI FHIR JPA
case DSTU2_HL7ORG:
case DSTU2_1:
default: default:
validatorModule = null; validatorModule = null;
break; break;
@@ -319,5 +334,12 @@ public class JpaRestfulServer extends RestfulServer {
config.setBundleTypesAllowedForStorage( config.setBundleTypesAllowedForStorage(
Collections.unmodifiableSet(new TreeSet<>(allowedBundleTypes))); Collections.unmodifiableSet(new TreeSet<>(allowedBundleTypes)));
} }
}
// Bulk Export
if (HapiProperties.getBulkExportEnabled()) {
registerProvider(appCtx.getBean(BulkDataExportProvider.class));
}
}
} }

View File

@@ -82,11 +82,34 @@ hibernate.search.default.indexBase=target/lucenefiles
hibernate.search.lucene_version=LUCENE_CURRENT hibernate.search.lucene_version=LUCENE_CURRENT
tester.config.refuse_to_fetch_third_party_urls=false tester.config.refuse_to_fetch_third_party_urls=false
##################################################
# ElasticSearch
# Note that using ElasticSearch is disabled by
# default and the server will use Lucene instead.
##################################################
elasticsearch.enabled=false
elasticsearch.rest_url=http://localhost:9200
elasticsearch.username=SomeUsername
elasticsearch.password=SomePassword
elasticsearch.rest_url=http://localhost:9200
elasticsearch.required_index_status=YELLOW
elasticsearch.schema_management_strategy=CREATE
# Immediately refresh indexes after every write. This is very bad for
# performance, but can be helpful for testing.
elasticsearch.debug.refresh_after_write=false
elasticsearch.debug.pretty_print_json_log=false
################################################## ##################################################
# Binary Storage Operations # Binary Storage Operations
################################################## ##################################################
binary_storage.enabled=true binary_storage.enabled=true
##################################################
# Bulk Data Specification
##################################################
bulk.export.enabled=true
################################################## ##################################################
# CORS Settings # CORS Settings
################################################## ##################################################

View File

@@ -1,30 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head th:fragment="head">
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="description" content="" />
<meta name="author" content="" />
<link rel="icon" type="image/x-icon" href="img/favicon.ico">
<script src="js/jquery-2.1.0.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<link href="css/bootstrap.min.css" rel="stylesheet" />
<link href="css/tester.css" rel="stylesheet" />
<script type="text/javascript" th:utext="'var conformance = ' + ${jsonEncodedConf} + ';'">
</script>
<script type="text/javascript" th:utext="'var resourceName = \'' + ${resourceName} + '\';'">
</script>
<link href="fa/css/font-awesome.min.css" rel="stylesheet" />
<link href="css/hapi-narrative.css" rel="stylesheet" />
<script type="text/javascript" src="js/moment-with-locales.min.js"></script>
<link href="css/bootstrap-datetimepicker.min.css" rel="stylesheet" />
<script src="js/bootstrap-datetimepicker.min.js"></script>
<link href="css/select2.css" rel="stylesheet"/>
<script src="js/select2.min.js"></script>
<script src="js/RestfulTester.js" type="text/javascript" ></script>
</head>
</html>

View File

@@ -14,10 +14,12 @@ import org.eclipse.jetty.websocket.api.Session;
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest; import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
import org.eclipse.jetty.websocket.client.WebSocketClient; import org.eclipse.jetty.websocket.client.WebSocketClient;
import org.hl7.fhir.instance.model.api.IIdType; import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Bundle; import org.hl7.fhir.r5.model.Bundle;
import org.hl7.fhir.r4.model.Observation; import org.hl7.fhir.r5.model.Observation;
import org.hl7.fhir.r4.model.Patient; import org.hl7.fhir.r5.model.Patient;
import org.hl7.fhir.r4.model.Subscription; import org.hl7.fhir.r5.model.Subscription;
import org.hl7.fhir.r5.model.Topic;
import org.hl7.fhir.r5.model.codesystems.SubscriptionChannelType;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
@@ -43,7 +45,7 @@ public class ExampleServerR5IT {
HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr5"); HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr5");
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R5"); HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R5");
HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true"); HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true");
ourCtx = FhirContext.forR4(); ourCtx = FhirContext.forR5();
} }
@Test @Test
@@ -61,17 +63,26 @@ public class ExampleServerR5IT {
@Test @Test
public void testWebsocketSubscription() throws Exception { public void testWebsocketSubscription() throws Exception {
/*
* Create topic
*/
Topic topic = new Topic();
topic.getResourceTrigger().getQueryCriteria().setCurrent("Observation?status=final");
/* /*
* Create subscription * Create subscription
*/ */
Subscription subscription = new Subscription(); Subscription subscription = new Subscription();
subscription.getTopic().setResource(topic);
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)"); subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED); subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED);
subscription.setCriteria("Observation?status=final");
Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent(); Subscription.SubscriptionChannelComponent channel = new Subscription.SubscriptionChannelComponent();
channel.setType(Subscription.SubscriptionChannelType.WEBSOCKET); channel.getType().addCoding()
channel.setPayload("application/json"); .setSystem(SubscriptionChannelType.WEBSOCKET.getSystem())
.setCode(SubscriptionChannelType.WEBSOCKET.toCode());
channel.getPayload().setContentType("application/json");
subscription.setChannel(channel); subscription.setChannel(channel);
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute(); MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();