8
.vscode/settings.json
vendored
Normal file
8
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"files.exclude": {
|
||||
"**/.classpath": true,
|
||||
"**/.project": true,
|
||||
"**/.settings": true,
|
||||
"**/.factorypath": true
|
||||
}
|
||||
}
|
||||
@@ -2,12 +2,12 @@ FROM maven:3.6.3-jdk-11-slim as build-hapi
|
||||
WORKDIR /tmp/hapi-fhir-jpaserver-starter
|
||||
|
||||
COPY pom.xml .
|
||||
RUN mvn dependency:go-offline
|
||||
RUN mvn -ntp dependency:go-offline
|
||||
|
||||
COPY src/ /tmp/hapi-fhir-jpaserver-starter/src/
|
||||
RUN mvn clean install -DskipTests
|
||||
|
||||
FROM tomcat:9.0.37-jdk11-openjdk-slim-buster
|
||||
FROM tomcat:9.0.38-jdk11-openjdk-slim-buster
|
||||
|
||||
RUN mkdir -p /data/hapi/lucenefiles && chmod 775 /data/hapi/lucenefiles
|
||||
COPY --from=build-hapi /tmp/hapi-fhir-jpaserver-starter/target/*.war /usr/local/tomcat/webapps/
|
||||
|
||||
176
README.md
176
README.md
@@ -4,40 +4,47 @@ This project is a complete starter project you can use to deploy a FHIR server u
|
||||
|
||||
Note that this project is specifically intended for end users of the HAPI FHIR JPA server module (in other words, it helps you implement HAPI FHIR, it is not the source of the library itself). If you are looking for the main HAPI FHIR project, see here: https://github.com/jamesagnew/hapi-fhir
|
||||
|
||||
Need Help? Please see: https://github.com/jamesagnew/hapi-fhir/wiki/Getting-Help
|
||||
|
||||
## Prerequisites
|
||||
|
||||
In order to use this sample, you should have:
|
||||
|
||||
- [This project](https://github.com/hapifhir/hapi-fhir-jpaserver-starter) checked out. You may wish to create a GitHub Fork of the project and check that out instead so that you can customize the project and save the results to GitHub.
|
||||
|
||||
### and either
|
||||
- Oracle Java (JDK) installed: Minimum JDK8 or newer.
|
||||
- Apache Maven build tool (newest version)
|
||||
|
||||
### or
|
||||
- Docker, as the entire project can be built using multistage docker (with both JDK and maven wrapped in docker) or used directly from [Docker Hub](https://hub.docker.com/repository/docker/hapiproject/hapi)
|
||||
|
||||
## Running via [Docker Hub](https://hub.docker.com/repository/docker/hapiproject/hapi)
|
||||
|
||||
Each tagged/released version of `hapi-fhir-jpaserver` is built as a Docker image and published to Docker hub. To run the published Docker image from DockerHub:
|
||||
|
||||
```
|
||||
docker pull hapiproject/hapi:latest
|
||||
docker run -p 8080:8080 hapiproject/hapi:tagname
|
||||
docker run -p 8080:8080 -e "spring.batch.job.enabled=false" hapiproject/hapi:tagname
|
||||
```
|
||||
|
||||
This will run the docker image with the default configuration, mapping port 8080 from the container to port 8080 in the host. Once running, you can access `http://localhost:8080/hapi-fhir-jpaserver/fhir` in the browser to access the HAPI FHIR server's UI.
|
||||
This will run the docker image with the default configuration, mapping port 8080 from the container to port 8080 in the host. Once running, you can access `http://localhost:8080/hapi-fhir-jpaserver/` in the browser to access the HAPI FHIR server's UI.
|
||||
|
||||
If you change the mapped port, you need to change the configuration used by HAPI to have the correct `server_address` property/value.
|
||||
If you change the mapped port, you need to change the configuration used by HAPI to have the correct `hapi.fhir.tester` property/value.
|
||||
|
||||
### Configuration via environment variables
|
||||
|
||||
You can customize HAPI directly from the `run` command using environment variables. For example:
|
||||
|
||||
`docker run -p 8090:8080 -e server_address=http://localhost:8090/hapi-fhir-jpaserver/fhir hapiproject/hapi:tagname`
|
||||
`docker run -p 8080:8080 -e hapi.fhir.default_encoding=xml hapiproject/hapi:tagname`
|
||||
|
||||
HAPI looks in the environment variables for properties in the [hapi.properties](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/hapi.properties) file.
|
||||
HAPI looks in the environment variables for properties in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file for defaults.
|
||||
|
||||
### Configuration via overridden hapi.properties file
|
||||
### Configuration via overridden application.yaml file
|
||||
|
||||
You can customize HAPI by telling HAPI to look for the `hapi.properties` file in a different location:
|
||||
You can customize HAPI by telling HAPI to look for the configuration file in a different location, eg.:
|
||||
|
||||
`docker run -p 8090:8080 -e hapi.properties=/some/directory/with/hapi.properties hapiproject/hapi:tagname`
|
||||
`docker run -p 8090:8080 -e "--spring.config.location=classpath:/another.application.yaml" hapiproject/hapi:tagname`
|
||||
|
||||
### Example docker-compose.yml
|
||||
|
||||
@@ -50,11 +57,11 @@ services:
|
||||
- "8090:8080"
|
||||
configs:
|
||||
- source: hapi
|
||||
target: /data/hapi/hapi.properties
|
||||
target: /data/hapi/application.yaml
|
||||
volumes:
|
||||
- hapi-data:/data/hapi
|
||||
environment:
|
||||
JAVA_OPTS: '-Dhapi.properties=/data/hapi/hapi.properties'
|
||||
SPRING_CONFIG_LOCATION: 'file:///data/hapi/application.yaml'
|
||||
configs:
|
||||
hapi:
|
||||
external: true
|
||||
@@ -65,15 +72,13 @@ volumes:
|
||||
|
||||
## Running locally
|
||||
|
||||
The easiest way to run this server is to run it directly in Maven using a built-in Jetty server. To do this, change `src/main/resources/hapi.properties` `server_address` and `server.base` with the values commented out as _For Jetty, use this_ and then execute the following command:
|
||||
The easiest way to run this server entirely depends on your environment requirements. At least, the following 4 ways are supported:
|
||||
|
||||
### Using jetty
|
||||
```bash
|
||||
mvn jetty:run
|
||||
mvn jetty:run -Dspring.batch.job.enabled=false
|
||||
```
|
||||
|
||||
Then, browse to the following link to use the server:
|
||||
|
||||
[http://localhost:8080/hapi-fhir-jpaserver/](http://localhost:8080/hapi-fhir-jpaserver/)
|
||||
|
||||
If you need to run this server on a different port (using Maven), you can change the port in the run command as follows:
|
||||
|
||||
@@ -81,43 +86,98 @@ If you need to run this server on a different port (using Maven), you can change
|
||||
mvn -Djetty.port=8888 jetty:run
|
||||
```
|
||||
|
||||
And replacing 8888 with the port of your choice.
|
||||
Server will then be accessible at http://localhost:8888/ and eg. http://localhost:8888/fhir/metadata. Remember to adjust you overlay configuration in the application.yaml to eg.
|
||||
|
||||
```yaml
|
||||
tester:
|
||||
-
|
||||
id: home
|
||||
name: Local Tester
|
||||
server_address: 'http://localhost:8888/fhir'
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
```
|
||||
|
||||
|
||||
|
||||
### Using Spring Boot
|
||||
```bash
|
||||
mvn clean package spring-boot:repackage -Pboot && java -jar target/ROOT.war
|
||||
```
|
||||
Server will then be accessible at http://localhost:8080/ and eg. http://localhost:8080/fhir/metadata. Remember to adjust you overlay configuration in the application.yaml to eg.
|
||||
|
||||
```yaml
|
||||
tester:
|
||||
-
|
||||
id: home
|
||||
name: Local Tester
|
||||
server_address: 'http://localhost:8080/fhir'
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
```
|
||||
### Using Spring Boot and Google distroless
|
||||
```bash
|
||||
mvn clean package com.google.cloud.tools:jib-maven-plugin:dockerBuild -Dimage=distroless-hapi && docker run -p 8080:8080 -e spring.batch.job.enabled=false distroless-hapi
|
||||
```
|
||||
Server will then be accessible at http://localhost:8080/ and eg. http://localhost:8080/fhir/metadata. Remember to adjust you overlay configuration in the application.yaml to eg.
|
||||
|
||||
```yaml
|
||||
tester:
|
||||
-
|
||||
id: home
|
||||
name: Local Tester
|
||||
server_address: 'http://localhost:8080/fhir'
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
```
|
||||
|
||||
### Using the Dockerfile and multistage build
|
||||
```bash
|
||||
./build-docker-image.sh && docker run -p 8080:8080 -e "spring.batch.job.enabled=false" hapi-fhir/hapi-fhir-jpaserver-starter:latest
|
||||
```
|
||||
Server will then be accessible at http://localhost:8080/ and eg. http://localhost:8080/fhir/metadata. Remember to adjust you overlay configuration in the application.yaml to eg.
|
||||
|
||||
```yaml
|
||||
tester:
|
||||
-
|
||||
id: home
|
||||
name: Local Tester
|
||||
server_address: 'http://localhost:8080/fhir'
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
```
|
||||
|
||||
## Configurations
|
||||
|
||||
Much of this HAPI starter project can be configured using the properties file in _src/main/resources/hapi.properties_. By default, this starter project is configured to use Derby as the database.
|
||||
Much of this HAPI starter project can be configured using the yaml file in _src/main/resources/application.yaml_. By default, this starter project is configured to use H2 as the database.
|
||||
|
||||
### MySql configuration
|
||||
|
||||
To configure the starter app to use MySQL, instead of the default Derby, update the hapi.properties file to have the following:
|
||||
To configure the starter app to use MySQL, instead of the default H2, update the application.yaml file to have the following:
|
||||
|
||||
- datasource.driver=com.mysql.jdbc.Driver
|
||||
- datasource.url=jdbc:mysql://localhost:3306/hapi_dstu3
|
||||
- hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
- datasource.username=admin
|
||||
- datasource.password=admin
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: 'jdbc:mysql://localhost:3306/hapi_dstu3'
|
||||
username: admin
|
||||
password: admin
|
||||
driverClassName: com.mysql.jdbc.Driver
|
||||
```
|
||||
|
||||
### PostgreSQL configuration
|
||||
|
||||
To configure the starter app to use PostgreSQL, instead of the default Derby, update the hapi.properties file to have the following:
|
||||
To configure the starter app to use PostgreSQL, instead of the default H2, update the application.yaml file to have the following:
|
||||
|
||||
- datasource.driver=org.postgresql.Driver
|
||||
- datasource.url=jdbc:postgresql://localhost:5432/hapi_dstu3
|
||||
- hibernate.dialect=org.hibernate.dialect.PostgreSQL95Dialect
|
||||
- datasource.username=admin
|
||||
- datasource.password=admin
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: 'jdbc:postgresql://localhost:5432/hapi_dstu3'
|
||||
username: admin
|
||||
password: admin
|
||||
driverClassName: org.postgresql.Driver
|
||||
```
|
||||
|
||||
Because the integration tests within the project rely on the default Derby database configuration, it is important to either explicity skip the integration tests during the build process, i.e., `mvn install -DskipTests`, or delete the tests altogether. Failure to skip or delete the tests once you've configured PostgreSQL for the datasource.driver, datasource.url, and hibernate.dialect as outlined above will result in build errors and compilation failure.
|
||||
|
||||
It is important to use PostgreSQL95Dialect when using PostgreSQL version 10+.
|
||||
|
||||
## Overriding application properties
|
||||
|
||||
You can override the properties that are loaded into the compiled web app (.war file) making a copy of the hapi.properties file on the file system, making changes to it, and then setting the JAVA_OPTS environment variable on the tomcat server to tell hapi-jpaserver-starter where the overriding properties file is. For example:
|
||||
|
||||
`-Dhapi.properties=/some/custom/directory/hapi.properties`
|
||||
|
||||
Note: This property name and the path is case-sensitive. "-DHAPI.PROPERTIES=XXX" will not work.
|
||||
Because the integration tests within the project rely on the default H2 database configuration, it is important to either explicity skip the integration tests during the build process, i.e., `mvn install -DskipTests`, or delete the tests altogether. Failure to skip or delete the tests once you've configured PostgreSQL for the datasource.driver, datasource.url, and hibernate.dialect as outlined above will result in build errors and compilation failure.
|
||||
|
||||
## Customizing The Web Testpage UI
|
||||
|
||||
@@ -127,7 +187,7 @@ The UI is customized using [Thymeleaf](https://www.thymeleaf.org/) template file
|
||||
|
||||
Several template files that can be customized are found in the following directory: [https://github.com/hapifhir/hapi-fhir-jpaserver-starter/tree/master/src/main/webapp/WEB-INF/templates](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/tree/master/src/main/webapp/WEB-INF/templates)
|
||||
|
||||
## Deploying to a Container
|
||||
## Deploying to an Application Server
|
||||
|
||||
Using the Maven-Embedded Jetty method above is convenient, but it is not a good solution if you want to leave the server running in the background.
|
||||
|
||||
@@ -147,6 +207,8 @@ Again, browse to the following link to use the server (note that the port 8080 m
|
||||
|
||||
[http://localhost:8080/hapi-fhir-jpaserver/](http://localhost:8080/hapi-fhir-jpaserver/)
|
||||
|
||||
If you would like it to be hosted at the root, eg. http://localhost:8080/ - then rename the WAR file to ```ROOT.war```.
|
||||
|
||||
## Deploy with docker compose
|
||||
|
||||
Docker compose is a simple option to build and deploy container. To deploy with docker compose, you should build the project
|
||||
@@ -156,14 +218,20 @@ reached at http://localhost:8080/hapi-fhir-jpaserver/.
|
||||
In order to use another port, change the `ports` parameter
|
||||
inside `docker-compose.yml` to `8888:8080`, where 8888 is a port of your choice.
|
||||
|
||||
The docker compose set also includes my MySQL database, if you choose to use MySQL instead of derby, change the following
|
||||
properties in hapi.properties:
|
||||
The docker compose set also includes my MySQL database, if you choose to use MySQL instead of H2, change the following
|
||||
properties in application.yaml:
|
||||
|
||||
- datasource.driver=com.mysql.jdbc.Driver
|
||||
- datasource.url=jdbc:mysql://hapi-fhir-mysql:3306/hapi
|
||||
- hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect
|
||||
- datasource.username=admin
|
||||
- datasource.password=admin
|
||||
```yaml
|
||||
spring:
|
||||
datasource:
|
||||
url: 'jdbc:mysql://hapi-fhir-mysql:3306/hapi'
|
||||
username: admin
|
||||
password: admin
|
||||
driverClassName: com.mysql.jdbc.Driver
|
||||
```
|
||||
|
||||
## Running hapi-fhir-jpaserver direclty from IntelliJ as Spring Boot
|
||||
Make sure you run with the maven profile called ```boot``` and NOT also ```jetty```. Then you are ready to press debug the project directly without any extra Application Servers.
|
||||
|
||||
## Running hapi-fhir-jpaserver-example in Tomcat from IntelliJ
|
||||
|
||||
@@ -201,21 +269,21 @@ It is important to use MySQL5Dialect when using MySQL version 5+.
|
||||
|
||||
## Enabling Subscriptions
|
||||
|
||||
The server may be configured with subscription support by enabling properties in the [hapi.properties](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/hapi.properties) file:
|
||||
The server may be configured with subscription support by enabling properties in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file:
|
||||
|
||||
- `subscription.resthook.enabled` - Enables REST Hook subscriptions, where the server will make an outgoing connection to a remote REST server
|
||||
- `hapi.fhir.subscription.resthook.enabled` - Enables REST Hook subscriptions, where the server will make an outgoing connection to a remote REST server
|
||||
|
||||
- `subscription.email.enabled` - Enables email subscriptions. Note that you must also provide the connection details for a usable SMTP server.
|
||||
- `hapi.fhir.subscription.email.*` - 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)
|
||||
- `hapi.fhir.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)
|
||||
|
||||
## Enabling EMPI
|
||||
|
||||
Set `empi.enabled=true` in the [hapi.properties](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/hapi.properties) file to enable EMPI on this server. The EMPI matching rules are configured in [empi-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/empi-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. Note that EMPI relies on subscriptions, so for EMPI to work, subscriptions must be enabled.
|
||||
Set `hapi.fhir.empi_enabled=true` in the [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml) file to enable EMPI on this server. The EMPI matching rules are configured in [empi-rules.json](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/empi-rules.json). The rules in this example file should be replaced with actual matching rules appropriate to your data. Note that EMPI relies on subscriptions, so for EMPI to work, subscriptions must be enabled.
|
||||
|
||||
## 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)
|
||||
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 [application.yaml](https://github.com/hapifhir/hapi-fhir-jpaserver-starter/blob/master/src/main/resources/application.yaml)
|
||||
|
||||
For example:
|
||||
|
||||
|
||||
132
pom.xml
132
pom.xml
@@ -3,6 +3,8 @@
|
||||
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>
|
||||
|
||||
<!-- one-liner to take you to the cloud with settings form the application.yaml file: -->
|
||||
<!-- 'mvn clean package com.google.cloud.tools:jib-maven-plugin:dockerBuild -Dimage=distroless-hapi && docker run -p 8080:8080 -e spring.batch.job.enabled=false distroless-hapi' -->
|
||||
<!--
|
||||
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
|
||||
@@ -17,8 +19,13 @@
|
||||
|
||||
<artifactId>hapi-fhir-jpaserver-starter</artifactId>
|
||||
|
||||
<properties>
|
||||
<java.version>8</java.version>
|
||||
<spring_boot_version>2.3.4.RELEASE</spring_boot_version>
|
||||
</properties>
|
||||
|
||||
<prerequisites>
|
||||
<maven>3.5.0</maven>
|
||||
<maven>3.6.3</maven>
|
||||
</prerequisites>
|
||||
|
||||
<packaging>war</packaging>
|
||||
@@ -69,12 +76,6 @@
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>javax.mail</groupId>
|
||||
<artifactId>javax.mail-api</artifactId>
|
||||
</dependency>
|
||||
-->
|
||||
|
||||
<!-- This dependency includes the core HAPI-FHIR classes -->
|
||||
<dependency>
|
||||
@@ -118,7 +119,7 @@
|
||||
<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
|
||||
@@ -240,18 +241,7 @@
|
||||
<artifactId>jetty-webapp</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<!--
|
||||
<dependency>
|
||||
<groupId>com.helger</groupId>
|
||||
<artifactId>ph-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
|
||||
@@ -276,15 +266,58 @@
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-autoconfigure</artifactId>
|
||||
<version>${spring_boot_version}</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-api</artifactId>
|
||||
<version>5.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter-engine</artifactId>
|
||||
<version>5.6.2</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<version>${spring_boot_version}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
||||
<!-- Tells Maven to name the generated WAR file as hapi-fhir-jpaserver.war -->
|
||||
<finalName>hapi-fhir-jpaserver</finalName>
|
||||
<!-- Tells Maven to name the generated WAR file as ROOT.war -->
|
||||
<finalName>ROOT</finalName>
|
||||
|
||||
<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.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<mainClass>ca.uhn.fhir.jpa.starter.Application</mainClass>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
<!-- The following is not required for the application to build, but allows you to test it by issuing "mvn package jetty:run -Dspring.batch.job.enabled=false" from the command line. -->
|
||||
<!--
|
||||
<plugin>
|
||||
<groupId>org.eclipse.jetty</groupId>
|
||||
<artifactId>jetty-maven-plugin</artifactId>
|
||||
@@ -296,14 +329,15 @@
|
||||
</webApp>
|
||||
</configuration>
|
||||
</plugin>
|
||||
-->
|
||||
|
||||
<!-- Tell Maven which Java source version you want to use -->
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-compiler-plugin</artifactId>
|
||||
<version>3.8.1</version>
|
||||
<configuration>
|
||||
<source>1.8</source>
|
||||
<target>1.8</target>
|
||||
<release>8</release>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -323,7 +357,7 @@
|
||||
<artifactId>hapi-fhir-testpage-overlay</artifactId>
|
||||
</overlay>
|
||||
</overlays>
|
||||
<webXml>src/main/webapp/WEB-INF/web.xml</webXml>
|
||||
<failOnMissingWebXml>false</failOnMissingWebXml>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
@@ -438,9 +472,51 @@
|
||||
</ignoredResourcePatterns>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
<profiles>
|
||||
<!-- Package the war for your preference. Use the boot profile if you prefer a single jar/war
|
||||
that can be started with and embedded application server. Default is jetty as it is assumed
|
||||
that the main users of this project already have an app server.
|
||||
Different profiles are needed as packing it for spring boot, makes the resulting war undeployable
|
||||
due to a class shading issue between tomcat and jetty.
|
||||
(the error is 'java.util.ServiceConfigurationError: org.apache.juli.logging.Log: org.eclipse.jetty.apache.jsp.JuliLog not a subtype')
|
||||
|
||||
-->
|
||||
|
||||
<!-- example of how to start the server using spring boot-->
|
||||
<!-- mvn clean package spring-boot:repackage -Pboot && java -jar target/hapi-fhir-jpaserver.war -->
|
||||
|
||||
<!-- Use the boot profile for development and debugging options when using your IDE -->
|
||||
<profile>
|
||||
<id>boot</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring_boot_version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
<!-- examples of how to start the server using the default profile-->
|
||||
<!-- mvn clean package jetty:run -Dspring.batch.job.enabled=false -->
|
||||
<!-- java -jar -Dspring.batch.job.enabled=false jetty-runner.jar target/hapi-fhir-jpaserver.war -->
|
||||
<profile>
|
||||
<id>jetty</id>
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
<version>${spring_boot_version}</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-tomcat</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</profile>
|
||||
</profiles>
|
||||
</project>
|
||||
|
||||
@@ -1,13 +1,20 @@
|
||||
package ca.uhn.fhir.jpa.empi;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.empi.api.IEmpiSettings;
|
||||
import ca.uhn.fhir.empi.rules.config.EmpiRuleValidator;
|
||||
import ca.uhn.fhir.empi.rules.config.EmpiSettings;
|
||||
import ca.uhn.fhir.jpa.starter.HapiProperties;
|
||||
import ca.uhn.fhir.jpa.empi.config.EmpiConsumerConfig;
|
||||
import ca.uhn.fhir.jpa.empi.config.EmpiSubmitterConfig;
|
||||
import ca.uhn.fhir.jpa.starter.AppProperties;
|
||||
import ca.uhn.fhir.rest.server.util.ISearchParamRetriever;
|
||||
import com.google.common.base.Charsets;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Conditional;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.core.io.DefaultResourceLoader;
|
||||
import org.springframework.core.io.Resource;
|
||||
|
||||
@@ -18,14 +25,21 @@ import java.io.IOException;
|
||||
* in 5.1.0 picks this up even if EMPI is disabled currently.
|
||||
*/
|
||||
@Configuration
|
||||
@Conditional(EmpiConfigCondition.class)
|
||||
@Import({EmpiConsumerConfig.class, EmpiSubmitterConfig.class})
|
||||
public class EmpiConfig {
|
||||
|
||||
@Bean
|
||||
IEmpiSettings empiSettings(EmpiRuleValidator theEmpiRuleValidator) throws IOException {
|
||||
EmpiRuleValidator empiRuleValidator(FhirContext theFhirContext, ISearchParamRetriever theSearchParamRetriever) {
|
||||
return new EmpiRuleValidator(theFhirContext, theSearchParamRetriever);
|
||||
}
|
||||
|
||||
@Bean
|
||||
IEmpiSettings empiSettings(@Autowired EmpiRuleValidator theEmpiRuleValidator, AppProperties appProperties) throws IOException {
|
||||
DefaultResourceLoader resourceLoader = new DefaultResourceLoader();
|
||||
Resource resource = resourceLoader.getResource("empi-rules.json");
|
||||
String json = IOUtils.toString(resource.getInputStream(), Charsets.UTF_8);
|
||||
return new EmpiSettings(theEmpiRuleValidator).setEnabled(HapiProperties.getEmpiEnabled()).setScriptText(json);
|
||||
return new EmpiSettings(theEmpiRuleValidator).setEnabled(appProperties.getEmpi_enabled()).setScriptText(json);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
13
src/main/java/ca/uhn/fhir/jpa/empi/EmpiConfigCondition.java
Normal file
13
src/main/java/ca/uhn/fhir/jpa/empi/EmpiConfigCondition.java
Normal file
@@ -0,0 +1,13 @@
|
||||
package ca.uhn.fhir.jpa.empi;
|
||||
|
||||
import org.springframework.context.annotation.Condition;
|
||||
import org.springframework.context.annotation.ConditionContext;
|
||||
import org.springframework.core.type.AnnotatedTypeMetadata;
|
||||
|
||||
public class EmpiConfigCondition implements Condition {
|
||||
@Override
|
||||
public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata metadata) {
|
||||
String property = conditionContext.getEnvironment().getProperty("hapi.fhir.empi_enabled");
|
||||
return Boolean.parseBoolean(property);
|
||||
}
|
||||
}
|
||||
669
src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java
Normal file
669
src/main/java/ca/uhn/fhir/jpa/starter/AppProperties.java
Normal file
@@ -0,0 +1,669 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig.ClientIdStrategyEnum;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
|
||||
@ConfigurationProperties(prefix = "hapi.fhir")
|
||||
@Configuration
|
||||
@EnableConfigurationProperties
|
||||
public class AppProperties {
|
||||
|
||||
private Boolean empi_enabled = false;
|
||||
private Boolean allow_cascading_deletes = false;
|
||||
private Boolean allow_contains_searches = true;
|
||||
private Boolean allow_external_references = false;
|
||||
private Boolean allow_multiple_delete = false;
|
||||
private Boolean allow_override_default_search_params = true;
|
||||
private Boolean allow_placeholder_references = true;
|
||||
private Boolean auto_create_placeholder_reference_targets = true;
|
||||
private Boolean enable_index_missing_fields = false;
|
||||
private Boolean enforce_referential_integrity_on_delete = true;
|
||||
private Boolean enforce_referential_integrity_on_write = true;
|
||||
private Boolean etag_support_enabled = true;
|
||||
private Boolean expunge_enabled = true;
|
||||
private Boolean fhirpath_interceptor_enabled = false;
|
||||
private Boolean filter_search_enabled = true;
|
||||
private Boolean graphql_enabled = false;
|
||||
private Boolean binary_storage_enabled = false;
|
||||
private Boolean bulk_export_enabled = false;
|
||||
private Boolean default_pretty_print = true;
|
||||
private Integer default_page_size = 20;
|
||||
private Integer max_binary_size = null;
|
||||
private Integer max_page_size = Integer.MAX_VALUE;
|
||||
private Integer defer_indexing_for_codesystems_of_size = 100;
|
||||
private Long retain_cached_searches_mins = 60L;
|
||||
private Long reuse_cached_search_results_millis = 60000L;
|
||||
private String server_address = null;
|
||||
private EncodingEnum default_encoding = EncodingEnum.JSON;
|
||||
private FhirVersionEnum fhir_version = FhirVersionEnum.R4;
|
||||
private ClientIdStrategyEnum client_id_strategy = ClientIdStrategyEnum.ALPHANUMERIC;
|
||||
private List<String> supported_resource_types = new ArrayList<>();
|
||||
private List<Bundle.BundleType> allowed_bundle_types = null;
|
||||
|
||||
private Validation validation = new Validation();
|
||||
private List<Tester> tester = ImmutableList.of(new Tester());
|
||||
private Logger logger = new Logger();
|
||||
private Subscription subscription = new Subscription();
|
||||
private Cors cors = null;
|
||||
private Partitioning partitioning = null;
|
||||
private List<ImplementationGuide> implementationGuides = null;
|
||||
|
||||
public Integer getDefer_indexing_for_codesystems_of_size() {
|
||||
return defer_indexing_for_codesystems_of_size;
|
||||
}
|
||||
|
||||
public void setDefer_indexing_for_codesystems_of_size(Integer defer_indexing_for_codesystems_of_size) {
|
||||
this.defer_indexing_for_codesystems_of_size = defer_indexing_for_codesystems_of_size;
|
||||
}
|
||||
|
||||
public List<ImplementationGuide> getImplementationGuides() {
|
||||
return implementationGuides;
|
||||
}
|
||||
|
||||
public void setImplementationGuides(List<ImplementationGuide> implementationGuides) {
|
||||
this.implementationGuides = implementationGuides;
|
||||
}
|
||||
|
||||
public Partitioning getPartitioning() {
|
||||
return partitioning;
|
||||
}
|
||||
|
||||
public void setPartitioning(Partitioning partitioning) {
|
||||
this.partitioning = partitioning;
|
||||
}
|
||||
|
||||
public Boolean getEmpi_enabled() {
|
||||
return empi_enabled;
|
||||
}
|
||||
|
||||
public void setEmpi_enabled(Boolean empi_enabled) {
|
||||
this.empi_enabled = empi_enabled;
|
||||
}
|
||||
|
||||
|
||||
public Cors getCors() {
|
||||
return cors;
|
||||
}
|
||||
|
||||
public void setCors(Cors cors) {
|
||||
this.cors = cors;
|
||||
}
|
||||
|
||||
public List<Bundle.BundleType> getAllowed_bundle_types() {
|
||||
return allowed_bundle_types;
|
||||
}
|
||||
|
||||
public void setAllowed_bundle_types(List<Bundle.BundleType> allowed_bundle_types) {
|
||||
this.allowed_bundle_types = allowed_bundle_types;
|
||||
}
|
||||
|
||||
public String getServer_address() {
|
||||
return server_address;
|
||||
}
|
||||
|
||||
public void setServer_address(String server_address) {
|
||||
this.server_address = server_address;
|
||||
}
|
||||
|
||||
public Subscription getSubscription() {
|
||||
return subscription;
|
||||
}
|
||||
|
||||
public Boolean getDefault_pretty_print() {
|
||||
return default_pretty_print;
|
||||
}
|
||||
|
||||
public void setDefault_pretty_print(Boolean default_pretty_print) {
|
||||
this.default_pretty_print = default_pretty_print;
|
||||
}
|
||||
|
||||
public void setSubscription(Subscription subscription) {
|
||||
this.subscription = subscription;
|
||||
}
|
||||
|
||||
public Validation getValidation() {
|
||||
return validation;
|
||||
}
|
||||
|
||||
public void setValidation(Validation validation) {
|
||||
this.validation = validation;
|
||||
}
|
||||
|
||||
public List<String> getSupported_resource_types() {
|
||||
return supported_resource_types;
|
||||
}
|
||||
|
||||
public void setSupported_resource_types(List<String> supported_resource_types) {
|
||||
this.supported_resource_types = supported_resource_types;
|
||||
}
|
||||
|
||||
public Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
|
||||
public void setLogger(Logger logger) {
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
public ClientIdStrategyEnum getClient_id_strategy() {
|
||||
return client_id_strategy;
|
||||
}
|
||||
|
||||
public void setClient_id_strategy(
|
||||
ClientIdStrategyEnum client_id_strategy) {
|
||||
this.client_id_strategy = client_id_strategy;
|
||||
}
|
||||
|
||||
public Boolean getAllow_cascading_deletes() {
|
||||
return allow_cascading_deletes;
|
||||
}
|
||||
|
||||
public void setAllow_cascading_deletes(Boolean allow_cascading_deletes) {
|
||||
this.allow_cascading_deletes = allow_cascading_deletes;
|
||||
}
|
||||
|
||||
public Boolean getAllow_contains_searches() {
|
||||
return allow_contains_searches;
|
||||
}
|
||||
|
||||
public void setAllow_contains_searches(Boolean allow_contains_searches) {
|
||||
this.allow_contains_searches = allow_contains_searches;
|
||||
}
|
||||
|
||||
public Boolean getAllow_external_references() {
|
||||
return allow_external_references;
|
||||
}
|
||||
|
||||
public void setAllow_external_references(Boolean allow_external_references) {
|
||||
this.allow_external_references = allow_external_references;
|
||||
}
|
||||
|
||||
public Boolean getAllow_multiple_delete() {
|
||||
return allow_multiple_delete;
|
||||
}
|
||||
|
||||
public void setAllow_multiple_delete(Boolean allow_multiple_delete) {
|
||||
this.allow_multiple_delete = allow_multiple_delete;
|
||||
}
|
||||
|
||||
public Boolean getAllow_override_default_search_params() {
|
||||
return allow_override_default_search_params;
|
||||
}
|
||||
|
||||
public void setAllow_override_default_search_params(
|
||||
Boolean allow_override_default_search_params) {
|
||||
this.allow_override_default_search_params = allow_override_default_search_params;
|
||||
}
|
||||
|
||||
public Boolean getAllow_placeholder_references() {
|
||||
return allow_placeholder_references;
|
||||
}
|
||||
|
||||
public void setAllow_placeholder_references(Boolean allow_placeholder_references) {
|
||||
this.allow_placeholder_references = allow_placeholder_references;
|
||||
}
|
||||
|
||||
public Boolean getAuto_create_placeholder_reference_targets() {
|
||||
return auto_create_placeholder_reference_targets;
|
||||
}
|
||||
|
||||
public void setAuto_create_placeholder_reference_targets(
|
||||
Boolean auto_create_placeholder_reference_targets) {
|
||||
this.auto_create_placeholder_reference_targets = auto_create_placeholder_reference_targets;
|
||||
}
|
||||
|
||||
public Integer getDefault_page_size() {
|
||||
return default_page_size;
|
||||
}
|
||||
|
||||
public void setDefault_page_size(Integer default_page_size) {
|
||||
this.default_page_size = default_page_size;
|
||||
}
|
||||
|
||||
public Boolean getEnable_index_missing_fields() {
|
||||
return enable_index_missing_fields;
|
||||
}
|
||||
|
||||
public void setEnable_index_missing_fields(Boolean enable_index_missing_fields) {
|
||||
this.enable_index_missing_fields = enable_index_missing_fields;
|
||||
}
|
||||
|
||||
public Boolean getEnforce_referential_integrity_on_delete() {
|
||||
return enforce_referential_integrity_on_delete;
|
||||
}
|
||||
|
||||
public void setEnforce_referential_integrity_on_delete(
|
||||
Boolean enforce_referential_integrity_on_delete) {
|
||||
this.enforce_referential_integrity_on_delete = enforce_referential_integrity_on_delete;
|
||||
}
|
||||
|
||||
public Boolean getEnforce_referential_integrity_on_write() {
|
||||
return enforce_referential_integrity_on_write;
|
||||
}
|
||||
|
||||
public void setEnforce_referential_integrity_on_write(
|
||||
Boolean enforce_referential_integrity_on_write) {
|
||||
this.enforce_referential_integrity_on_write = enforce_referential_integrity_on_write;
|
||||
}
|
||||
|
||||
public Boolean getEtag_support_enabled() {
|
||||
return etag_support_enabled;
|
||||
}
|
||||
|
||||
public void setEtag_support_enabled(Boolean etag_support_enabled) {
|
||||
this.etag_support_enabled = etag_support_enabled;
|
||||
}
|
||||
|
||||
public Boolean getExpunge_enabled() {
|
||||
return expunge_enabled;
|
||||
}
|
||||
|
||||
public void setExpunge_enabled(Boolean expunge_enabled) {
|
||||
this.expunge_enabled = expunge_enabled;
|
||||
}
|
||||
|
||||
public Boolean getFhirpath_interceptor_enabled() {
|
||||
return fhirpath_interceptor_enabled;
|
||||
}
|
||||
|
||||
public void setFhirpath_interceptor_enabled(Boolean fhirpath_interceptor_enabled) {
|
||||
this.fhirpath_interceptor_enabled = fhirpath_interceptor_enabled;
|
||||
}
|
||||
|
||||
public Boolean getFilter_search_enabled() {
|
||||
return filter_search_enabled;
|
||||
}
|
||||
|
||||
public void setFilter_search_enabled(Boolean filter_search_enabled) {
|
||||
this.filter_search_enabled = filter_search_enabled;
|
||||
}
|
||||
|
||||
public Boolean getGraphql_enabled() {
|
||||
return graphql_enabled;
|
||||
}
|
||||
|
||||
public void setGraphql_enabled(Boolean graphql_enabled) {
|
||||
this.graphql_enabled = graphql_enabled;
|
||||
}
|
||||
|
||||
public Boolean getBinary_storage_enabled() {
|
||||
return binary_storage_enabled;
|
||||
}
|
||||
|
||||
public void setBinary_storage_enabled(Boolean binary_storage_enabled) {
|
||||
this.binary_storage_enabled = binary_storage_enabled;
|
||||
}
|
||||
|
||||
public Boolean getBulk_export_enabled() {
|
||||
return bulk_export_enabled;
|
||||
}
|
||||
|
||||
public void setBulk_export_enabled(Boolean bulk_export_enabled) {
|
||||
this.bulk_export_enabled = bulk_export_enabled;
|
||||
}
|
||||
|
||||
public EncodingEnum getDefault_encoding() {
|
||||
return default_encoding;
|
||||
}
|
||||
|
||||
public void setDefault_encoding(EncodingEnum default_encoding) {
|
||||
this.default_encoding = default_encoding;
|
||||
}
|
||||
|
||||
public FhirVersionEnum getFhir_version() {
|
||||
return fhir_version;
|
||||
}
|
||||
|
||||
public void setFhir_version(FhirVersionEnum fhir_version) {
|
||||
this.fhir_version = fhir_version;
|
||||
}
|
||||
|
||||
public Integer getMax_binary_size() {
|
||||
return max_binary_size;
|
||||
}
|
||||
|
||||
public void setMax_binary_size(Integer max_binary_size) {
|
||||
this.max_binary_size = max_binary_size;
|
||||
}
|
||||
|
||||
public Integer getMax_page_size() {
|
||||
return max_page_size;
|
||||
}
|
||||
|
||||
public void setMax_page_size(Integer max_page_size) {
|
||||
this.max_page_size = max_page_size;
|
||||
}
|
||||
|
||||
public Long getRetain_cached_searches_mins() {
|
||||
return retain_cached_searches_mins;
|
||||
}
|
||||
|
||||
public void setRetain_cached_searches_mins(Long retain_cached_searches_mins) {
|
||||
this.retain_cached_searches_mins = retain_cached_searches_mins;
|
||||
}
|
||||
|
||||
public Long getReuse_cached_search_results_millis() {
|
||||
return reuse_cached_search_results_millis;
|
||||
}
|
||||
|
||||
public void setReuse_cached_search_results_millis(Long reuse_cached_search_results_millis) {
|
||||
this.reuse_cached_search_results_millis = reuse_cached_search_results_millis;
|
||||
}
|
||||
|
||||
public List<Tester> getTester() {
|
||||
return tester;
|
||||
}
|
||||
|
||||
public void setTester(List<Tester> tester) {
|
||||
this.tester = tester;
|
||||
}
|
||||
|
||||
public static class Cors {
|
||||
private Boolean allow_Credentials = true;
|
||||
private List<String> allowed_origin = ImmutableList.of("*");
|
||||
|
||||
public List<String> getAllowed_origin() {
|
||||
return allowed_origin;
|
||||
}
|
||||
|
||||
public void setAllowed_origin(List<String> allowed_origin) {
|
||||
this.allowed_origin = allowed_origin;
|
||||
}
|
||||
|
||||
public Boolean getAllow_Credentials() {
|
||||
return allow_Credentials;
|
||||
}
|
||||
|
||||
public void setAllow_Credentials(Boolean allow_Credentials) {
|
||||
this.allow_Credentials = allow_Credentials;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class Logger {
|
||||
|
||||
private String name = "fhirtest.access";
|
||||
private String error_format = "ERROR - ${requestVerb} ${requestUrl}";
|
||||
private String format = "Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]";
|
||||
private Boolean log_exceptions = true;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getError_format() {
|
||||
return error_format;
|
||||
}
|
||||
|
||||
public void setError_format(String error_format) {
|
||||
this.error_format = error_format;
|
||||
}
|
||||
|
||||
public String getFormat() {
|
||||
return format;
|
||||
}
|
||||
|
||||
public void setFormat(String format) {
|
||||
this.format = format;
|
||||
}
|
||||
|
||||
public Boolean getLog_exceptions() {
|
||||
return log_exceptions;
|
||||
}
|
||||
|
||||
public void setLog_exceptions(Boolean log_exceptions) {
|
||||
this.log_exceptions = log_exceptions;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class Tester {
|
||||
|
||||
private String id = "home";
|
||||
private String name = "Local Tester";
|
||||
private String server_address = "http://localhost:8080/fhir";
|
||||
private Boolean refuse_to_fetch_third_party_urls = true;
|
||||
private FhirVersionEnum fhir_version = FhirVersionEnum.R4;
|
||||
|
||||
public FhirVersionEnum getFhir_version() {
|
||||
return fhir_version;
|
||||
}
|
||||
|
||||
public void setFhir_version(FhirVersionEnum fhir_version) {
|
||||
this.fhir_version = fhir_version;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getServer_address() {
|
||||
return server_address;
|
||||
}
|
||||
|
||||
public void setServer_address(String server_address) {
|
||||
this.server_address = server_address;
|
||||
}
|
||||
|
||||
public Boolean getRefuse_to_fetch_third_party_urls() {
|
||||
return refuse_to_fetch_third_party_urls;
|
||||
}
|
||||
|
||||
public void setRefuse_to_fetch_third_party_urls(Boolean refuse_to_fetch_third_party_urls) {
|
||||
this.refuse_to_fetch_third_party_urls = refuse_to_fetch_third_party_urls;
|
||||
}
|
||||
}
|
||||
|
||||
public static class ImplementationGuide
|
||||
{
|
||||
private String url;
|
||||
private String name;
|
||||
private String version;
|
||||
|
||||
public String getUrl() {
|
||||
return url;
|
||||
}
|
||||
|
||||
public void setUrl(String url) {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getVersion() {
|
||||
return version;
|
||||
}
|
||||
|
||||
public void setVersion(String version) {
|
||||
this.version = version;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Validation {
|
||||
|
||||
private Boolean requests_enabled = false;
|
||||
private Boolean responses_enabled = false;
|
||||
|
||||
public Boolean getRequests_enabled() {
|
||||
return requests_enabled;
|
||||
}
|
||||
|
||||
public void setRequests_enabled(Boolean requests_enabled) {
|
||||
this.requests_enabled = requests_enabled;
|
||||
}
|
||||
|
||||
public Boolean getResponses_enabled() {
|
||||
return responses_enabled;
|
||||
}
|
||||
|
||||
public void setResponses_enabled(Boolean responses_enabled) {
|
||||
this.responses_enabled = responses_enabled;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Partitioning {
|
||||
|
||||
private Boolean partitioning_include_in_search_hashes = false;
|
||||
|
||||
|
||||
public Boolean getPartitioning_include_in_search_hashes() {
|
||||
return partitioning_include_in_search_hashes;
|
||||
}
|
||||
|
||||
public void setPartitioning_include_in_search_hashes(Boolean partitioning_include_in_search_hashes) {
|
||||
this.partitioning_include_in_search_hashes = partitioning_include_in_search_hashes;
|
||||
}
|
||||
}
|
||||
|
||||
public static class Subscription {
|
||||
|
||||
public Boolean getResthook_enabled() {
|
||||
return resthook_enabled;
|
||||
}
|
||||
|
||||
public void setResthook_enabled(Boolean resthook_enabled) {
|
||||
this.resthook_enabled = resthook_enabled;
|
||||
}
|
||||
|
||||
public Boolean getWebsocket_enabled() {
|
||||
return websocket_enabled;
|
||||
}
|
||||
|
||||
public void setWebsocket_enabled(Boolean websocket_enabled) {
|
||||
this.websocket_enabled = websocket_enabled;
|
||||
}
|
||||
|
||||
private Boolean resthook_enabled = false;
|
||||
private Boolean websocket_enabled = false;
|
||||
private Email email = null;
|
||||
|
||||
public Email getEmail() {
|
||||
return email;
|
||||
}
|
||||
|
||||
public void setEmail(Email email) {
|
||||
this.email = email;
|
||||
}
|
||||
|
||||
|
||||
public static class Email {
|
||||
public String getFrom() {
|
||||
return from;
|
||||
}
|
||||
|
||||
public void setFrom(String from) {
|
||||
this.from = from;
|
||||
}
|
||||
|
||||
public String getHost() {
|
||||
return host;
|
||||
}
|
||||
|
||||
public void setHost(String host) {
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
public Integer getPort() {
|
||||
return port;
|
||||
}
|
||||
|
||||
public void setPort(Integer port) {
|
||||
this.port = port;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public Boolean getAuth() {
|
||||
return auth;
|
||||
}
|
||||
|
||||
public void setAuth(Boolean auth) {
|
||||
this.auth = auth;
|
||||
}
|
||||
|
||||
public Boolean getStartTlsEnable() {
|
||||
return startTlsEnable;
|
||||
}
|
||||
|
||||
public void setStartTlsEnable(Boolean startTlsEnable) {
|
||||
this.startTlsEnable = startTlsEnable;
|
||||
}
|
||||
|
||||
public Boolean getStartTlsRequired() {
|
||||
return startTlsRequired;
|
||||
}
|
||||
|
||||
public void setStartTlsRequired(Boolean startTlsRequired) {
|
||||
this.startTlsRequired = startTlsRequired;
|
||||
}
|
||||
|
||||
public Boolean getQuitWait() {
|
||||
return quitWait;
|
||||
}
|
||||
|
||||
public void setQuitWait(Boolean quitWait) {
|
||||
this.quitWait = quitWait;
|
||||
}
|
||||
|
||||
private String from;
|
||||
private String host;
|
||||
private Integer port = 25;
|
||||
private String username;
|
||||
private String password;
|
||||
private Boolean auth = false;
|
||||
private Boolean startTlsEnable = false;
|
||||
private Boolean startTlsRequired = false;
|
||||
private Boolean quitWait = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
76
src/main/java/ca/uhn/fhir/jpa/starter/Application.java
Normal file
76
src/main/java/ca/uhn/fhir/jpa/starter/Application.java
Normal file
@@ -0,0 +1,76 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import ca.uhn.fhir.jpa.empi.EmpiConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.match.config.WebsocketDispatcherConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.config.SubscriptionSubmitterConfig;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||
import org.springframework.boot.web.servlet.ServletRegistrationBean;
|
||||
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
import org.springframework.web.servlet.DispatcherServlet;
|
||||
|
||||
@ServletComponentScan(basePackageClasses = {
|
||||
JpaRestfulServer.class})
|
||||
@SpringBootApplication(exclude = {ElasticsearchRestClientAutoConfiguration.class})
|
||||
@Import({SubscriptionSubmitterConfig.class, SubscriptionProcessorConfig.class, SubscriptionChannelConfig.class, WebsocketDispatcherConfig.class, EmpiConfig.class})
|
||||
public class Application extends SpringBootServletInitializer {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
System.setProperty("spring.batch.job.enabled", "false");
|
||||
SpringApplication.run(Application.class, args);
|
||||
|
||||
//Server is now accessible at eg. http://localhost:8080/hapi-fhir-jpaserver/fhir/metadata
|
||||
//UI is now accessible at http://localhost:8080/hapi-fhir-jpaserver/
|
||||
}
|
||||
|
||||
@Override
|
||||
protected SpringApplicationBuilder configure(
|
||||
SpringApplicationBuilder builder) {
|
||||
return builder.sources(Application.class);
|
||||
}
|
||||
|
||||
@Autowired
|
||||
AutowireCapableBeanFactory beanFactory;
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean hapiServletRegistration() {
|
||||
ServletRegistrationBean servletRegistrationBean = new ServletRegistrationBean();
|
||||
JpaRestfulServer jpaRestfulServer = new JpaRestfulServer();
|
||||
beanFactory.autowireBean(jpaRestfulServer);
|
||||
servletRegistrationBean.setServlet(jpaRestfulServer);
|
||||
servletRegistrationBean.addUrlMappings("/fhir/*");
|
||||
servletRegistrationBean.setLoadOnStartup(1);
|
||||
|
||||
return servletRegistrationBean;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ServletRegistrationBean overlayRegistrationBean() {
|
||||
|
||||
AnnotationConfigWebApplicationContext annotationConfigWebApplicationContext = new AnnotationConfigWebApplicationContext();
|
||||
annotationConfigWebApplicationContext.register(FhirTesterConfig.class);
|
||||
|
||||
DispatcherServlet dispatcherServlet = new DispatcherServlet(
|
||||
annotationConfigWebApplicationContext);
|
||||
dispatcherServlet.setContextClass(AnnotationConfigWebApplicationContext.class);
|
||||
dispatcherServlet.setContextConfigLocation(FhirTesterConfig.class.getName());
|
||||
|
||||
ServletRegistrationBean registrationBean = new ServletRegistrationBean();
|
||||
registrationBean.setServlet(dispatcherServlet);
|
||||
registrationBean.addUrlMappings("/*");
|
||||
registrationBean.setLoadOnStartup(1);
|
||||
return registrationBean;
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.empi.EmpiConfig;
|
||||
import ca.uhn.fhir.jpa.empi.config.EmpiConsumerConfig;
|
||||
import ca.uhn.fhir.jpa.empi.config.EmpiSubmitterConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.config.SubscriptionChannelConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.match.config.WebsocketDispatcherConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.submit.config.SubscriptionSubmitterConfig;
|
||||
import org.springframework.web.context.support.AnnotationConfigWebApplicationContext;
|
||||
|
||||
public class ApplicationContext extends AnnotationConfigWebApplicationContext {
|
||||
|
||||
public ApplicationContext() {
|
||||
FhirVersionEnum fhirVersion = HapiProperties.getFhirVersion();
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
register(FhirServerConfigDstu2.class, FhirServerConfigCommon.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
register(FhirServerConfigDstu3.class, FhirServerConfigCommon.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.R4) {
|
||||
register(FhirServerConfigR4.class, FhirServerConfigCommon.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.R5) {
|
||||
register(FhirServerConfigR5.class, FhirServerConfigCommon.class);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
if (HapiProperties.getSubscriptionWebsocketEnabled()) {
|
||||
register(WebsocketDispatcherConfig.class);
|
||||
}
|
||||
|
||||
if (HapiProperties.getSubscriptionEmailEnabled()
|
||||
|| HapiProperties.getSubscriptionRestHookEnabled()
|
||||
|| HapiProperties.getSubscriptionWebsocketEnabled()) {
|
||||
register(SubscriptionSubmitterConfig.class);
|
||||
register(SubscriptionProcessorConfig.class);
|
||||
register(SubscriptionChannelConfig.class);
|
||||
}
|
||||
|
||||
if (HapiProperties.getEmpiEnabled()) {
|
||||
register(EmpiSubmitterConfig.class);
|
||||
register(EmpiConsumerConfig.class);
|
||||
register(EmpiConfig.class);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,39 +10,33 @@ import ca.uhn.fhir.jpa.api.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.jpa.binstore.BinaryStorageInterceptor;
|
||||
import ca.uhn.fhir.jpa.bulk.provider.BulkDataExportProvider;
|
||||
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||
import ca.uhn.fhir.jpa.packages.IPackageInstallerSvc;
|
||||
import ca.uhn.fhir.jpa.packages.PackageInstallationSpec;
|
||||
import ca.uhn.fhir.jpa.partition.PartitionManagementProvider;
|
||||
import ca.uhn.fhir.jpa.provider.GraphQLProvider;
|
||||
import ca.uhn.fhir.jpa.provider.IJpaSystemProvider;
|
||||
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.JpaSystemProviderDstu3;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaConformanceProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.provider.r5.JpaConformanceProviderR5;
|
||||
import ca.uhn.fhir.jpa.provider.r5.JpaSystemProviderR5;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.util.SubscriptionDebugLogInterceptor;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import ca.uhn.fhir.rest.server.HardcodedServerAddressStrategy;
|
||||
import ca.uhn.fhir.rest.server.RestfulServer;
|
||||
import ca.uhn.fhir.rest.server.interceptor.CorsInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.FhirPathFilterInterceptor;
|
||||
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.rest.server.interceptor.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.partition.RequestTenantPartitionInterceptor;
|
||||
import ca.uhn.fhir.rest.server.provider.ResourceProviderFactory;
|
||||
import ca.uhn.fhir.rest.server.tenant.UrlBaseTenantIdentificationStrategy;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import ca.uhn.fhir.validation.ResultSeverityEnum;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
import org.hl7.fhir.dstu3.model.Meta;
|
||||
import com.google.common.base.Strings;
|
||||
import org.hl7.fhir.r4.model.Bundle.BundleType;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
@@ -50,12 +44,67 @@ import org.springframework.web.cors.CorsConfiguration;
|
||||
import javax.servlet.ServletException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class BaseJpaRestfulServer extends RestfulServer {
|
||||
|
||||
@Autowired
|
||||
DaoRegistry daoRegistry;
|
||||
|
||||
@Autowired
|
||||
DaoConfig daoConfig;
|
||||
|
||||
@Autowired
|
||||
ISearchParamRegistry searchParamRegistry;
|
||||
|
||||
@Autowired
|
||||
IFhirSystemDao fhirSystemDao;
|
||||
|
||||
@Autowired
|
||||
ResourceProviderFactory resourceProviders;
|
||||
|
||||
@Autowired
|
||||
IJpaSystemProvider jpaSystemProvider;
|
||||
|
||||
@Autowired
|
||||
IInterceptorBroadcaster interceptorBroadcaster;
|
||||
|
||||
@Autowired
|
||||
DatabaseBackedPagingProvider databaseBackedPagingProvider;
|
||||
|
||||
@Autowired
|
||||
IInterceptorService interceptorService;
|
||||
|
||||
@Autowired
|
||||
IValidatorModule validatorModule;
|
||||
|
||||
@Autowired
|
||||
Optional<GraphQLProvider> graphQLProvider;
|
||||
|
||||
@Autowired
|
||||
BulkDataExportProvider bulkDataExportProvider;
|
||||
|
||||
@Autowired
|
||||
PartitionManagementProvider partitionManagementProvider;
|
||||
|
||||
@Autowired
|
||||
BinaryStorageInterceptor binaryStorageInterceptor;
|
||||
|
||||
@Autowired
|
||||
IPackageInstallerSvc packageInstallerSvc;
|
||||
|
||||
@Autowired
|
||||
AppProperties appProperties;
|
||||
|
||||
@Autowired
|
||||
ApplicationContext myApplicationContext;
|
||||
|
||||
public BaseJpaRestfulServer() {
|
||||
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -67,47 +116,19 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
* Create a FhirContext object that uses the version of FHIR
|
||||
* specified in the properties file.
|
||||
*/
|
||||
ApplicationContext appCtx = (ApplicationContext) getServletContext()
|
||||
.getAttribute("org.springframework.web.context.WebApplicationContext.ROOT");
|
||||
// Customize supported resource types
|
||||
Set<String> supportedResourceTypes = HapiProperties.getSupportedResourceTypes();
|
||||
List<String> supportedResourceTypes = appProperties.getSupported_resource_types();
|
||||
|
||||
if (!supportedResourceTypes.isEmpty() && !supportedResourceTypes.contains("SearchParameter")) {
|
||||
supportedResourceTypes.add("SearchParameter");
|
||||
}
|
||||
|
||||
if (!supportedResourceTypes.isEmpty()) {
|
||||
DaoRegistry daoRegistry = appCtx.getBean(DaoRegistry.class);
|
||||
daoRegistry.setSupportedResourceTypes(supportedResourceTypes);
|
||||
}
|
||||
|
||||
/*
|
||||
* ResourceProviders are fetched from the Spring context
|
||||
*/
|
||||
FhirVersionEnum fhirVersion = HapiProperties.getFhirVersion();
|
||||
ResourceProviderFactory resourceProviders;
|
||||
Object systemProvider;
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
resourceProviders = appCtx.getBean("myResourceProvidersDstu2", ResourceProviderFactory.class);
|
||||
systemProvider = appCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
resourceProviders = appCtx.getBean("myResourceProvidersDstu3", ResourceProviderFactory.class);
|
||||
systemProvider = appCtx.getBean("mySystemProviderDstu3", JpaSystemProviderDstu3.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.R4) {
|
||||
resourceProviders = appCtx.getBean("myResourceProvidersR4", ResourceProviderFactory.class);
|
||||
systemProvider = appCtx.getBean("mySystemProviderR4", JpaSystemProviderR4.class);
|
||||
} else if (fhirVersion == FhirVersionEnum.R5) {
|
||||
resourceProviders = appCtx.getBean("myResourceProvidersR5", ResourceProviderFactory.class);
|
||||
systemProvider = appCtx.getBean("mySystemProviderR5", JpaSystemProviderR5.class);
|
||||
} else {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
setFhirContext(appCtx.getBean(FhirContext.class));
|
||||
|
||||
setFhirContext(fhirSystemDao.getContext());
|
||||
registerProviders(resourceProviders.createProviders());
|
||||
registerProvider(systemProvider);
|
||||
registerProvider(jpaSystemProvider);
|
||||
|
||||
FhirVersionEnum fhirVersion = fhirSystemDao.getContext().getVersion().getVersion();
|
||||
/*
|
||||
* The conformance provider exports the supported resources, search parameters, etc for
|
||||
* this server. The JPA version adds resourceProviders counts to the exported statement, so it
|
||||
@@ -116,27 +137,31 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
* You can also create your own subclass of the conformance provider if you need to
|
||||
* provide further customization of your server's CapabilityStatement
|
||||
*/
|
||||
DaoConfig daoConfig = appCtx.getBean(DaoConfig.class);
|
||||
ISearchParamRegistry searchParamRegistry = appCtx.getBean(ISearchParamRegistry.class);
|
||||
|
||||
|
||||
if (fhirVersion == FhirVersionEnum.DSTU2) {
|
||||
IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDao = appCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, daoConfig);
|
||||
|
||||
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, fhirSystemDao,
|
||||
daoConfig);
|
||||
confProvider.setImplementationDescription("HAPI FHIR DSTU2 Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else {
|
||||
if (fhirVersion == FhirVersionEnum.DSTU3) {
|
||||
IFhirSystemDao<Bundle, Meta> systemDao = appCtx.getBean("mySystemDaoDstu3", IFhirSystemDao.class);
|
||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, systemDao, daoConfig, searchParamRegistry);
|
||||
|
||||
JpaConformanceProviderDstu3 confProvider = new JpaConformanceProviderDstu3(this, fhirSystemDao,
|
||||
daoConfig, searchParamRegistry);
|
||||
confProvider.setImplementationDescription("HAPI FHIR DSTU3 Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else if (fhirVersion == FhirVersionEnum.R4) {
|
||||
IFhirSystemDao<org.hl7.fhir.r4.model.Bundle, org.hl7.fhir.r4.model.Meta> systemDao = appCtx.getBean("mySystemDaoR4", IFhirSystemDao.class);
|
||||
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, systemDao, daoConfig, searchParamRegistry);
|
||||
|
||||
JpaConformanceProviderR4 confProvider = new JpaConformanceProviderR4(this, fhirSystemDao,
|
||||
daoConfig, searchParamRegistry);
|
||||
confProvider.setImplementationDescription("HAPI FHIR R4 Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else if (fhirVersion == FhirVersionEnum.R5) {
|
||||
IFhirSystemDao<org.hl7.fhir.r5.model.Bundle, org.hl7.fhir.r5.model.Meta> systemDao = appCtx.getBean("mySystemDaoR5", IFhirSystemDao.class);
|
||||
JpaConformanceProviderR5 confProvider = new JpaConformanceProviderR5(this, systemDao, daoConfig, searchParamRegistry);
|
||||
|
||||
JpaConformanceProviderR5 confProvider = new JpaConformanceProviderR5(this, fhirSystemDao,
|
||||
daoConfig, searchParamRegistry);
|
||||
confProvider.setImplementationDescription("HAPI FHIR R5 Server");
|
||||
setServerConformanceProvider(confProvider);
|
||||
} else {
|
||||
@@ -147,7 +172,10 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
/*
|
||||
* ETag Support
|
||||
*/
|
||||
setETagSupport(HapiProperties.getEtagSupport());
|
||||
|
||||
if (appProperties.getEtag_support_enabled() == false)
|
||||
setETagSupport(ETagSupportEnum.DISABLED);
|
||||
|
||||
|
||||
/*
|
||||
* This server tries to dynamically generate narratives
|
||||
@@ -158,12 +186,12 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
/*
|
||||
* Default to JSON and pretty printing
|
||||
*/
|
||||
setDefaultPrettyPrint(HapiProperties.getDefaultPrettyPrint());
|
||||
setDefaultPrettyPrint(appProperties.getDefault_pretty_print());
|
||||
|
||||
/*
|
||||
* Default encoding
|
||||
*/
|
||||
setDefaultResponseEncoding(HapiProperties.getDefaultEncoding());
|
||||
setDefaultResponseEncoding(appProperties.getDefault_encoding());
|
||||
|
||||
/*
|
||||
* This configures the server to page search results to and from
|
||||
@@ -171,7 +199,8 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
* a performance hit when performing searches that return lots of results,
|
||||
* but makes the server much more scalable.
|
||||
*/
|
||||
setPagingProvider(appCtx.getBean(DatabaseBackedPagingProvider.class));
|
||||
|
||||
setPagingProvider(databaseBackedPagingProvider);
|
||||
|
||||
/*
|
||||
* This interceptor formats the output using nice colourful
|
||||
@@ -181,7 +210,7 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
ResponseHighlighterInterceptor responseHighlighterInterceptor = new ResponseHighlighterInterceptor();
|
||||
this.registerInterceptor(responseHighlighterInterceptor);
|
||||
|
||||
if (HapiProperties.isFhirPathFilterInterceptorEnabled()) {
|
||||
if (appProperties.getFhirpath_interceptor_enabled()) {
|
||||
registerInterceptor(new FhirPathFilterInterceptor());
|
||||
}
|
||||
|
||||
@@ -189,10 +218,10 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
* Add some logging for each request
|
||||
*/
|
||||
LoggingInterceptor loggingInterceptor = new LoggingInterceptor();
|
||||
loggingInterceptor.setLoggerName(HapiProperties.getLoggerName());
|
||||
loggingInterceptor.setMessageFormat(HapiProperties.getLoggerFormat());
|
||||
loggingInterceptor.setErrorMessageFormat(HapiProperties.getLoggerErrorFormat());
|
||||
loggingInterceptor.setLogExceptions(HapiProperties.getLoggerLogExceptions());
|
||||
loggingInterceptor.setLoggerName(appProperties.getLogger().getName());
|
||||
loggingInterceptor.setMessageFormat(appProperties.getLogger().getFormat());
|
||||
loggingInterceptor.setErrorMessageFormat(appProperties.getLogger().getError_format());
|
||||
loggingInterceptor.setLogExceptions(appProperties.getLogger().getLog_exceptions());
|
||||
this.registerInterceptor(loggingInterceptor);
|
||||
|
||||
/*
|
||||
@@ -201,8 +230,8 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
* 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:
|
||||
*/
|
||||
String serverAddress = HapiProperties.getServerAddress();
|
||||
if (serverAddress != null && serverAddress.length() > 0) {
|
||||
String serverAddress = appProperties.getServer_address();
|
||||
if (!Strings.isNullOrEmpty(serverAddress)) {
|
||||
setServerAddressStrategy(new HardcodedServerAddressStrategy(serverAddress));
|
||||
}
|
||||
|
||||
@@ -213,22 +242,20 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
* so it is a potential security vulnerability. Consider using an AuthorizationInterceptor
|
||||
* with this feature.
|
||||
*/
|
||||
if (false) { // <-- DISABLED RIGHT NOW
|
||||
registerProvider(appCtx.getBean(TerminologyUploaderProvider.class));
|
||||
if (ctx.getVersion().getVersion().isEqualOrNewerThan(FhirVersionEnum.DSTU3)) { // <-- ENABLED RIGHT NOW
|
||||
registerProvider(myApplicationContext.getBean(TerminologyUploaderProvider.class));
|
||||
}
|
||||
|
||||
// If you want to enable the $trigger-subscription operation to allow
|
||||
// manual triggering of a subscription delivery, enable this provider
|
||||
if (false) { // <-- DISABLED RIGHT NOW
|
||||
SubscriptionTriggeringProvider retriggeringProvider = appCtx
|
||||
.getBean(SubscriptionTriggeringProvider.class);
|
||||
registerProvider(retriggeringProvider);
|
||||
if (true) { // <-- ENABLED RIGHT NOW
|
||||
registerProvider(myApplicationContext.getBean(SubscriptionTriggeringProvider.class));
|
||||
}
|
||||
|
||||
// Define your CORS configuration. This is an example
|
||||
// showing a typical setup. You should customize this
|
||||
// to your specific needs
|
||||
if (HapiProperties.getCorsEnabled()) {
|
||||
if (appProperties.getCors() != null) {
|
||||
CorsConfiguration config = new CorsConfiguration();
|
||||
config.addAllowedHeader(HttpHeaders.ORIGIN);
|
||||
config.addAllowedHeader(HttpHeaders.ACCEPT);
|
||||
@@ -238,17 +265,15 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
config.addAllowedHeader("x-fhir-starter");
|
||||
config.addAllowedHeader("X-Requested-With");
|
||||
config.addAllowedHeader("Prefer");
|
||||
String allAllowedCORSOrigins = HapiProperties.getCorsAllowedOrigin();
|
||||
Arrays.stream(allAllowedCORSOrigins.split(",")).forEach(o -> {
|
||||
config.addAllowedOrigin(o);
|
||||
});
|
||||
config.addAllowedOrigin(HapiProperties.getCorsAllowedOrigin());
|
||||
List<String> allAllowedCORSOrigins = appProperties.getCors().getAllowed_origin();
|
||||
allAllowedCORSOrigins.forEach(config::addAllowedOrigin);
|
||||
|
||||
|
||||
config.addExposedHeader("Location");
|
||||
config.addExposedHeader("Content-Location");
|
||||
config.setAllowedMethods(
|
||||
Arrays.asList("GET", "POST", "PUT", "DELETE", "OPTIONS", "PATCH", "HEAD"));
|
||||
config.setAllowCredentials(HapiProperties.getCorsAllowedCredentials());
|
||||
config.setAllowCredentials(appProperties.getCors().getAllow_Credentials());
|
||||
|
||||
// Create the interceptor and register it
|
||||
CorsInterceptor interceptor = new CorsInterceptor(config);
|
||||
@@ -257,39 +282,35 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
|
||||
// If subscriptions are enabled, we want to register the interceptor that
|
||||
// will activate them and match results against them
|
||||
if (HapiProperties.getSubscriptionWebsocketEnabled() ||
|
||||
HapiProperties.getSubscriptionEmailEnabled() ||
|
||||
HapiProperties.getSubscriptionRestHookEnabled()) {
|
||||
if (appProperties.getSubscription() != null) {
|
||||
// Subscription debug logging
|
||||
IInterceptorService interceptorService = appCtx.getBean(IInterceptorService.class);
|
||||
interceptorService.registerInterceptor(new SubscriptionDebugLogInterceptor());
|
||||
}
|
||||
|
||||
// Cascading deletes
|
||||
DaoRegistry daoRegistry = appCtx.getBean(DaoRegistry.class);
|
||||
IInterceptorBroadcaster interceptorBroadcaster = appCtx.getBean(IInterceptorBroadcaster.class);
|
||||
if (HapiProperties.getAllowCascadingDeletes()) {
|
||||
CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(ctx, daoRegistry, interceptorBroadcaster);
|
||||
|
||||
|
||||
if (appProperties.getAllow_cascading_deletes()) {
|
||||
CascadingDeleteInterceptor cascadingDeleteInterceptor = new CascadingDeleteInterceptor(ctx,
|
||||
daoRegistry, interceptorBroadcaster);
|
||||
getInterceptorService().registerInterceptor(cascadingDeleteInterceptor);
|
||||
}
|
||||
|
||||
// Binary Storage
|
||||
if (HapiProperties.isBinaryStorageEnabled()) {
|
||||
BinaryStorageInterceptor binaryStorageInterceptor = appCtx
|
||||
.getBean(BinaryStorageInterceptor.class);
|
||||
if (appProperties.getBinary_storage_enabled()) {
|
||||
getInterceptorService().registerInterceptor(binaryStorageInterceptor);
|
||||
}
|
||||
|
||||
// Validation
|
||||
IValidatorModule validatorModule = appCtx.getBean(IValidatorModule.class);
|
||||
|
||||
if (validatorModule != null) {
|
||||
if (HapiProperties.getValidateRequestsEnabled()) {
|
||||
if (appProperties.getValidation().getRequests_enabled()) {
|
||||
RequestValidatingInterceptor interceptor = new RequestValidatingInterceptor();
|
||||
interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
interceptor.setValidatorModules(Collections.singletonList(validatorModule));
|
||||
registerInterceptor(interceptor);
|
||||
}
|
||||
if (HapiProperties.getValidateResponsesEnabled()) {
|
||||
if (appProperties.getValidation().getResponses_enabled()) {
|
||||
ResponseValidatingInterceptor interceptor = new ResponseValidatingInterceptor();
|
||||
interceptor.setFailOnSeverity(ResultSeverityEnum.ERROR);
|
||||
interceptor.setValidatorModules(Collections.singletonList(validatorModule));
|
||||
@@ -298,40 +319,46 @@ public class BaseJpaRestfulServer extends RestfulServer {
|
||||
}
|
||||
|
||||
// GraphQL
|
||||
if (HapiProperties.getGraphqlEnabled()) {
|
||||
if (appProperties.getGraphql_enabled()) {
|
||||
if (fhirVersion.isEqualOrNewerThan(FhirVersionEnum.DSTU3)) {
|
||||
registerProvider(appCtx.getBean(GraphQLProvider.class));
|
||||
registerProvider(graphQLProvider.get());
|
||||
}
|
||||
}
|
||||
|
||||
if (!HapiProperties.getAllowedBundleTypes().isEmpty()) {
|
||||
String allowedBundleTypesString = HapiProperties.getAllowedBundleTypes();
|
||||
Set<String> allowedBundleTypes = new HashSet<>();
|
||||
Arrays.stream(allowedBundleTypesString.split(",")).forEach(o -> {
|
||||
BundleType type = BundleType.valueOf(o);
|
||||
allowedBundleTypes.add(type.toCode());
|
||||
});
|
||||
DaoConfig config = daoConfig;
|
||||
config.setBundleTypesAllowedForStorage(
|
||||
Collections.unmodifiableSet(new TreeSet<>(allowedBundleTypes)));
|
||||
if (appProperties.getAllowed_bundle_types() != null) {
|
||||
daoConfig.setBundleTypesAllowedForStorage(appProperties.getAllowed_bundle_types().stream().map(BundleType::toCode).collect(Collectors.toSet()));
|
||||
}
|
||||
|
||||
daoConfig.setDeferIndexingForCodesystemsOfSize(appProperties.getDefer_indexing_for_codesystems_of_size());
|
||||
|
||||
// Bulk Export
|
||||
if (HapiProperties.getBulkExportEnabled()) {
|
||||
registerProvider(appCtx.getBean(BulkDataExportProvider.class));
|
||||
if (appProperties.getBulk_export_enabled()) {
|
||||
registerProvider(bulkDataExportProvider);
|
||||
}
|
||||
|
||||
// Partitioning
|
||||
if (HapiProperties.getPartitioningMultitenancyEnabled()) {
|
||||
if (appProperties.getPartitioning() != null) {
|
||||
registerInterceptor(new RequestTenantPartitionInterceptor());
|
||||
setTenantIdentificationStrategy(new UrlBaseTenantIdentificationStrategy());
|
||||
registerProviders(appCtx.getBean(PartitionManagementProvider.class));
|
||||
registerProviders(partitionManagementProvider);
|
||||
}
|
||||
|
||||
if (HapiProperties.getClientIdStrategy() == DaoConfig.ClientIdStrategyEnum.ANY) {
|
||||
if (appProperties.getClient_id_strategy() == DaoConfig.ClientIdStrategyEnum.ANY) {
|
||||
daoConfig.setResourceServerIdStrategy(DaoConfig.IdStrategyEnum.UUID);
|
||||
daoConfig.setResourceClientIdStrategy(HapiProperties.getClientIdStrategy());
|
||||
daoConfig.setResourceClientIdStrategy(appProperties.getClient_id_strategy());
|
||||
}
|
||||
|
||||
if (appProperties.getImplementationGuides() != null) {
|
||||
List<AppProperties.ImplementationGuide> guides = appProperties.getImplementationGuides();
|
||||
for (AppProperties.ImplementationGuide guide : guides) {
|
||||
packageInstallerSvc.install(new PackageInstallationSpec()
|
||||
.setPackageUrl(guide.getUrl())
|
||||
.setName(guide.getName())
|
||||
.setVersion(guide.getVersion())
|
||||
.setInstallMode(PackageInstallationSpec.InstallModeEnum.STORE_AND_INSTALL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
92
src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java
Normal file
92
src/main/java/ca/uhn/fhir/jpa/starter/EnvironmentHelper.java
Normal file
@@ -0,0 +1,92 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import org.springframework.core.env.CompositePropertySource;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.EnumerablePropertySource;
|
||||
import org.springframework.core.env.PropertySource;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
public class EnvironmentHelper {
|
||||
|
||||
public static Properties getHibernateProperties(ConfigurableEnvironment environment) {
|
||||
Properties properties = new Properties();
|
||||
|
||||
if (environment.getProperty("spring.jpa.properties", String.class) == null) {
|
||||
properties.put("hibernate.search.model_mapping", "ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory");
|
||||
properties.put("hibernate.format_sql", "false");
|
||||
properties.put("hibernate.show_sql", "false");
|
||||
properties.put("hibernate.hbm2ddl.auto", "update");
|
||||
properties.put("hibernate.jdbc.batch_size", "20");
|
||||
properties.put("hibernate.cache.use_query_cache", "false");
|
||||
properties.put("hibernate.cache.use_second_level_cache", "false");
|
||||
properties.put("hibernate.cache.use_structured_entries", "false");
|
||||
properties.put("hibernate.cache.use_minimal_puts", "false");
|
||||
properties.put("hibernate.search.default.directory_provider", "filesystem");
|
||||
properties.put("hibernate.search.default.indexBase", "target/lucenefiles");
|
||||
properties.put("hibernate.search.lucene_version", "LUCENE_CURRENT");
|
||||
} else {
|
||||
Arrays.asList(environment.getProperty("spring.jpa.properties", String.class).split(" ")).stream().forEach(s ->
|
||||
{
|
||||
String[] values = s.split("=");
|
||||
properties.put(values[0], values[1]);
|
||||
});
|
||||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
public static Map<String, Object> getPropertiesStartingWith(ConfigurableEnvironment aEnv,
|
||||
String aKeyPrefix) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
Map<String, Object> map = getAllProperties(aEnv);
|
||||
|
||||
for (Map.Entry<String, Object> entry : map.entrySet()) {
|
||||
String key = entry.getKey();
|
||||
|
||||
if (key.startsWith(aKeyPrefix)) {
|
||||
result.put(key, entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, Object> getAllProperties(ConfigurableEnvironment aEnv) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
aEnv.getPropertySources().forEach(ps -> addAll(result, getAllProperties(ps)));
|
||||
return result;
|
||||
}
|
||||
|
||||
public static Map<String, Object> getAllProperties(PropertySource<?> aPropSource) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (aPropSource instanceof CompositePropertySource) {
|
||||
CompositePropertySource cps = (CompositePropertySource) aPropSource;
|
||||
cps.getPropertySources().forEach(ps -> addAll(result, getAllProperties(ps)));
|
||||
return result;
|
||||
}
|
||||
|
||||
if (aPropSource instanceof EnumerablePropertySource<?>) {
|
||||
EnumerablePropertySource<?> ps = (EnumerablePropertySource<?>) aPropSource;
|
||||
Arrays.asList(ps.getPropertyNames()).forEach(key -> result.put(key, ps.getProperty(key)));
|
||||
return result;
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private static void addAll(Map<String, Object> aBase, Map<String, Object> aToBeAdded) {
|
||||
for (Map.Entry<String, Object> entry : aToBeAdded.entrySet()) {
|
||||
if (aBase.containsKey(entry.getKey())) {
|
||||
continue;
|
||||
}
|
||||
|
||||
aBase.put(entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,14 @@ import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.SubscriptionDeliveryHandlerFactory;
|
||||
import ca.uhn.fhir.jpa.subscription.match.deliver.email.IEmailSender;
|
||||
import ca.uhn.fhir.jpa.subscription.match.deliver.email.JavaMailEmailSender;
|
||||
import org.apache.commons.dbcp2.BasicDataSource;
|
||||
import com.google.common.base.Strings;
|
||||
import org.hl7.fhir.dstu2.model.Subscription;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||
import org.thymeleaf.util.Validate;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.sql.Driver;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* This is the primary configuration file for the example server
|
||||
@@ -29,57 +26,34 @@ public class FhirServerConfigCommon {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirServerConfigCommon.class);
|
||||
|
||||
private Boolean enableIndexMissingFields = HapiProperties.getEnableIndexMissingFields();
|
||||
private Boolean autoCreatePlaceholderReferenceTargets = HapiProperties.getAutoCreatePlaceholderReferenceTargets();
|
||||
private Boolean enforceReferentialIntegrityOnWrite = HapiProperties.getEnforceReferentialIntegrityOnWrite();
|
||||
private Boolean enforceReferentialIntegrityOnDelete = HapiProperties.getEnforceReferentialIntegrityOnDelete();
|
||||
private Boolean allowContainsSearches = HapiProperties.getAllowContainsSearches();
|
||||
private Boolean allowMultipleDelete = HapiProperties.getAllowMultipleDelete();
|
||||
private Boolean allowExternalReferences = HapiProperties.getAllowExternalReferences();
|
||||
private Boolean expungeEnabled = HapiProperties.getExpungeEnabled();
|
||||
private Boolean allowPlaceholderReferences = HapiProperties.getAllowPlaceholderReferences();
|
||||
private Boolean subscriptionRestHookEnabled = HapiProperties.getSubscriptionRestHookEnabled();
|
||||
private Boolean subscriptionEmailEnabled = HapiProperties.getSubscriptionEmailEnabled();
|
||||
private Boolean allowOverrideDefaultSearchParams = HapiProperties.getAllowOverrideDefaultSearchParams();
|
||||
private String emailFrom = HapiProperties.getEmailFrom();
|
||||
private Boolean emailEnabled = HapiProperties.getEmailEnabled();
|
||||
private String emailHost = HapiProperties.getEmailHost();
|
||||
private Integer emailPort = HapiProperties.getEmailPort();
|
||||
private String emailUsername = HapiProperties.getEmailUsername();
|
||||
private String emailPassword = HapiProperties.getEmailPassword();
|
||||
private Boolean emailAuth = HapiProperties.getEmailAuth();
|
||||
private Boolean emailStartTlsEnable = HapiProperties.getEmailStartTlsEnable();
|
||||
private Boolean emailStartTlsRequired = HapiProperties.getEmailStartTlsRequired();
|
||||
private Boolean emailQuitWait = HapiProperties.getEmailQuitWait();
|
||||
@Autowired
|
||||
private ApplicationContext myAppCtx;
|
||||
|
||||
public FhirServerConfigCommon() {
|
||||
ourLog.info("Server configured to " + (this.allowContainsSearches ? "allow" : "deny") + " contains searches");
|
||||
ourLog.info("Server configured to " + (this.allowMultipleDelete ? "allow" : "deny") + " multiple deletes");
|
||||
ourLog.info("Server configured to " + (this.allowExternalReferences ? "allow" : "deny") + " external references");
|
||||
ourLog.info("Server configured to " + (this.expungeEnabled ? "enable" : "disable") + " expunges");
|
||||
ourLog.info("Server configured to " + (this.allowPlaceholderReferences ? "allow" : "deny") + " placeholder references");
|
||||
ourLog.info("Server configured to " + (this.allowOverrideDefaultSearchParams ? "allow" : "deny") + " overriding default search params");
|
||||
public FhirServerConfigCommon(AppProperties appProperties) {
|
||||
ourLog.info("Server configured to " + (appProperties.getAllow_contains_searches() ? "allow" : "deny") + " contains searches");
|
||||
ourLog.info("Server configured to " + (appProperties.getAllow_multiple_delete() ? "allow" : "deny") + " multiple deletes");
|
||||
ourLog.info("Server configured to " + (appProperties.getAllow_external_references() ? "allow" : "deny") + " external references");
|
||||
ourLog.info("Server configured to " + (appProperties.getExpunge_enabled() ? "enable" : "disable") + " expunges");
|
||||
ourLog.info("Server configured to " + (appProperties.getAllow_placeholder_references() ? "allow" : "deny") + " placeholder references");
|
||||
ourLog.info("Server configured to " + (appProperties.getAllow_override_default_search_params() ? "allow" : "deny") + " overriding default search params");
|
||||
|
||||
if (this.emailEnabled) {
|
||||
ourLog.info("Server is configured to enable email with host '" + this.emailHost + "' and port " + this.emailPort.toString());
|
||||
ourLog.info("Server will use '" + this.emailFrom + "' as the from email address");
|
||||
if (appProperties.getSubscription().getEmail() != null) {
|
||||
AppProperties.Subscription.Email email = appProperties.getSubscription().getEmail();
|
||||
ourLog.info("Server is configured to enable email with host '" + email.getHost() + "' and port " + email.getPort());
|
||||
ourLog.info("Server will use '" + email.getFrom() + "' as the from email address");
|
||||
|
||||
if (this.emailUsername != null && this.emailUsername.length() > 0) {
|
||||
ourLog.info("Server is configured to use username '" + this.emailUsername + "' for email");
|
||||
if (!Strings.isNullOrEmpty(email.getUsername())) {
|
||||
ourLog.info("Server is configured to use username '" + email.getUsername() + "' for email");
|
||||
}
|
||||
|
||||
if (this.emailPassword != null && this.emailPassword.length() > 0) {
|
||||
if (!Strings.isNullOrEmpty(email.getPassword())) {
|
||||
ourLog.info("Server is configured to use a password for email");
|
||||
}
|
||||
}
|
||||
|
||||
if (this.subscriptionRestHookEnabled) {
|
||||
if (appProperties.getSubscription().getResthook_enabled()) {
|
||||
ourLog.info("REST-hook subscriptions enabled");
|
||||
}
|
||||
|
||||
if (this.subscriptionEmailEnabled) {
|
||||
if (appProperties.getSubscription().getEmail() != null) {
|
||||
ourLog.info("Email subscriptions enabled");
|
||||
}
|
||||
}
|
||||
@@ -88,56 +62,60 @@ public class FhirServerConfigCommon {
|
||||
* Configure FHIR properties around the the JPA server via this bean
|
||||
*/
|
||||
@Bean()
|
||||
public DaoConfig daoConfig() {
|
||||
public DaoConfig daoConfig(AppProperties appProperties) {
|
||||
DaoConfig retVal = new DaoConfig();
|
||||
|
||||
retVal.setIndexMissingFields(this.enableIndexMissingFields ? DaoConfig.IndexEnabledEnum.ENABLED : DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
retVal.setAutoCreatePlaceholderReferenceTargets(this.autoCreatePlaceholderReferenceTargets);
|
||||
retVal.setEnforceReferentialIntegrityOnWrite(this.enforceReferentialIntegrityOnWrite);
|
||||
retVal.setEnforceReferentialIntegrityOnDelete(this.enforceReferentialIntegrityOnDelete);
|
||||
retVal.setAllowContainsSearches(this.allowContainsSearches);
|
||||
retVal.setAllowMultipleDelete(this.allowMultipleDelete);
|
||||
retVal.setAllowExternalReferences(this.allowExternalReferences);
|
||||
retVal.setExpungeEnabled(this.expungeEnabled);
|
||||
retVal.setAutoCreatePlaceholderReferenceTargets(this.allowPlaceholderReferences);
|
||||
retVal.setEmailFromAddress(this.emailFrom);
|
||||
retVal.setIndexMissingFields(appProperties.getEnable_index_missing_fields() ? DaoConfig.IndexEnabledEnum.ENABLED : DaoConfig.IndexEnabledEnum.DISABLED);
|
||||
retVal.setAutoCreatePlaceholderReferenceTargets(appProperties.getAuto_create_placeholder_reference_targets());
|
||||
retVal.setEnforceReferentialIntegrityOnWrite(appProperties.getEnforce_referential_integrity_on_write());
|
||||
retVal.setEnforceReferentialIntegrityOnDelete(appProperties.getEnforce_referential_integrity_on_delete());
|
||||
retVal.setAllowContainsSearches(appProperties.getAllow_contains_searches());
|
||||
retVal.setAllowMultipleDelete(appProperties.getAllow_multiple_delete());
|
||||
retVal.setAllowExternalReferences(appProperties.getAllow_external_references());
|
||||
retVal.setExpungeEnabled(appProperties.getExpunge_enabled());
|
||||
retVal.setAutoCreatePlaceholderReferenceTargets(appProperties.getAllow_placeholder_references());
|
||||
if(appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null)
|
||||
retVal.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom());
|
||||
|
||||
Integer maxFetchSize = HapiProperties.getMaximumFetchSize();
|
||||
Integer maxFetchSize = appProperties.getMax_page_size();
|
||||
retVal.setFetchSizeDefaultMaximum(maxFetchSize);
|
||||
ourLog.info("Server configured to have a maximum fetch size of " + (maxFetchSize == Integer.MAX_VALUE ? "'unlimited'" : maxFetchSize));
|
||||
|
||||
Long reuseCachedSearchResultsMillis = HapiProperties.getReuseCachedSearchResultsMillis();
|
||||
Long reuseCachedSearchResultsMillis = appProperties.getReuse_cached_search_results_millis();
|
||||
retVal.setReuseCachedSearchResultsForMillis(reuseCachedSearchResultsMillis);
|
||||
ourLog.info("Server configured to cache search results for {} milliseconds", reuseCachedSearchResultsMillis);
|
||||
|
||||
Long retainCachedSearchesMinutes = HapiProperties.getExpireSearchResultsAfterMins();
|
||||
|
||||
Long retainCachedSearchesMinutes = appProperties.getRetain_cached_searches_mins();
|
||||
retVal.setExpireSearchResultsAfterMillis(retainCachedSearchesMinutes * 60 * 1000);
|
||||
|
||||
if(appProperties.getSubscription() != null) {
|
||||
// Subscriptions are enabled by channel type
|
||||
if (HapiProperties.getSubscriptionRestHookEnabled()) {
|
||||
if (appProperties.getSubscription().getResthook_enabled()) {
|
||||
ourLog.info("Enabling REST-hook subscriptions");
|
||||
retVal.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
}
|
||||
if (HapiProperties.getSubscriptionEmailEnabled()) {
|
||||
if (appProperties.getSubscription().getEmail() != null) {
|
||||
ourLog.info("Enabling email subscriptions");
|
||||
retVal.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.EMAIL);
|
||||
}
|
||||
if (HapiProperties.getSubscriptionWebsocketEnabled()) {
|
||||
if (appProperties.getSubscription().getWebsocket_enabled()) {
|
||||
ourLog.info("Enabling websocket subscriptions");
|
||||
retVal.addSupportedSubscriptionType(org.hl7.fhir.dstu2.model.Subscription.SubscriptionChannelType.WEBSOCKET);
|
||||
}
|
||||
}
|
||||
|
||||
retVal.setFilterParameterEnabled(HapiProperties.getFilterSearchEnabled());
|
||||
retVal.setFilterParameterEnabled(appProperties.getFilter_search_enabled());
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public PartitionSettings partitionSettings() {
|
||||
public PartitionSettings partitionSettings(AppProperties appProperties) {
|
||||
PartitionSettings retVal = new PartitionSettings();
|
||||
|
||||
// Partitioning
|
||||
if (HapiProperties.getPartitioningMultitenancyEnabled()) {
|
||||
if (appProperties.getPartitioning() != null) {
|
||||
retVal.setPartitioningEnabled(true);
|
||||
}
|
||||
|
||||
@@ -146,19 +124,20 @@ public class FhirServerConfigCommon {
|
||||
|
||||
|
||||
@Bean
|
||||
public ModelConfig modelConfig() {
|
||||
public ModelConfig modelConfig(AppProperties appProperties) {
|
||||
ModelConfig modelConfig = new ModelConfig();
|
||||
modelConfig.setAllowContainsSearches(this.allowContainsSearches);
|
||||
modelConfig.setAllowExternalReferences(this.allowExternalReferences);
|
||||
modelConfig.setDefaultSearchParamsCanBeOverridden(this.allowOverrideDefaultSearchParams);
|
||||
modelConfig.setEmailFromAddress(this.emailFrom);
|
||||
modelConfig.setAllowContainsSearches(appProperties.getAllow_contains_searches());
|
||||
modelConfig.setAllowExternalReferences(appProperties.getAllow_external_references());
|
||||
modelConfig.setDefaultSearchParamsCanBeOverridden(appProperties.getAllow_override_default_search_params());
|
||||
if(appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null)
|
||||
modelConfig.setEmailFromAddress(appProperties.getSubscription().getEmail().getFrom());
|
||||
|
||||
// You can enable these if you want to support Subscriptions from your server
|
||||
if (this.subscriptionRestHookEnabled) {
|
||||
if (appProperties.getSubscription() != null && appProperties.getSubscription().getResthook_enabled() != null) {
|
||||
modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
}
|
||||
|
||||
if (this.subscriptionEmailEnabled) {
|
||||
if (appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null) {
|
||||
modelConfig.addSupportedSubscriptionType(Subscription.SubscriptionChannelType.EMAIL);
|
||||
}
|
||||
|
||||
@@ -171,7 +150,7 @@ public class FhirServerConfigCommon {
|
||||
* <p>
|
||||
* A URL to a remote database could also be placed here, along with login credentials and other properties supported by BasicDataSource.
|
||||
*/
|
||||
@Bean(destroyMethod = "close")
|
||||
/*@Bean(destroyMethod = "close")
|
||||
public BasicDataSource dataSource() throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
|
||||
BasicDataSource retVal = new BasicDataSource();
|
||||
Driver driver = (Driver) Class.forName(HapiProperties.getDataSourceDriver()).getConstructor().newInstance();
|
||||
@@ -181,38 +160,37 @@ public class FhirServerConfigCommon {
|
||||
retVal.setPassword(HapiProperties.getDataSourcePassword());
|
||||
retVal.setMaxTotal(HapiProperties.getDataSourceMaxPoolSize());
|
||||
return retVal;
|
||||
}
|
||||
}*/
|
||||
|
||||
@Lazy
|
||||
@Bean
|
||||
public IBinaryStorageSvc binaryStorageSvc() {
|
||||
public IBinaryStorageSvc binaryStorageSvc(AppProperties appProperties) {
|
||||
DatabaseBlobBinaryStorageSvcImpl binaryStorageSvc = new DatabaseBlobBinaryStorageSvcImpl();
|
||||
|
||||
if (HapiProperties.getMaxBinarySize() != null) {
|
||||
binaryStorageSvc.setMaximumBinarySize(HapiProperties.getMaxBinarySize());
|
||||
if (appProperties.getMax_binary_size() != null) {
|
||||
binaryStorageSvc.setMaximumBinarySize(appProperties.getMax_binary_size());
|
||||
}
|
||||
|
||||
return binaryStorageSvc;
|
||||
}
|
||||
|
||||
@Bean()
|
||||
public IEmailSender emailSender() {
|
||||
if (this.emailEnabled) {
|
||||
public IEmailSender emailSender(AppProperties appProperties, Optional<SubscriptionDeliveryHandlerFactory> subscriptionDeliveryHandlerFactory) {
|
||||
if (appProperties.getSubscription() != null && appProperties.getSubscription().getEmail() != null) {
|
||||
JavaMailEmailSender retVal = new JavaMailEmailSender();
|
||||
|
||||
retVal.setSmtpServerHostname(this.emailHost);
|
||||
retVal.setSmtpServerPort(this.emailPort);
|
||||
retVal.setSmtpServerUsername(this.emailUsername);
|
||||
retVal.setSmtpServerPassword(this.emailPassword);
|
||||
retVal.setAuth(this.emailAuth);
|
||||
retVal.setStartTlsEnable(this.emailStartTlsEnable);
|
||||
retVal.setStartTlsRequired(this.emailStartTlsRequired);
|
||||
retVal.setQuitWait(this.emailQuitWait);
|
||||
|
||||
SubscriptionDeliveryHandlerFactory subscriptionDeliveryHandlerFactory = myAppCtx.getBean(SubscriptionDeliveryHandlerFactory.class);
|
||||
Validate.notNull(subscriptionDeliveryHandlerFactory, "No subscription delivery handler");
|
||||
subscriptionDeliveryHandlerFactory.setEmailSender(retVal);
|
||||
AppProperties.Subscription.Email email = appProperties.getSubscription().getEmail();
|
||||
retVal.setSmtpServerHostname(email.getHost());
|
||||
retVal.setSmtpServerPort(email.getPort());
|
||||
retVal.setSmtpServerUsername(email.getUsername());
|
||||
retVal.setSmtpServerPassword(email.getPassword());
|
||||
retVal.setAuth(email.getAuth());
|
||||
retVal.setStartTlsEnable(email.getStartTlsEnable());
|
||||
retVal.setStartTlsRequired(email.getStartTlsRequired());
|
||||
retVal.setQuitWait(email.getQuitWait());
|
||||
|
||||
if(subscriptionDeliveryHandlerFactory.isPresent())
|
||||
subscriptionDeliveryHandlerFactory.get().setEmailSender(retVal);
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -7,13 +7,20 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@Profile("dstu2")
|
||||
public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
||||
|
||||
@Autowired
|
||||
@@ -24,14 +31,20 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
||||
* the default/max page sizes for search results. You can set these however
|
||||
* you want, although very large page sizes will require a lot of RAM.
|
||||
*/
|
||||
@Autowired
|
||||
AppProperties appProperties;
|
||||
|
||||
@Override
|
||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
|
||||
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
|
||||
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
|
||||
pagingProvider.setDefaultPageSize(appProperties.getDefault_page_size());
|
||||
pagingProvider.setMaximumPageSize(appProperties.getMax_page_size());
|
||||
return pagingProvider;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment configurableEnvironment;
|
||||
|
||||
@Override
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
@@ -43,8 +56,7 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
|
||||
}
|
||||
|
||||
retVal.setJpaProperties(HapiProperties.getJpaProperties());
|
||||
retVal.setJpaProperties(EnvironmentHelper.getHibernateProperties(configurableEnvironment));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@@ -56,4 +68,5 @@ public class FhirServerConfigDstu2 extends BaseJavaConfigDstu2 {
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
||||
@@ -14,6 +16,7 @@ import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@Profile("dstu3")
|
||||
public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
|
||||
|
||||
@Autowired
|
||||
@@ -24,14 +27,20 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
|
||||
* the default/max page sizes for search results. You can set these however
|
||||
* you want, although very large page sizes will require a lot of RAM.
|
||||
*/
|
||||
@Autowired
|
||||
AppProperties appProperties;
|
||||
|
||||
@Override
|
||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
|
||||
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
|
||||
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
|
||||
pagingProvider.setDefaultPageSize(appProperties.getDefault_page_size());
|
||||
pagingProvider.setMaximumPageSize(appProperties.getMax_page_size());
|
||||
return pagingProvider;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment configurableEnvironment;
|
||||
|
||||
@Override
|
||||
@Bean
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
@@ -44,7 +53,7 @@ public class FhirServerConfigDstu3 extends BaseJavaConfigDstu3 {
|
||||
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
|
||||
}
|
||||
|
||||
retVal.setJpaProperties(HapiProperties.getJpaProperties());
|
||||
retVal.setJpaProperties(EnvironmentHelper.getHibernateProperties(configurableEnvironment));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,13 +7,19 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
import java.util.Arrays;
|
||||
import java.util.Properties;
|
||||
|
||||
@Configuration
|
||||
@Profile("r4")
|
||||
public class FhirServerConfigR4 extends BaseJavaConfigR4 {
|
||||
|
||||
@Autowired
|
||||
@@ -24,14 +30,20 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 {
|
||||
* the default/max page sizes for search results. You can set these however
|
||||
* you want, although very large page sizes will require a lot of RAM.
|
||||
*/
|
||||
@Autowired
|
||||
AppProperties appProperties;
|
||||
|
||||
@Override
|
||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
|
||||
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
|
||||
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
|
||||
pagingProvider.setDefaultPageSize(appProperties.getDefault_page_size());
|
||||
pagingProvider.setMaximumPageSize(appProperties.getMax_page_size());
|
||||
return pagingProvider;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment configurableEnvironment;
|
||||
|
||||
@Override
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
@@ -44,7 +56,7 @@ public class FhirServerConfigR4 extends BaseJavaConfigR4 {
|
||||
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
|
||||
}
|
||||
|
||||
retVal.setJpaProperties(HapiProperties.getJpaProperties());
|
||||
retVal.setJpaProperties(EnvironmentHelper.getHibernateProperties(configurableEnvironment));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@@ -7,6 +7,8 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Primary;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.core.env.ConfigurableEnvironment;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
||||
|
||||
@@ -14,6 +16,7 @@ import javax.persistence.EntityManagerFactory;
|
||||
import javax.sql.DataSource;
|
||||
|
||||
@Configuration
|
||||
@Profile("r5")
|
||||
public class FhirServerConfigR5 extends BaseJavaConfigR5 {
|
||||
|
||||
@Autowired
|
||||
@@ -24,14 +27,20 @@ public class FhirServerConfigR5 extends BaseJavaConfigR5 {
|
||||
* the default/max page sizes for search results. You can set these however
|
||||
* you want, although very large page sizes will require a lot of RAM.
|
||||
*/
|
||||
@Autowired
|
||||
AppProperties appProperties;
|
||||
|
||||
@Override
|
||||
public DatabaseBackedPagingProvider databaseBackedPagingProvider() {
|
||||
DatabaseBackedPagingProvider pagingProvider = super.databaseBackedPagingProvider();
|
||||
pagingProvider.setDefaultPageSize(HapiProperties.getDefaultPageSize());
|
||||
pagingProvider.setMaximumPageSize(HapiProperties.getMaximumPageSize());
|
||||
pagingProvider.setDefaultPageSize(appProperties.getDefault_page_size());
|
||||
pagingProvider.setMaximumPageSize(appProperties.getMax_page_size());
|
||||
return pagingProvider;
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private ConfigurableEnvironment configurableEnvironment;
|
||||
|
||||
@Override
|
||||
@Bean()
|
||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
||||
@@ -44,7 +53,7 @@ public class FhirServerConfigR5 extends BaseJavaConfigR5 {
|
||||
throw new ConfigurationException("Could not set the data source due to a configuration issue", e);
|
||||
}
|
||||
|
||||
retVal.setJpaProperties(HapiProperties.getJpaProperties());
|
||||
retVal.setJpaProperties(EnvironmentHelper.getHibernateProperties(configurableEnvironment));
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
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
|
||||
/**
|
||||
@@ -35,15 +34,19 @@ public class FhirTesterConfig {
|
||||
* you might want to use that instead of using the variable.
|
||||
*/
|
||||
@Bean
|
||||
public TesterConfig testerConfig() {
|
||||
public TesterConfig testerConfig(AppProperties appProperties) {
|
||||
TesterConfig retVal = new TesterConfig();
|
||||
appProperties.getTester().stream().forEach(t -> {
|
||||
retVal
|
||||
.addServer()
|
||||
.withId(HapiProperties.getServerId())
|
||||
.withFhirVersion(HapiProperties.getFhirVersion())
|
||||
.withBaseUrl(HapiProperties.getServerAddress())
|
||||
.withName(HapiProperties.getServerName());
|
||||
retVal.setRefuseToFetchThirdPartyUrls(HapiProperties.getTesterConfigRefustToFetchThirdPartyUrls());
|
||||
.withId(t.getId())
|
||||
.withFhirVersion(t.getFhir_version())
|
||||
.withBaseUrl(t.getServer_address())
|
||||
.withName(t.getName());
|
||||
retVal.setRefuseToFetchThirdPartyUrls(
|
||||
t.getRefuse_to_fetch_third_party_urls());
|
||||
|
||||
});
|
||||
return retVal;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,535 +0,0 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.ETagSupportEnum;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus;
|
||||
import org.hibernate.search.elasticsearch.cfg.IndexSchemaManagementStrategy;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.trim;
|
||||
|
||||
public class HapiProperties {
|
||||
static final String ENABLE_INDEX_MISSING_FIELDS = "enable_index_missing_fields";
|
||||
static final String AUTO_CREATE_PLACEHOLDER_REFERENCE_TARGETS = "auto_create_placeholder_reference_targets";
|
||||
static final String ENFORCE_REFERENTIAL_INTEGRITY_ON_WRITE = "enforce_referential_integrity_on_write";
|
||||
static final String ENFORCE_REFERENTIAL_INTEGRITY_ON_DELETE = "enforce_referential_integrity_on_delete";
|
||||
static final String BINARY_STORAGE_ENABLED = "binary_storage.enabled";
|
||||
static final String ALLOW_EXTERNAL_REFERENCES = "allow_external_references";
|
||||
static final String ALLOW_MULTIPLE_DELETE = "allow_multiple_delete";
|
||||
static final String ALLOW_PLACEHOLDER_REFERENCES = "allow_placeholder_references";
|
||||
static final String REUSE_CACHED_SEARCH_RESULTS_MILLIS = "reuse_cached_search_results_millis";
|
||||
static final String DATASOURCE_DRIVER = "datasource.driver";
|
||||
static final String DATASOURCE_MAX_POOL_SIZE = "datasource.max_pool_size";
|
||||
static final String DATASOURCE_PASSWORD = "datasource.password";
|
||||
static final String DATASOURCE_URL = "datasource.url";
|
||||
static final String DATASOURCE_USERNAME = "datasource.username";
|
||||
static final String DEFAULT_ENCODING = "default_encoding";
|
||||
static final String DEFAULT_PAGE_SIZE = "default_page_size";
|
||||
static final String DEFAULT_PRETTY_PRINT = "default_pretty_print";
|
||||
static final String ETAG_SUPPORT = "etag_support";
|
||||
static final String FHIR_VERSION = "fhir_version";
|
||||
static final String ALLOW_CASCADING_DELETES = "allow_cascading_deletes";
|
||||
static final String HAPI_PROPERTIES = "hapi.properties";
|
||||
static final String LOGGER_ERROR_FORMAT = "logger.error_format";
|
||||
static final String LOGGER_FORMAT = "logger.format";
|
||||
static final String LOGGER_LOG_EXCEPTIONS = "logger.log_exceptions";
|
||||
static final String LOGGER_NAME = "logger.name";
|
||||
static final String MAX_FETCH_SIZE = "max_fetch_size";
|
||||
static final String MAX_PAGE_SIZE = "max_page_size";
|
||||
static final String SERVER_ADDRESS = "server_address";
|
||||
static final String SERVER_ID = "server.id";
|
||||
static final String SERVER_NAME = "server.name";
|
||||
static final String SUBSCRIPTION_EMAIL_ENABLED = "subscription.email.enabled";
|
||||
static final String SUBSCRIPTION_RESTHOOK_ENABLED = "subscription.resthook.enabled";
|
||||
static final String SUBSCRIPTION_WEBSOCKET_ENABLED = "subscription.websocket.enabled";
|
||||
static final String EMPI_ENABLED = "empi.enabled";
|
||||
static final String PARTITIONING_ENABLED = "partitioning.enabled";
|
||||
static final String PARTITIONING_CROSS_PARTITION_REFERENCE_MODE = "partitioning.cross_partition_reference_mode";
|
||||
static final String ALLOWED_BUNDLE_TYPES = "allowed_bundle_types";
|
||||
static final String TEST_PORT = "test.port";
|
||||
static final String TESTER_CONFIG_REFUSE_TO_FETCH_THIRD_PARTY_URLS = "tester.config.refuse_to_fetch_third_party_urls";
|
||||
static final String CORS_ENABLED = "cors.enabled";
|
||||
static final String CORS_ALLOWED_ORIGIN = "cors.allowed_origin";
|
||||
static final String CORS_ALLOW_CREDENTIALS = "cors.allowCredentials";
|
||||
static final String ALLOW_CONTAINS_SEARCHES = "allow_contains_searches";
|
||||
static final String ALLOW_OVERRIDE_DEFAULT_SEARCH_PARAMS = "allow_override_default_search_params";
|
||||
static final String EMAIL_FROM = "email.from";
|
||||
static final String VALIDATE_REQUESTS_ENABLED = "validation.requests.enabled";
|
||||
static final String VALIDATE_RESPONSES_ENABLED = "validation.responses.enabled";
|
||||
static final String FILTER_SEARCH_ENABLED = "filter_search.enabled";
|
||||
static final String GRAPHQL_ENABLED = "graphql.enabled";
|
||||
static final String BULK_EXPORT_ENABLED = "bulk.export.enabled";
|
||||
static final String EXPIRE_SEARCH_RESULTS_AFTER_MINS = "retain_cached_searches_mins";
|
||||
static final String MAX_BINARY_SIZE = "max_binary_size";
|
||||
static final String PARTITIONING_MULTITENANCY_ENABLED = "partitioning.multitenancy.enabled";
|
||||
private static final String PARTITIONING_INCLUDE_PARTITION_IN_SEARCH_HASHES = "partitioning.partitioning_include_in_search_hashes";
|
||||
static final String CLIENT_ID_STRATEGY = "daoconfig.client_id_strategy";
|
||||
private static Properties ourProperties;
|
||||
|
||||
public static boolean isElasticSearchEnabled() {
|
||||
return HapiProperties.getPropertyBoolean("elasticsearch.enabled", false);
|
||||
}
|
||||
|
||||
/*
|
||||
* Force the configuration to be reloaded
|
||||
*/
|
||||
public static void forceReload() {
|
||||
ourProperties = null;
|
||||
getProperties();
|
||||
}
|
||||
|
||||
/**
|
||||
* This is mostly here for unit tests. Use the actual properties file
|
||||
* to set values
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static void setProperty(String theKey, String theValue) {
|
||||
getProperties().setProperty(theKey, theValue);
|
||||
}
|
||||
|
||||
public static Properties getJpaProperties() {
|
||||
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_strategy", 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
|
||||
Properties properties;
|
||||
try (InputStream in = HapiProperties.class.getClassLoader().getResourceAsStream(HAPI_PROPERTIES)) {
|
||||
properties = new Properties();
|
||||
properties.load(in);
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException("Could not load HAPI properties", e);
|
||||
}
|
||||
|
||||
Properties overrideProps = loadOverrideProperties();
|
||||
if (overrideProps != null) {
|
||||
properties.putAll(overrideProps);
|
||||
}
|
||||
properties.putAll(System.getenv().entrySet()
|
||||
.stream()
|
||||
.filter(e -> e.getValue() != null && properties.containsKey(e.getKey()))
|
||||
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
|
||||
return properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a configuration file path is explicitly specified via -Dhapi.properties=<path>, the properties there will
|
||||
* be used to override the entries in the default hapi.properties file (currently under WEB-INF/classes)
|
||||
*
|
||||
* @return properties loaded from the explicitly specified configuraiton file if there is one, or null otherwise.
|
||||
*/
|
||||
private static Properties loadOverrideProperties() {
|
||||
String confFile = System.getProperty(HAPI_PROPERTIES);
|
||||
if (confFile != null) {
|
||||
try {
|
||||
Properties props = new Properties();
|
||||
props.load(new FileInputStream(confFile));
|
||||
return props;
|
||||
} catch (Exception e) {
|
||||
throw new ConfigurationException("Could not load HAPI properties file: " + confFile, e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static String getProperty(String propertyName) {
|
||||
String env = "HAPI_" + propertyName.toUpperCase(Locale.US);
|
||||
env = env.replace(".", "_");
|
||||
env = env.replace("-", "_");
|
||||
|
||||
String propertyValue = System.getenv(env);
|
||||
if (propertyValue != null) {
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
Properties properties = HapiProperties.getProperties();
|
||||
if (properties != null) {
|
||||
propertyValue = properties.getProperty(propertyName);
|
||||
}
|
||||
|
||||
return propertyValue;
|
||||
}
|
||||
|
||||
private static String getProperty(String propertyName, String defaultValue) {
|
||||
String value = getProperty(propertyName);
|
||||
|
||||
if (value != null && value.length() > 0) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
private static Boolean getBooleanProperty(String propertyName, Boolean defaultValue) {
|
||||
String value = HapiProperties.getProperty(propertyName);
|
||||
|
||||
if (value == null || value.length() == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return Boolean.parseBoolean(value);
|
||||
}
|
||||
|
||||
private static boolean getBooleanProperty(String propertyName, boolean defaultValue) {
|
||||
return getBooleanProperty(propertyName, Boolean.valueOf(defaultValue));
|
||||
}
|
||||
|
||||
private static Integer getIntegerProperty(String propertyName, Integer defaultValue) {
|
||||
String value = HapiProperties.getProperty(propertyName);
|
||||
|
||||
if (value == null || value.length() == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
return Integer.parseInt(value);
|
||||
}
|
||||
|
||||
public static FhirVersionEnum getFhirVersion() {
|
||||
String fhirVersionString = HapiProperties.getProperty(FHIR_VERSION);
|
||||
|
||||
if (fhirVersionString != null && fhirVersionString.length() > 0) {
|
||||
return FhirVersionEnum.valueOf(fhirVersionString);
|
||||
}
|
||||
|
||||
return FhirVersionEnum.DSTU3;
|
||||
}
|
||||
|
||||
public static boolean isBinaryStorageEnabled() {
|
||||
return HapiProperties.getBooleanProperty(BINARY_STORAGE_ENABLED, true);
|
||||
}
|
||||
|
||||
public static ETagSupportEnum getEtagSupport() {
|
||||
String etagSupportString = HapiProperties.getProperty(ETAG_SUPPORT);
|
||||
|
||||
if (etagSupportString != null && etagSupportString.length() > 0) {
|
||||
return ETagSupportEnum.valueOf(etagSupportString);
|
||||
}
|
||||
|
||||
return ETagSupportEnum.ENABLED;
|
||||
}
|
||||
|
||||
public static DaoConfig.ClientIdStrategyEnum getClientIdStrategy() {
|
||||
String idStrategy = HapiProperties.getProperty(CLIENT_ID_STRATEGY);
|
||||
|
||||
if (idStrategy != null && idStrategy.length() > 0) {
|
||||
return DaoConfig.ClientIdStrategyEnum.valueOf(idStrategy);
|
||||
}
|
||||
|
||||
return DaoConfig.ClientIdStrategyEnum.ALPHANUMERIC;
|
||||
}
|
||||
|
||||
public static EncodingEnum getDefaultEncoding() {
|
||||
String defaultEncodingString = HapiProperties.getProperty(DEFAULT_ENCODING);
|
||||
|
||||
if (defaultEncodingString != null && defaultEncodingString.length() > 0) {
|
||||
return EncodingEnum.valueOf(defaultEncodingString);
|
||||
}
|
||||
|
||||
return EncodingEnum.JSON;
|
||||
}
|
||||
|
||||
public static Boolean getDefaultPrettyPrint() {
|
||||
return HapiProperties.getBooleanProperty(DEFAULT_PRETTY_PRINT, true);
|
||||
}
|
||||
|
||||
public static String getServerAddress() {
|
||||
return HapiProperties.getProperty(SERVER_ADDRESS);
|
||||
}
|
||||
|
||||
public static Integer getDefaultPageSize() {
|
||||
return HapiProperties.getIntegerProperty(DEFAULT_PAGE_SIZE, 20);
|
||||
}
|
||||
|
||||
public static Integer getMaximumPageSize() {
|
||||
return HapiProperties.getIntegerProperty(MAX_PAGE_SIZE, 200);
|
||||
}
|
||||
|
||||
public static Integer getMaximumFetchSize() {
|
||||
return HapiProperties.getIntegerProperty(MAX_FETCH_SIZE, Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
public static String getLoggerName() {
|
||||
return HapiProperties.getProperty(LOGGER_NAME, "fhirtest.access");
|
||||
}
|
||||
|
||||
public static String getLoggerFormat() {
|
||||
return HapiProperties.getProperty(LOGGER_FORMAT, "Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]");
|
||||
}
|
||||
|
||||
public static String getLoggerErrorFormat() {
|
||||
return HapiProperties.getProperty(LOGGER_ERROR_FORMAT, "ERROR - ${requestVerb} ${requestUrl}");
|
||||
}
|
||||
|
||||
public static Boolean getLoggerLogExceptions() {
|
||||
return HapiProperties.getBooleanProperty(LOGGER_LOG_EXCEPTIONS, true);
|
||||
}
|
||||
|
||||
public static String getDataSourceDriver() {
|
||||
return HapiProperties.getProperty(DATASOURCE_DRIVER, "org.apache.derby.jdbc.EmbeddedDriver");
|
||||
}
|
||||
|
||||
public static Integer getDataSourceMaxPoolSize() {
|
||||
return HapiProperties.getIntegerProperty(DATASOURCE_MAX_POOL_SIZE, 10);
|
||||
}
|
||||
|
||||
public static String getDataSourceUrl() {
|
||||
return HapiProperties.getProperty(DATASOURCE_URL, "jdbc:derby:directory:target/jpaserver_derby_files;create=true");
|
||||
}
|
||||
|
||||
public static String getDataSourceUsername() {
|
||||
return HapiProperties.getProperty(DATASOURCE_USERNAME);
|
||||
}
|
||||
|
||||
public static String getDataSourcePassword() {
|
||||
return HapiProperties.getProperty(DATASOURCE_PASSWORD);
|
||||
}
|
||||
|
||||
public static Boolean getAllowMultipleDelete() {
|
||||
return HapiProperties.getBooleanProperty(ALLOW_MULTIPLE_DELETE, false);
|
||||
}
|
||||
|
||||
public static Boolean getAllowCascadingDeletes() {
|
||||
return HapiProperties.getBooleanProperty(ALLOW_CASCADING_DELETES, false);
|
||||
}
|
||||
|
||||
public static Boolean getAllowExternalReferences() {
|
||||
return HapiProperties.getBooleanProperty(ALLOW_EXTERNAL_REFERENCES, false);
|
||||
}
|
||||
|
||||
public static Boolean getExpungeEnabled() {
|
||||
return HapiProperties.getBooleanProperty("expunge_enabled", true);
|
||||
}
|
||||
|
||||
public static Boolean getTesterConfigRefustToFetchThirdPartyUrls() {
|
||||
return HapiProperties.getBooleanProperty(TESTER_CONFIG_REFUSE_TO_FETCH_THIRD_PARTY_URLS, false);
|
||||
}
|
||||
|
||||
public static Boolean getCorsEnabled() {
|
||||
return HapiProperties.getBooleanProperty(CORS_ENABLED, true);
|
||||
}
|
||||
|
||||
public static String getCorsAllowedOrigin() {
|
||||
return HapiProperties.getProperty(CORS_ALLOWED_ORIGIN, "*");
|
||||
}
|
||||
|
||||
public static String getAllowedBundleTypes() {
|
||||
return HapiProperties.getProperty(ALLOWED_BUNDLE_TYPES, "");
|
||||
}
|
||||
|
||||
@Nonnull
|
||||
public static Set<String> getSupportedResourceTypes() {
|
||||
String[] types = defaultString(getProperty("supported_resource_types")).split(",");
|
||||
return Arrays.stream(types)
|
||||
.map(StringUtils::trim)
|
||||
.filter(StringUtils::isNotBlank)
|
||||
.collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
public static String getServerName() {
|
||||
return HapiProperties.getProperty(SERVER_NAME, "Local Tester");
|
||||
}
|
||||
|
||||
public static String getServerId() {
|
||||
return HapiProperties.getProperty(SERVER_ID, "home");
|
||||
}
|
||||
|
||||
public static Boolean getAllowPlaceholderReferences() {
|
||||
return HapiProperties.getBooleanProperty(ALLOW_PLACEHOLDER_REFERENCES, true);
|
||||
}
|
||||
|
||||
public static Boolean getSubscriptionEmailEnabled() {
|
||||
return HapiProperties.getBooleanProperty(SUBSCRIPTION_EMAIL_ENABLED, false);
|
||||
}
|
||||
|
||||
public static Boolean getSubscriptionRestHookEnabled() {
|
||||
return HapiProperties.getBooleanProperty(SUBSCRIPTION_RESTHOOK_ENABLED, false);
|
||||
}
|
||||
|
||||
public static Boolean getSubscriptionWebsocketEnabled() {
|
||||
return HapiProperties.getBooleanProperty(SUBSCRIPTION_WEBSOCKET_ENABLED, false);
|
||||
}
|
||||
|
||||
public static Boolean getEmpiEnabled() {
|
||||
return HapiProperties.getBooleanProperty(EMPI_ENABLED, false);
|
||||
}
|
||||
|
||||
public static Boolean getPartitioningEnabled() {
|
||||
return HapiProperties.getBooleanProperty(PARTITIONING_ENABLED, false);
|
||||
}
|
||||
|
||||
|
||||
public static String getPartitioningCrossPartitionReferenceMode() {
|
||||
return HapiProperties.getProperty(PARTITIONING_CROSS_PARTITION_REFERENCE_MODE, "NOT_ALLOWED");
|
||||
}
|
||||
|
||||
public static Boolean getIncludePartitionInSearchHashes() {
|
||||
return HapiProperties.getBooleanProperty(PARTITIONING_INCLUDE_PARTITION_IN_SEARCH_HASHES, true);
|
||||
}
|
||||
|
||||
public static Boolean getAllowContainsSearches() {
|
||||
return HapiProperties.getBooleanProperty(ALLOW_CONTAINS_SEARCHES, true);
|
||||
}
|
||||
|
||||
public static Boolean getAllowOverrideDefaultSearchParams() {
|
||||
return HapiProperties.getBooleanProperty(ALLOW_OVERRIDE_DEFAULT_SEARCH_PARAMS, true);
|
||||
}
|
||||
|
||||
public static String getEmailFrom() {
|
||||
return HapiProperties.getProperty(EMAIL_FROM, "some@test.com");
|
||||
}
|
||||
|
||||
public static Boolean getEmailEnabled() {
|
||||
return HapiProperties.getBooleanProperty("email.enabled", false);
|
||||
}
|
||||
|
||||
public static String getEmailHost() {
|
||||
return HapiProperties.getProperty("email.host");
|
||||
}
|
||||
|
||||
public static Integer getEmailPort() {
|
||||
return HapiProperties.getIntegerProperty("email.port", 0);
|
||||
}
|
||||
|
||||
public static String getEmailUsername() {
|
||||
return HapiProperties.getProperty("email.username");
|
||||
}
|
||||
|
||||
public static String getEmailPassword() {
|
||||
return HapiProperties.getProperty("email.password");
|
||||
}
|
||||
|
||||
// Defaults from https://javaee.github.io/javamail/docs/api/com/sun/mail/smtp/package-summary.html
|
||||
public static Boolean getEmailAuth() {
|
||||
return HapiProperties.getBooleanProperty("email.auth", false);
|
||||
}
|
||||
|
||||
public static Boolean getEmailStartTlsEnable() {
|
||||
return HapiProperties.getBooleanProperty("email.starttls.enable", false);
|
||||
}
|
||||
|
||||
public static Boolean getEmailStartTlsRequired() {
|
||||
return HapiProperties.getBooleanProperty("email.starttls.required", false);
|
||||
}
|
||||
|
||||
public static Boolean getEmailQuitWait() {
|
||||
return HapiProperties.getBooleanProperty("email.quitwait", true);
|
||||
}
|
||||
|
||||
public static Long getReuseCachedSearchResultsMillis() {
|
||||
String value = HapiProperties.getProperty(REUSE_CACHED_SEARCH_RESULTS_MILLIS, "60000");
|
||||
return Long.valueOf(value);
|
||||
}
|
||||
|
||||
public static Long getExpireSearchResultsAfterMins() {
|
||||
String value = HapiProperties.getProperty(EXPIRE_SEARCH_RESULTS_AFTER_MINS, "60");
|
||||
return Long.valueOf(value);
|
||||
}
|
||||
|
||||
public static Boolean getCorsAllowedCredentials() {
|
||||
return HapiProperties.getBooleanProperty(CORS_ALLOW_CREDENTIALS, false);
|
||||
}
|
||||
|
||||
public static boolean getValidateRequestsEnabled() {
|
||||
return HapiProperties.getBooleanProperty(VALIDATE_REQUESTS_ENABLED, false);
|
||||
}
|
||||
|
||||
public static boolean getValidateResponsesEnabled() {
|
||||
return HapiProperties.getBooleanProperty(VALIDATE_RESPONSES_ENABLED, false);
|
||||
}
|
||||
|
||||
public static boolean getFilterSearchEnabled() {
|
||||
return HapiProperties.getBooleanProperty(FILTER_SEARCH_ENABLED, true);
|
||||
}
|
||||
|
||||
public static boolean getGraphqlEnabled() {
|
||||
return HapiProperties.getBooleanProperty(GRAPHQL_ENABLED, true);
|
||||
}
|
||||
|
||||
public static boolean getEnforceReferentialIntegrityOnDelete() {
|
||||
return HapiProperties.getBooleanProperty(ENFORCE_REFERENTIAL_INTEGRITY_ON_DELETE, true);
|
||||
}
|
||||
|
||||
public static boolean getEnforceReferentialIntegrityOnWrite() {
|
||||
return HapiProperties.getBooleanProperty(ENFORCE_REFERENTIAL_INTEGRITY_ON_WRITE, true);
|
||||
}
|
||||
|
||||
public static boolean getAutoCreatePlaceholderReferenceTargets() {
|
||||
return HapiProperties.getBooleanProperty(AUTO_CREATE_PLACEHOLDER_REFERENCE_TARGETS, true);
|
||||
}
|
||||
|
||||
public static boolean getEnableIndexMissingFields() {
|
||||
return HapiProperties.getBooleanProperty(ENABLE_INDEX_MISSING_FIELDS, false);
|
||||
}
|
||||
|
||||
public static Integer getMaxBinarySize() {
|
||||
return getIntegerProperty(MAX_BINARY_SIZE, null);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public static boolean isFhirPathFilterInterceptorEnabled() {
|
||||
return HapiProperties.getBooleanProperty("fhirpath_interceptor.enabled", false);
|
||||
}
|
||||
|
||||
public static boolean getPartitioningMultitenancyEnabled() {
|
||||
return HapiProperties.getBooleanProperty(PARTITIONING_MULTITENANCY_ENABLED, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
|
||||
@Import(AppProperties.class)
|
||||
public class JpaRestfulServer extends BaseJpaRestfulServer {
|
||||
|
||||
@Autowired
|
||||
AppProperties appProperties;
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public JpaRestfulServer() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void initialize() throws ServletException {
|
||||
super.initialize();
|
||||
|
||||
133
src/main/resources/application.yaml
Normal file
133
src/main/resources/application.yaml
Normal file
@@ -0,0 +1,133 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: 'jdbc:h2:file:./target/database/h2'
|
||||
username: sa
|
||||
password: null
|
||||
driverClassName: org.h2.Driver
|
||||
max-active: 15
|
||||
profiles:
|
||||
### This is the FHIR version. Choose between, dstu2, dstu3, r4 or r5
|
||||
active: r4
|
||||
jpa:
|
||||
properties:
|
||||
hibernate.dialect: org.hibernate.dialect.H2Dialect
|
||||
hibernate.search.model_mapping: ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory
|
||||
hibernate.format_sql: false
|
||||
hibernate.show_sql: false
|
||||
hibernate.hbm2ddl.auto: update
|
||||
hibernate.jdbc.batch_size: 20
|
||||
hibernate.cache.use_query_cache: false
|
||||
hibernate.cache.use_second_level_cache: false
|
||||
hibernate.cache.use_structured_entries: false
|
||||
hibernate.cache.use_minimal_puts: false
|
||||
hibernate.search.default.directory_provider: filesystem
|
||||
hibernate.search.default.indexBase: target/lucenefiles
|
||||
hibernate.search.lucene_version: LUCENE_CURRENT
|
||||
|
||||
batch:
|
||||
job:
|
||||
enabled: false
|
||||
|
||||
hapi:
|
||||
fhir:
|
||||
defer_indexing_for_codesystems_of_size: 101
|
||||
# implementationguides:
|
||||
# -
|
||||
# url: https://build.fhir.org/ig/hl7dk/dk-medcom/branches/corrections/package.tgz
|
||||
# name: dk.fhir.ig.medcom-core
|
||||
# version: 0.8.0
|
||||
# -
|
||||
# name: hl7.fhir.uv.ips
|
||||
# version: 0.3.0
|
||||
|
||||
#supported_resource_types:
|
||||
# - Patient
|
||||
# - Observation
|
||||
# allow_cascading_deletes: true
|
||||
# allow_contains_searches: true
|
||||
# allow_external_references: true
|
||||
# allow_multiple_delete: true
|
||||
# allow_override_default_search_params: true
|
||||
# allow_placeholder_references: true
|
||||
# auto_create_placeholder_reference_targets: false
|
||||
# default_encoding: JSON
|
||||
# default_pretty_print: true
|
||||
# default_page_size: 20
|
||||
# enable_index_missing_fields: false
|
||||
# enforce_referential_integrity_on_delete: false
|
||||
# enforce_referential_integrity_on_write: false
|
||||
# etag_support_enabled: true
|
||||
# expunge_enabled: true
|
||||
# daoconfig_client_id_strategy: null
|
||||
# fhirpath_interceptor_enabled: false
|
||||
# filter_search_enabled: true
|
||||
# graphql_enabled: true
|
||||
#partitioning:
|
||||
# cross_partition_reference_mode: true
|
||||
# multitenancy_enabled: true
|
||||
# partitioning_include_in_search_hashes: true
|
||||
#cors:
|
||||
# allow_Credentials: true
|
||||
# Supports multiple, comma separated allowed origin entries
|
||||
# cors.allowed_origin=http://localhost:8080,https://localhost:8080,https://fhirtest.uhn.ca
|
||||
# allowed_origin:
|
||||
# - '*'
|
||||
|
||||
# logger:
|
||||
# error_format: 'ERROR - ${requestVerb} ${requestUrl}'
|
||||
# format: >-
|
||||
# Path[${servletPath}] Source[${requestHeader.x-forwarded-for}]
|
||||
# Operation[${operationType} ${operationName} ${idOrResourceName}]
|
||||
# UA[${requestHeader.user-agent}] Params[${requestParameters}]
|
||||
# ResponseEncoding[${responseEncodingNoDefault}]
|
||||
# log_exceptions: true
|
||||
# name: fhirtest.access
|
||||
# max_binary_size: 104857600
|
||||
# max_page_size: 200
|
||||
# retain_cached_searches_mins: 60
|
||||
# reuse_cached_search_results_millis: 60000
|
||||
tester:
|
||||
-
|
||||
id: home
|
||||
name: Local Tester
|
||||
server_address: 'http://localhost:8080/fhir'
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
-
|
||||
id: global
|
||||
name: Global Tester
|
||||
server_address: "http://hapi.fhir.org/baseR4"
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
# validation:
|
||||
# requests_enabled: true
|
||||
# responses_enabled: true
|
||||
# binary_storage_enabled: true
|
||||
# bulk_export_enabled: true
|
||||
# partitioning_multitenancy_enabled:
|
||||
# subscription:
|
||||
# resthook_enabled: false
|
||||
# websocket_enabled: false
|
||||
# email:
|
||||
# from: some@test.com
|
||||
# host: google.com
|
||||
# port:
|
||||
# username:
|
||||
# password:
|
||||
# auth:
|
||||
# startTlsEnable:
|
||||
# startTlsRequired:
|
||||
# quitWait:
|
||||
|
||||
|
||||
#
|
||||
#elasticsearch:
|
||||
# debug:
|
||||
# pretty_print_json_log: false
|
||||
# refresh_after_write: false
|
||||
# enabled: false
|
||||
# password: SomePassword
|
||||
# required_index_status: YELLOW
|
||||
# rest_url: 'http://localhost:9200'
|
||||
# schema_management_strategy: CREATE
|
||||
# username: SomeUsername
|
||||
@@ -1,167 +0,0 @@
|
||||
# Adjust this to set the version of FHIR supported by this server. See
|
||||
# FhirVersionEnum for a list of available constants. Example values include
|
||||
# DSTU2, DSTU3, R4.
|
||||
fhir_version=R4
|
||||
|
||||
# This is the address that the FHIR server will report as its own address.
|
||||
# If this server will be deployed (for example) to an internet accessible
|
||||
# server, put the DNS name of that server here.
|
||||
#
|
||||
# Note that this is also the address that the hapi-fhir-testpage-overlay
|
||||
# (the web UI similar to the one at http://hapi.fhir.org) will use to
|
||||
# connect internally to the FHIR server, so this also needs to be a name
|
||||
# accessible from the server itself.
|
||||
server_address=http://localhost:8080/hapi-fhir-jpaserver/fhir/
|
||||
|
||||
enable_index_missing_fields=false
|
||||
auto_create_placeholder_reference_targets=false
|
||||
enforce_referential_integrity_on_write=false
|
||||
enforce_referential_integrity_on_delete=false
|
||||
default_encoding=JSON
|
||||
etag_support=ENABLED
|
||||
reuse_cached_search_results_millis=60000
|
||||
retain_cached_searches_mins=60
|
||||
default_page_size=20
|
||||
max_page_size=200
|
||||
allow_override_default_search_params=true
|
||||
allow_contains_searches=true
|
||||
allow_multiple_delete=true
|
||||
allow_external_references=true
|
||||
allow_cascading_deletes=true
|
||||
allow_placeholder_references=true
|
||||
expunge_enabled=true
|
||||
persistence_unit_name=HAPI_PU
|
||||
logger.name=fhirtest.access
|
||||
logger.format=Path[${servletPath}] Source[${requestHeader.x-forwarded-for}] Operation[${operationType} ${operationName} ${idOrResourceName}] UA[${requestHeader.user-agent}] Params[${requestParameters}] ResponseEncoding[${responseEncodingNoDefault}]
|
||||
logger.error_format=ERROR - ${requestVerb} ${requestUrl}
|
||||
logger.log_exceptions=true
|
||||
datasource.driver=org.h2.Driver
|
||||
datasource.url=jdbc:h2:file:./target/database/h2
|
||||
datasource.username=
|
||||
datasource.password=
|
||||
server.name=Local Tester
|
||||
server.id=home
|
||||
test.port=
|
||||
|
||||
###################################################
|
||||
# Binary Storage (104857600 = 100mb)
|
||||
###################################################
|
||||
max_binary_size=104857600
|
||||
|
||||
###################################################
|
||||
# Validation
|
||||
###################################################
|
||||
# Should all incoming requests be validated
|
||||
validation.requests.enabled=false
|
||||
# Should outgoing responses be validated
|
||||
validation.responses.enabled=false
|
||||
|
||||
###################################################
|
||||
# Search Features
|
||||
###################################################
|
||||
filter_search.enabled=true
|
||||
graphql.enabled=true
|
||||
# See FhirPathFilterInterceptor
|
||||
fhirpath_interceptor.enabled=false
|
||||
|
||||
###################################################
|
||||
# Supported Resources
|
||||
###################################################
|
||||
# Enable the following property if you want to customize the
|
||||
# list of resources that is supported by the server (i.e. to
|
||||
# disable specific resources)
|
||||
#supported_resource_types=Patient,Observation,Encounter
|
||||
|
||||
###################################################
|
||||
# Database Settings
|
||||
###################################################
|
||||
hibernate.dialect=org.hibernate.dialect.H2Dialect
|
||||
hibernate.search.model_mapping=ca.uhn.fhir.jpa.search.LuceneSearchMappingFactory
|
||||
hibernate.format_sql=false
|
||||
hibernate.show_sql=false
|
||||
hibernate.hbm2ddl.auto=update
|
||||
hibernate.jdbc.batch_size=20
|
||||
hibernate.cache.use_query_cache=false
|
||||
hibernate.cache.use_second_level_cache=false
|
||||
hibernate.cache.use_structured_entries=false
|
||||
hibernate.cache.use_minimal_puts=false
|
||||
hibernate.search.default.directory_provider=filesystem
|
||||
hibernate.search.default.indexBase=target/lucenefiles
|
||||
hibernate.search.lucene_version=LUCENE_CURRENT
|
||||
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.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.enabled=true
|
||||
|
||||
##################################################
|
||||
# Bulk Data Specification
|
||||
##################################################
|
||||
bulk.export.enabled=true
|
||||
|
||||
##################################################
|
||||
# CORS Settings
|
||||
##################################################
|
||||
cors.enabled=true
|
||||
cors.allowCredentials=true
|
||||
# Supports multiple, comma separated allowed origin entries
|
||||
# cors.allowed_origin=http://localhost:8080,https://localhost:8080,https://fhirtest.uhn.ca
|
||||
cors.allowed_origin=*
|
||||
|
||||
##################################################
|
||||
# Allowed Bundle Types for persistence (defaults are: COLLECTION,DOCUMENT,MESSAGE)
|
||||
##################################################
|
||||
#allowed_bundle_types=COLLECTION,DOCUMENT,MESSAGE,TRANSACTION,TRANSACTIONRESPONSE,BATCH,BATCHRESPONSE,HISTORY,SEARCHSET
|
||||
|
||||
##################################################
|
||||
# Subscriptions
|
||||
##################################################
|
||||
|
||||
# Enable REST Hook Subscription Channel
|
||||
subscription.resthook.enabled=false
|
||||
|
||||
# Enable Email Subscription Channel
|
||||
subscription.email.enabled=false
|
||||
email.enabled=false
|
||||
email.from=some@test.com
|
||||
email.host=
|
||||
email.port=0
|
||||
email.username=
|
||||
email.password=
|
||||
|
||||
# Enable Websocket Subscription Channel
|
||||
subscription.websocket.enabled=false
|
||||
|
||||
###################################################
|
||||
# EMPI
|
||||
###################################################
|
||||
empi.enabled=false
|
||||
|
||||
###################################################
|
||||
# Partitioning And Multitenancy
|
||||
###################################################
|
||||
partitioning.enabled=false
|
||||
partitioning.cross_partition_reference_mode=NOT_ALLOWED
|
||||
partitioning.partitioning_include_in_search_hashes=true
|
||||
partitioning.multitenancy.enabled=false
|
||||
|
||||
#daoconfig.client_id_strategy=ANY
|
||||
|
||||
@@ -9,24 +9,6 @@
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<appender name="EMPI_TROUBLESHOOTING" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter"><level>DEBUG</level></filter>
|
||||
<file>${smile.basedir}/log/empi-troubleshooting.log</file>
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.FixedWindowRollingPolicy">
|
||||
<fileNamePattern>${smile.basedir}/log/empi-troubleshooting.log.%i.gz</fileNamePattern>
|
||||
<minIndex>1</minIndex>
|
||||
<maxIndex>9</maxIndex>
|
||||
</rollingPolicy>
|
||||
<triggeringPolicy class="ch.qos.logback.core.rolling.SizeBasedTriggeringPolicy">
|
||||
<maxFileSize>5MB</maxFileSize>
|
||||
</triggeringPolicy>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n${log.stackfilter.pattern}</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
<logger name="ca.uhn.fhir.log.empi_troubleshooting" level="TRACE">
|
||||
<appender-ref ref="EMPI_TROUBLESHOOTING"/>
|
||||
</logger>
|
||||
|
||||
<root level="INFO">
|
||||
<appender-ref ref="STDOUT" />
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
<web-app
|
||||
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
|
||||
metadata-complete="false"
|
||||
version="3.1">
|
||||
|
||||
<listener>
|
||||
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
|
||||
</listener>
|
||||
<context-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>
|
||||
ca.uhn.fhir.jpa.starter.ApplicationContext
|
||||
</param-value>
|
||||
</context-param>
|
||||
<context-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
</param-value>
|
||||
</context-param>
|
||||
|
||||
<!-- Servlets -->
|
||||
<servlet>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
|
||||
<init-param>
|
||||
<param-name>contextClass</param-name>
|
||||
<param-value>org.springframework.web.context.support.AnnotationConfigWebApplicationContext</param-value>
|
||||
</init-param>
|
||||
<init-param>
|
||||
<param-name>contextConfigLocation</param-name>
|
||||
<param-value>
|
||||
ca.uhn.fhir.jpa.starter.FhirTesterConfig
|
||||
</param-value>
|
||||
</init-param>
|
||||
<load-on-startup>2</load-on-startup>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>spring</servlet-name>
|
||||
<url-pattern>/</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<servlet-class>ca.uhn.fhir.jpa.starter.JpaRestfulServer</servlet-class>
|
||||
<load-on-startup>1</load-on-startup>
|
||||
</servlet>
|
||||
<servlet-mapping>
|
||||
<servlet-name>fhirServlet</servlet-name>
|
||||
<url-pattern>/fhir/*</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
</web-app>
|
||||
20
src/test/java/ca/uhn/fhir/jpa/starter/Demo.java
Normal file
20
src/test/java/ca/uhn/fhir/jpa/starter/Demo.java
Normal file
@@ -0,0 +1,20 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.boot.autoconfigure.elasticsearch.ElasticsearchRestClientAutoConfiguration;
|
||||
import org.springframework.boot.web.servlet.ServletComponentScan;
|
||||
|
||||
@ServletComponentScan(basePackageClasses = {JpaRestfulServer.class})
|
||||
@SpringBootApplication(exclude = ElasticsearchRestClientAutoConfiguration.class)
|
||||
public class Demo {
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
System.setProperty("spring.profiles.active", "r4");
|
||||
System.setProperty("spring.batch.job.enabled", "false");
|
||||
SpringApplication.run(Demo.class, args);
|
||||
|
||||
//Server is now accessible at eg. http://localhost:8080/metadata
|
||||
}
|
||||
}
|
||||
@@ -5,79 +5,53 @@ import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
||||
{
|
||||
"spring.batch.job.enabled=false",
|
||||
"spring.profiles.active=dstu2",
|
||||
"spring.datasource.url=jdbc:h2:mem:dbr2"
|
||||
})
|
||||
public class ExampleServerDstu2IT {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private IGenericClient ourClient;
|
||||
private FhirContext ourCtx;
|
||||
|
||||
static {
|
||||
HapiProperties.forceReload();
|
||||
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "DSTU2");
|
||||
HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr2");
|
||||
ourCtx = FhirContext.forDstu2();
|
||||
}
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Test
|
||||
public void testCreateAndRead() {
|
||||
ourLog.info("Base URL is: " + HapiProperties.getServerAddress());
|
||||
void testCreateAndRead() {
|
||||
|
||||
String methodName = "testCreateResourceConditional";
|
||||
|
||||
Patient pt = new Patient();
|
||||
pt.addName().addFamily(methodName);
|
||||
IIdType id = ourClient.create().resource(pt).execute().getId();
|
||||
|
||||
Patient pt2 = ourClient.read().resource(Patient.class).withId(id).execute();
|
||||
assertEquals(methodName, pt2.getName().get(0).getFamily().get(0).getValue());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
String path = Paths.get("").toAbsolutePath().toString();
|
||||
|
||||
ourLog.info("Project base path is: {}", path);
|
||||
|
||||
ourServer = new Server(0);
|
||||
|
||||
WebAppContext webAppContext = new WebAppContext();
|
||||
webAppContext.setContextPath("/hapi-fhir-jpaserver");
|
||||
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
|
||||
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter");
|
||||
webAppContext.setParentLoaderPriority(true);
|
||||
|
||||
ourServer.setHandler(webAppContext);
|
||||
ourServer.start();
|
||||
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
ourCtx = FhirContext.forDstu2();
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
String ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver/fhir/";
|
||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
}
|
||||
|
||||
public static void main(String[] theArgs) throws Exception {
|
||||
ourPort = 8080;
|
||||
beforeClass();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,6 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
@@ -18,39 +15,44 @@ import org.hl7.fhir.dstu3.model.Observation;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static ca.uhn.fhir.util.TestUtil.waitForSize;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
||||
{
|
||||
"spring.batch.job.enabled=false",
|
||||
"spring.profiles.active=dstu3",
|
||||
"spring.datasource.url=jdbc:h2:mem:dbr3",
|
||||
"hapi.fhir.subscription.websocket_enabled=true",
|
||||
"hapi.fhir.allow_external_references=true",
|
||||
"hapi.fhir.allow_placeholder_references=true",
|
||||
})
|
||||
|
||||
|
||||
public class ExampleServerDstu3IT {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu3IT.class);
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
||||
private IGenericClient ourClient;
|
||||
private FhirContext ourCtx;
|
||||
|
||||
static {
|
||||
HapiProperties.forceReload();
|
||||
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "DSTU3");
|
||||
HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr3");
|
||||
HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true");
|
||||
HapiProperties.setProperty(HapiProperties.ALLOW_EXTERNAL_REFERENCES, "true");
|
||||
HapiProperties.setProperty(HapiProperties.ALLOW_PLACEHOLDER_REFERENCES, "true");
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
}
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
@Test
|
||||
public void testCreateAndRead() {
|
||||
ourLog.info("Base URL is: " + HapiProperties.getServerAddress());
|
||||
|
||||
String methodName = "testCreateResourceConditional";
|
||||
|
||||
Patient pt = new Patient();
|
||||
@@ -90,7 +92,7 @@ public class ExampleServerDstu3IT {
|
||||
SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON);
|
||||
|
||||
myWebSocketClient.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + "/hapi-fhir-jpaserver/websocket");
|
||||
URI echoUri = new URI("ws://localhost:" + port + "/websocket");
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request);
|
||||
@@ -119,39 +121,15 @@ public class ExampleServerDstu3IT {
|
||||
ourClient.delete().resourceById(mySubscriptionId).execute();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
String path = Paths.get("").toAbsolutePath().toString();
|
||||
|
||||
ourLog.info("Project base path is: {}", path);
|
||||
|
||||
ourServer = new Server(0);
|
||||
|
||||
WebAppContext webAppContext = new WebAppContext();
|
||||
webAppContext.setContextPath("/hapi-fhir-jpaserver");
|
||||
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
|
||||
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter");
|
||||
webAppContext.setParentLoaderPriority(true);
|
||||
|
||||
ourServer.setHandler(webAppContext);
|
||||
ourServer.start();
|
||||
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
ourCtx = FhirContext.forDstu3();
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
String ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver/fhir/";
|
||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
}
|
||||
|
||||
public static void main(String[] theArgs) throws Exception {
|
||||
ourPort = 8080;
|
||||
beforeClass();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,26 +7,20 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import ca.uhn.fhir.util.BundleUtil;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.hl7.fhir.r4.model.Person;
|
||||
import org.hl7.fhir.r4.model.Reference;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
@@ -38,26 +32,30 @@ import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
||||
{
|
||||
"spring.batch.job.enabled=false",
|
||||
"spring.profiles.active=r4",
|
||||
"spring.datasource.url=jdbc:h2:mem:dbr4",
|
||||
"hapi.fhir.subscription.websocket_enabled=true",
|
||||
"hapi.fhir.empi_enabled=true",
|
||||
//Override is currently required when using Empi as the construction of the Empi beans are ambiguous as they are constructed multiple places. This is evident when running in a spring boot environment
|
||||
"spring.main.allow-bean-definition-overriding=true"
|
||||
})
|
||||
public class ExampleServerR4IT {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerR4IT.class);
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
||||
private IGenericClient ourClient;
|
||||
private FhirContext ourCtx;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
static {
|
||||
HapiProperties.forceReload();
|
||||
HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr4");
|
||||
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R4");
|
||||
HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true");
|
||||
HapiProperties.setProperty(HapiProperties.EMPI_ENABLED, "true");
|
||||
ourCtx = FhirContext.forR4();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndRead() {
|
||||
ourLog.info("Base URL is: " + HapiProperties.getServerAddress());
|
||||
void testCreateAndRead() {
|
||||
|
||||
String methodName = "testCreateResourceConditional";
|
||||
|
||||
Patient pt = new Patient();
|
||||
@@ -121,7 +119,7 @@ public class ExampleServerR4IT {
|
||||
SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON);
|
||||
|
||||
myWebSocketClient.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + "/hapi-fhir-jpaserver/websocket");
|
||||
URI echoUri = new URI("ws://localhost:" + port + "/websocket");
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request);
|
||||
@@ -154,42 +152,15 @@ public class ExampleServerR4IT {
|
||||
return ourClient.search().forResource(Subscription.class).where(Subscription.STATUS.exactly().code("active")).cacheControl(new CacheControlDirective().setNoCache(true)).returnBundle(Bundle.class).execute().getEntry().size();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
String path = Paths.get("").toAbsolutePath().toString();
|
||||
|
||||
ourLog.info("Project base path is: {}", path);
|
||||
|
||||
ourServer = new Server(0);
|
||||
|
||||
WebAppContext webAppContext = new WebAppContext();
|
||||
webAppContext.setContextPath("/hapi-fhir-jpaserver");
|
||||
webAppContext.setDisplayName("HAPI FHIR");
|
||||
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
|
||||
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter");
|
||||
webAppContext.setParentLoaderPriority(true);
|
||||
|
||||
ourServer.setHandler(webAppContext);
|
||||
ourServer.start();
|
||||
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
ourCtx = FhirContext.forR4();
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
String ourServerBase = HapiProperties.getServerAddress();
|
||||
ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver/fhir/";
|
||||
|
||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
}
|
||||
|
||||
public static void main(String[] theArgs) throws Exception {
|
||||
ourPort = 8080;
|
||||
beforeClass();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import static ca.uhn.fhir.util.TestUtil.waitForSize;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
@@ -7,9 +11,9 @@ import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import java.net.URI;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import org.eclipse.jetty.websocket.api.Session;
|
||||
import org.eclipse.jetty.websocket.client.ClientUpgradeRequest;
|
||||
import org.eclipse.jetty.websocket.client.WebSocketClient;
|
||||
@@ -20,38 +24,34 @@ import org.hl7.fhir.r5.model.Observation;
|
||||
import org.hl7.fhir.r5.model.Patient;
|
||||
import org.hl7.fhir.r5.model.Subscription;
|
||||
import org.hl7.fhir.r5.model.SubscriptionTopic;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import java.net.URI;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static ca.uhn.fhir.util.TestUtil.waitForSize;
|
||||
import static org.awaitility.Awaitility.await;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
||||
{
|
||||
"spring.batch.job.enabled=false",
|
||||
"spring.profiles.active=r5",
|
||||
"spring.datasource.url=jdbc:h2:mem:dbr5",
|
||||
"hapi.fhir.subscription.websocket_enabled=true"
|
||||
})
|
||||
public class ExampleServerR5IT {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerR5IT.class);
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
||||
private IGenericClient ourClient;
|
||||
private FhirContext ourCtx;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
static {
|
||||
HapiProperties.forceReload();
|
||||
HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr5");
|
||||
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R5");
|
||||
HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true");
|
||||
ourCtx = FhirContext.forR5();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndRead() {
|
||||
ourLog.info("Base URL is: " + HapiProperties.getServerAddress());
|
||||
|
||||
String methodName = "testCreateResourceConditional";
|
||||
|
||||
Patient pt = new Patient();
|
||||
@@ -97,7 +97,7 @@ public class ExampleServerR5IT {
|
||||
SocketImplementation mySocketImplementation = new SocketImplementation(mySubscriptionId.getIdPart(), EncodingEnum.JSON);
|
||||
|
||||
myWebSocketClient.start();
|
||||
URI echoUri = new URI("ws://localhost:" + ourPort + "/hapi-fhir-jpaserver/websocket");
|
||||
URI echoUri = new URI("ws://localhost:" + port + "/websocket");
|
||||
ClientUpgradeRequest request = new ClientUpgradeRequest();
|
||||
ourLog.info("Connecting to : {}", echoUri);
|
||||
Future<Session> connection = myWebSocketClient.connect(mySocketImplementation, echoUri, request);
|
||||
@@ -123,41 +123,14 @@ public class ExampleServerR5IT {
|
||||
ourClient.delete().resourceById(mySubscriptionId).execute();
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
String path = Paths.get("").toAbsolutePath().toString();
|
||||
|
||||
ourLog.info("Project base path is: {}", path);
|
||||
|
||||
ourServer = new Server(0);
|
||||
|
||||
WebAppContext webAppContext = new WebAppContext();
|
||||
webAppContext.setContextPath("/hapi-fhir-jpaserver");
|
||||
webAppContext.setDisplayName("HAPI FHIR");
|
||||
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
|
||||
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter");
|
||||
webAppContext.setParentLoaderPriority(true);
|
||||
|
||||
ourServer.setHandler(webAppContext);
|
||||
ourServer.start();
|
||||
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
ourCtx = FhirContext.forR5();
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
String ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver/fhir/";
|
||||
|
||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
}
|
||||
|
||||
public static void main(String[] theArgs) throws Exception {
|
||||
ourPort = 8080;
|
||||
beforeClass();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,44 +7,42 @@ import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.client.interceptor.UrlTenantSelectionInterceptor;
|
||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||
import org.eclipse.jetty.server.Server;
|
||||
import org.eclipse.jetty.webapp.WebAppContext;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.CodeType;
|
||||
import org.hl7.fhir.r4.model.IntegerType;
|
||||
import org.hl7.fhir.r4.model.Parameters;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.boot.web.server.LocalServerPort;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT, classes = Application.class, properties =
|
||||
{
|
||||
"spring.batch.job.enabled=false",
|
||||
"spring.profiles.active=r4",
|
||||
"spring.datasource.url=jdbc:h2:mem:dbr4-mt",
|
||||
"hapi.fhir.subscription.websocket_enabled=true",
|
||||
"hapi.fhir.partitioning.partitioning_include_in_search_hashes=false"
|
||||
|
||||
})
|
||||
public class MultitenantServerR4IT {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(MultitenantServerR4IT.class);
|
||||
private static IGenericClient ourClient;
|
||||
private static FhirContext ourCtx;
|
||||
private static int ourPort;
|
||||
private static Server ourServer;
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleServerDstu2IT.class);
|
||||
private IGenericClient ourClient;
|
||||
private FhirContext ourCtx;
|
||||
|
||||
@LocalServerPort
|
||||
private int port;
|
||||
|
||||
private static UrlTenantSelectionInterceptor ourClientTenantInterceptor;
|
||||
|
||||
static {
|
||||
HapiProperties.forceReload();
|
||||
HapiProperties.setProperty(HapiProperties.DATASOURCE_URL, "jdbc:h2:mem:dbr4-mt");
|
||||
HapiProperties.setProperty(HapiProperties.FHIR_VERSION, "R4");
|
||||
HapiProperties.setProperty(HapiProperties.SUBSCRIPTION_WEBSOCKET_ENABLED, "true");
|
||||
HapiProperties.setProperty(HapiProperties.PARTITIONING_ENABLED, "true");
|
||||
HapiProperties.setProperty(HapiProperties.PARTITIONING_MULTITENANCY_ENABLED, "true");
|
||||
ourCtx = FhirContext.forR4();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateAndReadInTenantA() {
|
||||
ourLog.info("Base URL is: " + HapiProperties.getServerAddress());
|
||||
|
||||
|
||||
// Create tenant A
|
||||
ourClientTenantInterceptor.setTenantId("DEFAULT");
|
||||
@@ -70,7 +68,7 @@ public class MultitenantServerR4IT {
|
||||
|
||||
@Test
|
||||
public void testCreateAndReadInTenantB() {
|
||||
ourLog.info("Base URL is: " + HapiProperties.getServerAddress());
|
||||
|
||||
|
||||
// Create tenant A
|
||||
ourClientTenantInterceptor.setTenantId("DEFAULT");
|
||||
@@ -94,45 +92,16 @@ public class MultitenantServerR4IT {
|
||||
assertEquals("Family B", pt2.getName().get(0).getFamily());
|
||||
}
|
||||
|
||||
@AfterAll
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
}
|
||||
|
||||
@BeforeAll
|
||||
public static void beforeClass() throws Exception {
|
||||
String path = Paths.get("").toAbsolutePath().toString();
|
||||
|
||||
ourLog.info("Project base path is: {}", path);
|
||||
|
||||
ourServer = new Server(0);
|
||||
|
||||
WebAppContext webAppContext = new WebAppContext();
|
||||
webAppContext.setContextPath("/hapi-fhir-jpaserver");
|
||||
webAppContext.setDisplayName("HAPI FHIR");
|
||||
webAppContext.setDescriptor(path + "/src/main/webapp/WEB-INF/web.xml");
|
||||
webAppContext.setResourceBase(path + "/target/hapi-fhir-jpaserver-starter");
|
||||
webAppContext.setParentLoaderPriority(true);
|
||||
|
||||
ourServer.setHandler(webAppContext);
|
||||
ourServer.start();
|
||||
|
||||
ourPort = JettyUtil.getPortForStartedServer(ourServer);
|
||||
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
String ourServerBase = HapiProperties.getServerAddress();
|
||||
ourServerBase = "http://localhost:" + ourPort + "/hapi-fhir-jpaserver/fhir/";
|
||||
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
@BeforeEach
|
||||
void beforeEach() {
|
||||
|
||||
ourClientTenantInterceptor = new UrlTenantSelectionInterceptor();
|
||||
ourCtx = FhirContext.forR4();
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
String ourServerBase = "http://localhost:" + port + "/fhir/";
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
ourClient.registerInterceptor(ourClientTenantInterceptor);
|
||||
}
|
||||
|
||||
public static void main(String[] theArgs) throws Exception {
|
||||
ourPort = 8080;
|
||||
beforeClass();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,36 +0,0 @@
|
||||
package ca.uhn.fhir.jpa.starter;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.ServerSocket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Provides server ports
|
||||
*/
|
||||
public class RandomServerPortProvider {
|
||||
|
||||
private static List<Integer> ourPorts = new ArrayList<Integer>();
|
||||
|
||||
public 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 e) {
|
||||
throw new Error(e);
|
||||
} catch (InterruptedException e) {
|
||||
throw new Error(e);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<Integer> list() {
|
||||
return ourPorts;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
104
src/test/resources/application-integrationtest.yaml
Normal file
104
src/test/resources/application-integrationtest.yaml
Normal file
@@ -0,0 +1,104 @@
|
||||
spring:
|
||||
datasource:
|
||||
url: 'jdbc:h2:file:./target/database/h2'
|
||||
username: sa
|
||||
password: null
|
||||
driverClassName: org.h2.Driver
|
||||
max-active: 15
|
||||
profiles:
|
||||
### This is the FHIR version. Choose between, dstu2, dstu3, r4 or r5
|
||||
active: r4
|
||||
|
||||
hapi:
|
||||
fhir:
|
||||
#supported_resource_types:
|
||||
# - Patient
|
||||
# - Observation
|
||||
# allow_cascading_deletes: true
|
||||
# allow_contains_searches: true
|
||||
# allow_external_references: true
|
||||
# allow_multiple_delete: true
|
||||
# allow_override_default_search_params: true
|
||||
# allow_placeholder_references: true
|
||||
# auto_create_placeholder_reference_targets: false
|
||||
# default_encoding: JSON
|
||||
# default_pretty_print: true
|
||||
# default_page_size: 20
|
||||
# enable_index_missing_fields: false
|
||||
# enforce_referential_integrity_on_delete: false
|
||||
# enforce_referential_integrity_on_write: false
|
||||
# etag_support_enabled: true
|
||||
# expunge_enabled: true
|
||||
# daoconfig_client_id_strategy: null
|
||||
# fhirpath_interceptor_enabled: false
|
||||
# filter_search_enabled: true
|
||||
# graphql_enabled: true
|
||||
#partitioning:
|
||||
# cross_partition_reference_mode: true
|
||||
# multitenancy_enabled: true
|
||||
# partitioning_include_in_search_hashes: true
|
||||
#cors:
|
||||
# allow_Credentials: true
|
||||
# Supports multiple, comma separated allowed origin entries
|
||||
# cors.allowed_origin=http://localhost:8080,https://localhost:8080,https://fhirtest.uhn.ca
|
||||
# allowed_origin:
|
||||
# - '*'
|
||||
|
||||
# logger:
|
||||
# error_format: 'ERROR - ${requestVerb} ${requestUrl}'
|
||||
# format: >-
|
||||
# Path[${servletPath}] Source[${requestHeader.x-forwarded-for}]
|
||||
# Operation[${operationType} ${operationName} ${idOrResourceName}]
|
||||
# UA[${requestHeader.user-agent}] Params[${requestParameters}]
|
||||
# ResponseEncoding[${responseEncodingNoDefault}]
|
||||
# log_exceptions: true
|
||||
# name: fhirtest.access
|
||||
# max_binary_size: 104857600
|
||||
# max_page_size: 200
|
||||
# retain_cached_searches_mins: 60
|
||||
# reuse_cached_search_results_millis: 60000
|
||||
tester:
|
||||
-
|
||||
id: home
|
||||
name: Local Tester
|
||||
server_address: 'http://localhost:8080/hapi-fhir-jpaserver/fhir'
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
-
|
||||
id: global
|
||||
name: Global Tester
|
||||
server_address: "http://hapi.fhir.org/baseR4"
|
||||
refuse_to_fetch_third_party_urls: false
|
||||
fhir_version: R4
|
||||
# validation:
|
||||
# requests_enabled: true
|
||||
# responses_enabled: true
|
||||
# binary_storage_enabled: true
|
||||
# bulk_export_enabled: true
|
||||
# partitioning_multitenancy_enabled:
|
||||
# subscription:
|
||||
# resthook_enabled: false
|
||||
# websocket_enabled: false
|
||||
# email:
|
||||
# from: some@test.com
|
||||
# host: google.com
|
||||
# port:
|
||||
# username:
|
||||
# password:
|
||||
# auth:
|
||||
# startTlsEnable:
|
||||
# startTlsRequired:
|
||||
# quitWait:
|
||||
|
||||
|
||||
#
|
||||
#elasticsearch:
|
||||
# debug:
|
||||
# pretty_print_json_log: false
|
||||
# refresh_after_write: false
|
||||
# enabled: false
|
||||
# password: SomePassword
|
||||
# required_index_status: YELLOW
|
||||
# rest_url: 'http://localhost:9200'
|
||||
# schema_management_strategy: CREATE
|
||||
# username: SomeUsername
|
||||
Reference in New Issue
Block a user