API improvements for MegaScale (#4112)
* Start work on sharded DB * Work on migrating * Work * Ongoing work * Ongoing work * Work * Work * Ongoing work * Work * Work * Test fix * Test fix * Work * Compile fix * Test cleanup * Test fix * Resolve fixmes * Resolve fixme * Resolve compile errors * Compile fix * Fixes * Work * Add note for later * Test fix * Test fixes * Build fix * Test fixes * Fixes * Test fixes * Test fixes * Test fixes * Test fix * Fixes * Fixes * Remove dead code in pom * More test cleanup * Docs fix * Changes * Fix * Fixes * Resolve merge conflicts * Build update * Merge build fixes * Version bump * Address review comments * Review comments * Review comments * Test fixes * Test fix * Cleanup
This commit is contained in:
parent
155b579093
commit
0d5f8da93f
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
@ -111,6 +111,7 @@
|
||||||
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
|
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
|
||||||
<ignoredResourcePattern>.*\.html$</ignoredResourcePattern>
|
<ignoredResourcePattern>.*\.html$</ignoredResourcePattern>
|
||||||
<ignoredResourcePattern>schemaorg_apache_xmlbeans.*</ignoredResourcePattern>
|
<ignoredResourcePattern>schemaorg_apache_xmlbeans.*</ignoredResourcePattern>
|
||||||
|
<ignoredResource>classpath.index</ignoredResource>
|
||||||
<ignoredResource>javac.bat</ignoredResource>
|
<ignoredResource>javac.bat</ignoredResource>
|
||||||
<ignoredResource>about.html</ignoredResource>
|
<ignoredResource>about.html</ignoredResource>
|
||||||
<ignoredResource>changelog.xml</ignoredResource>
|
<ignoredResource>changelog.xml</ignoredResource>
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -1898,6 +1898,8 @@ public enum Pointcut implements IPointcut {
|
||||||
* <p>
|
* <p>
|
||||||
* Hooks must return an instance of <code>ca.uhn.fhir.interceptor.model.RequestPartitionId</code>.
|
* Hooks must return an instance of <code>ca.uhn.fhir.interceptor.model.RequestPartitionId</code>.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @see #STORAGE_PARTITION_IDENTIFY_ANY For an alternative that is not read/write specific
|
||||||
*/
|
*/
|
||||||
STORAGE_PARTITION_IDENTIFY_CREATE(
|
STORAGE_PARTITION_IDENTIFY_CREATE(
|
||||||
// Return type
|
// Return type
|
||||||
|
@ -1938,6 +1940,8 @@ public enum Pointcut implements IPointcut {
|
||||||
* <p>
|
* <p>
|
||||||
* Hooks must return an instance of <code>ca.uhn.fhir.interceptor.model.RequestPartitionId</code>.
|
* Hooks must return an instance of <code>ca.uhn.fhir.interceptor.model.RequestPartitionId</code>.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @see #STORAGE_PARTITION_IDENTIFY_ANY For an alternative that is not read/write specific
|
||||||
*/
|
*/
|
||||||
STORAGE_PARTITION_IDENTIFY_READ(
|
STORAGE_PARTITION_IDENTIFY_READ(
|
||||||
// Return type
|
// Return type
|
||||||
|
@ -1948,6 +1952,95 @@ public enum Pointcut implements IPointcut {
|
||||||
"ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails"
|
"ca.uhn.fhir.interceptor.model.ReadPartitionIdRequestDetails"
|
||||||
),
|
),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Storage Hook:</b>
|
||||||
|
* Invoked before FHIR operations to request the identification of the partition ID to be associated with the
|
||||||
|
* request being made.
|
||||||
|
* <p>
|
||||||
|
* This hook is an alternative to {@link #STORAGE_PARTITION_IDENTIFY_READ} and {@link #STORAGE_PARTITION_IDENTIFY_CREATE}
|
||||||
|
* and can be used in cases where a partition interceptor does not need knowledge of the specific resources being
|
||||||
|
* accessed/read/written in order to determine the appropriate partition.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* This hook will only be called if
|
||||||
|
* partitioning is enabled in the JPA server.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Hooks may accept the following parameters:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* ca.uhn.fhir.rest.api.server.RequestDetails - A bean containing details about the request that is about to be processed, including details such as the
|
||||||
|
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||||
|
* pulled out of the servlet request. Note that the bean
|
||||||
|
* properties are not all guaranteed to be populated, depending on how early during processing the
|
||||||
|
* exception occurred.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* ca.uhn.fhir.rest.server.servlet.ServletRequestDetails - A bean containing details about the request that is about to be processed, including details such as the
|
||||||
|
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||||
|
* pulled out of the servlet request. This parameter is identical to the RequestDetails parameter above but will
|
||||||
|
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* Hooks must return an instance of <code>ca.uhn.fhir.interceptor.model.RequestPartitionId</code>.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @see #STORAGE_PARTITION_IDENTIFY_READ
|
||||||
|
* @see #STORAGE_PARTITION_IDENTIFY_CREATE
|
||||||
|
*/
|
||||||
|
STORAGE_PARTITION_IDENTIFY_ANY(
|
||||||
|
// Return type
|
||||||
|
"ca.uhn.fhir.interceptor.model.RequestPartitionId",
|
||||||
|
// Params
|
||||||
|
"ca.uhn.fhir.rest.api.server.RequestDetails",
|
||||||
|
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"
|
||||||
|
),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <b>Storage Hook:</b>
|
||||||
|
* Invoked when a partition has been created, typically meaning the <code>$partition-management-create-partition</code>
|
||||||
|
* operation has been invoked.
|
||||||
|
* <p>
|
||||||
|
* This hook will only be called if
|
||||||
|
* partitioning is enabled in the JPA server.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* Hooks may accept the following parameters:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>
|
||||||
|
* ca.uhn.fhir.interceptor.model.RequestPartitionId - The partition ID that was selected
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* ca.uhn.fhir.rest.api.server.RequestDetails - A bean containing details about the request that is about to be processed, including details such as the
|
||||||
|
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||||
|
* pulled out of the servlet request. Note that the bean
|
||||||
|
* properties are not all guaranteed to be populated, depending on how early during processing the
|
||||||
|
* exception occurred.
|
||||||
|
* </li>
|
||||||
|
* <li>
|
||||||
|
* ca.uhn.fhir.rest.server.servlet.ServletRequestDetails - A bean containing details about the request that is about to be processed, including details such as the
|
||||||
|
* resource type and logical ID (if any) and other FHIR-specific aspects of the request which have been
|
||||||
|
* pulled out of the servlet request. This parameter is identical to the RequestDetails parameter above but will
|
||||||
|
* only be populated when operating in a RestfulServer implementation. It is provided as a convenience.
|
||||||
|
* </li>
|
||||||
|
* </ul>
|
||||||
|
* <p>
|
||||||
|
* Hooks must return void.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
STORAGE_PARTITION_CREATED(
|
||||||
|
// Return type
|
||||||
|
void.class,
|
||||||
|
// Params
|
||||||
|
"ca.uhn.fhir.interceptor.model.RequestPartitionId",
|
||||||
|
"ca.uhn.fhir.rest.api.server.RequestDetails",
|
||||||
|
"ca.uhn.fhir.rest.server.servlet.ServletRequestDetails"
|
||||||
|
),
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <b>Storage Hook:</b>
|
* <b>Storage Hook:</b>
|
||||||
* Invoked before any partition aware FHIR operation, when the selected partition has been identified (ie. after the
|
* Invoked before any partition aware FHIR operation, when the selected partition has been identified (ie. after the
|
||||||
|
|
|
@ -60,6 +60,7 @@ import java.util.concurrent.atomic.AtomicInteger;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
// TODO: JA maybe add an enummap for pointcuts registered?
|
||||||
public abstract class BaseInterceptorService<POINTCUT extends IPointcut> implements IBaseInterceptorService<POINTCUT>, IBaseInterceptorBroadcaster<POINTCUT> {
|
public abstract class BaseInterceptorService<POINTCUT extends IPointcut> implements IBaseInterceptorService<POINTCUT>, IBaseInterceptorBroadcaster<POINTCUT> {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseInterceptorService.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(BaseInterceptorService.class);
|
||||||
private final List<Object> myInterceptors = new ArrayList<>();
|
private final List<Object> myInterceptors = new ArrayList<>();
|
||||||
|
|
|
@ -4,14 +4,14 @@
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-bom</artifactId>
|
<artifactId>hapi-fhir-bom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<packaging>pom</packaging>
|
<packaging>pom</packaging>
|
||||||
<name>HAPI FHIR BOM</name>
|
<name>HAPI FHIR BOM</name>
|
||||||
|
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir-cli</artifactId>
|
<artifactId>hapi-fhir-cli</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../../hapi-deployable-pom</relativePath>
|
<relativePath>../../hapi-deployable-pom</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-fhir</artifactId>
|
<artifactId>hapi-fhir</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../pom.xml</relativePath>
|
<relativePath>../pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@ HAPI-FHIR 6.0.0 has begun the process of replacing Spring Batch with a custom ba
|
||||||
|
|
||||||
A HAPI-FHIR batch job definition consists of a job name, version, parameter json input type, and a chain of job steps. Each step of the chain declares the json output type it produces, which will be the input type for the following step. The final step in the chain does not declare an output type as the final step will typically do the work of the job, e.g. reindex resources, export data to disk, etc.
|
A HAPI-FHIR batch job definition consists of a job name, version, parameter json input type, and a chain of job steps. Each step of the chain declares the json output type it produces, which will be the input type for the following step. The final step in the chain does not declare an output type as the final step will typically do the work of the job, e.g. reindex resources, export data to disk, etc.
|
||||||
|
|
||||||
<a href="/hapi-fhir/docs/images/job-definition.svg"/>
|
<img src="/hapi-fhir/docs/images/job-definition.svg"/>
|
||||||
|
|
||||||
### Submitting a Job
|
### Submitting a Job
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
<modelVersion>4.0.0</modelVersion>
|
<modelVersion>4.0.0</modelVersion>
|
||||||
|
|
|
@ -20,75 +20,12 @@ package ca.uhn.fhir.jpa.util;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
|
||||||
import com.google.common.collect.ImmutableSet;
|
|
||||||
import com.google.common.collect.Lists;
|
|
||||||
import com.google.common.collect.Sets;
|
|
||||||
import com.google.common.reflect.ClassPath;
|
|
||||||
import com.google.common.reflect.ClassPath.ClassInfo;
|
|
||||||
import org.apache.commons.io.IOUtils;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
|
||||||
import org.hibernate.annotations.Subselect;
|
|
||||||
import org.hibernate.validator.constraints.Length;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.InstantType;
|
import org.hl7.fhir.r4.model.InstantType;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
|
||||||
import javax.persistence.Embeddable;
|
|
||||||
import javax.persistence.Embedded;
|
|
||||||
import javax.persistence.EmbeddedId;
|
|
||||||
import javax.persistence.Entity;
|
|
||||||
import javax.persistence.ForeignKey;
|
|
||||||
import javax.persistence.GeneratedValue;
|
|
||||||
import javax.persistence.Index;
|
|
||||||
import javax.persistence.JoinColumn;
|
|
||||||
import javax.persistence.Lob;
|
|
||||||
import javax.persistence.OneToMany;
|
|
||||||
import javax.persistence.OneToOne;
|
|
||||||
import javax.persistence.SequenceGenerator;
|
|
||||||
import javax.persistence.Table;
|
|
||||||
import javax.persistence.Transient;
|
|
||||||
import javax.persistence.UniqueConstraint;
|
|
||||||
import javax.validation.constraints.Size;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.lang.reflect.AnnotatedElement;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.lang.reflect.Modifier;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static com.google.common.base.Ascii.toUpperCase;
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
public class TestUtil {
|
public class TestUtil {
|
||||||
public static final int MAX_COL_LENGTH = 4000;
|
|
||||||
private static final int MAX_LENGTH = 30;
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestUtil.class);
|
|
||||||
private static Set<String> ourReservedWords;
|
|
||||||
|
|
||||||
|
|
||||||
// Exceptions set because H2 sets indexes for FKs automatically so this index had to be called as the target FK field
|
|
||||||
// it is indexing to avoid SchemaMigrationTest to complain about the extra index (which doesn't exist in H2)
|
|
||||||
private static final Set<String> duplicateNameValidationExceptionList = Sets.newHashSet(
|
|
||||||
"FK_CONCEPTPROP_CONCEPT",
|
|
||||||
"FK_CONCEPTDESIG_CONCEPT",
|
|
||||||
"FK_TERM_CONCEPTPC_CHILD",
|
|
||||||
"FK_TERM_CONCEPTPC_PARENT",
|
|
||||||
"FK_TRM_VALUESET_CONCEPT_PID",
|
|
||||||
"FK_SEARCHINC_SEARCH"
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* non instantiable
|
* non instantiable
|
||||||
|
@ -97,288 +34,6 @@ public class TestUtil {
|
||||||
super();
|
super();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* This is really only useful for unit tests, do not call otherwise
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("UnstableApiUsage")
|
|
||||||
public static void scanEntities(String packageName) throws IOException, ClassNotFoundException {
|
|
||||||
|
|
||||||
try (InputStream is = TestUtil.class.getResourceAsStream("/mysql-reserved-words.txt")) {
|
|
||||||
String contents = IOUtils.toString(is, Constants.CHARSET_UTF8);
|
|
||||||
String[] words = contents.split("\\n");
|
|
||||||
ourReservedWords = Arrays.stream(words)
|
|
||||||
.filter(t -> isNotBlank(t))
|
|
||||||
.map(t -> toUpperCase(t))
|
|
||||||
.collect(Collectors.toSet());
|
|
||||||
}
|
|
||||||
|
|
||||||
ImmutableSet<ClassInfo> classes = ClassPath.from(TestUtil.class.getClassLoader()).getTopLevelClassesRecursive(packageName);
|
|
||||||
Set<String> names = new HashSet<String>();
|
|
||||||
|
|
||||||
if (classes.size() <= 1) {
|
|
||||||
throw new InternalErrorException(Msg.code(1623) + "Found no classes");
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ClassInfo classInfo : classes) {
|
|
||||||
Class<?> clazz = Class.forName(classInfo.getName());
|
|
||||||
Entity entity = clazz.getAnnotation(Entity.class);
|
|
||||||
Embeddable embeddable = clazz.getAnnotation(Embeddable.class);
|
|
||||||
if (entity == null && embeddable == null) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
scanClass(names, clazz, false);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void scanClass(Set<String> theNames, Class<?> theClazz, boolean theIsSuperClass) {
|
|
||||||
Map<String, Integer> columnNameToLength = new HashMap<>();
|
|
||||||
|
|
||||||
scanClassOrSuperclass(theNames, theClazz, theIsSuperClass, columnNameToLength);
|
|
||||||
|
|
||||||
Table table = theClazz.getAnnotation(Table.class);
|
|
||||||
if (table != null) {
|
|
||||||
|
|
||||||
// This is the length for MySQL per https://dev.mysql.com/doc/refman/8.0/en/innodb-limits.html
|
|
||||||
// No idea why 3072.. what a weird limit but I'm sure they have their reason.
|
|
||||||
int maxIndexLength = 3072;
|
|
||||||
|
|
||||||
for (UniqueConstraint nextIndex : table.uniqueConstraints()) {
|
|
||||||
int indexLength = calculateIndexLength(nextIndex.columnNames(), columnNameToLength, theClazz, nextIndex.name());
|
|
||||||
if (indexLength > maxIndexLength) {
|
|
||||||
throw new IllegalStateException(Msg.code(1624) + "Index '" + nextIndex.name() + "' is too long. Length is " + indexLength + " and must not exceed " + maxIndexLength + " which is the maximum MySQL length");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static int calculateIndexLength(String[] theColumnNames, Map<String, Integer> theColumnNameToLength, Class<?> theClazz, String theIndexName) {
|
|
||||||
int retVal = 0;
|
|
||||||
for (String nextName : theColumnNames) {
|
|
||||||
Integer nextLength = theColumnNameToLength.get(nextName);
|
|
||||||
if (nextLength == null) {
|
|
||||||
throw new IllegalStateException(Msg.code(1625) + "Index '" + theIndexName + "' references unknown column: " + nextName);
|
|
||||||
}
|
|
||||||
retVal += nextLength;
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void scanClassOrSuperclass(Set<String> theNames, Class<?> theClazz, boolean theIsSuperClass, Map<String, Integer> columnNameToLength) {
|
|
||||||
ourLog.info("Scanning: {}", theClazz.getSimpleName());
|
|
||||||
|
|
||||||
Subselect subselect = theClazz.getAnnotation(Subselect.class);
|
|
||||||
boolean isView = (subselect != null);
|
|
||||||
|
|
||||||
scan(theClazz, theNames, theIsSuperClass, isView);
|
|
||||||
|
|
||||||
for (Field nextField : theClazz.getDeclaredFields()) {
|
|
||||||
if (Modifier.isStatic(nextField.getModifiers())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
ourLog.info(" * Scanning field: {}", nextField.getName());
|
|
||||||
scan(nextField, theNames, theIsSuperClass, isView);
|
|
||||||
|
|
||||||
Lob lobClass = nextField.getAnnotation(Lob.class);
|
|
||||||
if (lobClass != null) {
|
|
||||||
if (nextField.getType().equals(byte[].class) == false) {
|
|
||||||
//Validate.isTrue(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isTransient = nextField.getAnnotation(Transient.class) != null;
|
|
||||||
if (!isTransient) {
|
|
||||||
boolean hasColumn = nextField.getAnnotation(Column.class) != null;
|
|
||||||
boolean hasJoinColumn = nextField.getAnnotation(JoinColumn.class) != null;
|
|
||||||
boolean hasEmbeddedId = nextField.getAnnotation(EmbeddedId.class) != null;
|
|
||||||
boolean hasEmbedded = nextField.getAnnotation(Embedded.class) != null;
|
|
||||||
OneToMany oneToMany = nextField.getAnnotation(OneToMany.class);
|
|
||||||
OneToOne oneToOne = nextField.getAnnotation(OneToOne.class);
|
|
||||||
boolean isOtherSideOfOneToManyMapping = oneToMany != null && isNotBlank(oneToMany.mappedBy());
|
|
||||||
boolean isOtherSideOfOneToOneMapping = oneToOne != null && isNotBlank(oneToOne.mappedBy());
|
|
||||||
boolean isField = nextField.getAnnotation(org.hibernate.search.mapper.pojo.mapping.definition.annotation.FullTextField.class) != null;
|
|
||||||
isField |= nextField.getAnnotation(org.hibernate.search.mapper.pojo.mapping.definition.annotation.GenericField.class) != null;
|
|
||||||
isField |= nextField.getAnnotation(org.hibernate.search.mapper.pojo.mapping.definition.annotation.ScaledNumberField.class) != null;
|
|
||||||
Validate.isTrue(
|
|
||||||
hasEmbedded ||
|
|
||||||
hasColumn ||
|
|
||||||
hasJoinColumn ||
|
|
||||||
isOtherSideOfOneToManyMapping ||
|
|
||||||
isOtherSideOfOneToOneMapping ||
|
|
||||||
hasEmbeddedId ||
|
|
||||||
isField, "Non-transient has no @Column or @JoinColumn or @EmbeddedId: " + nextField);
|
|
||||||
|
|
||||||
int columnLength = 16;
|
|
||||||
String columnName = null;
|
|
||||||
if (hasColumn) {
|
|
||||||
columnName = nextField.getAnnotation(Column.class).name();
|
|
||||||
columnLength = nextField.getAnnotation(Column.class).length();
|
|
||||||
}
|
|
||||||
if (hasJoinColumn) {
|
|
||||||
columnName = nextField.getAnnotation(JoinColumn.class).name();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (columnName != null) {
|
|
||||||
if (nextField.getType().isAssignableFrom(String.class)) {
|
|
||||||
// MySQL treats each char as the max possible byte count in UTF-8 for its calculations
|
|
||||||
columnLength = columnLength * 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
columnNameToLength.put(columnName, columnLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Class<?> innerClass : theClazz.getDeclaredClasses()) {
|
|
||||||
Embeddable embeddable = innerClass.getAnnotation(Embeddable.class);
|
|
||||||
if (embeddable != null) {
|
|
||||||
scanClassOrSuperclass(theNames, innerClass, false, columnNameToLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (theClazz.getSuperclass().equals(Object.class)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
scanClassOrSuperclass(theNames, theClazz.getSuperclass(), true, columnNameToLength);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void scan(AnnotatedElement theAnnotatedElement, Set<String> theNames, boolean theIsSuperClass, boolean theIsView) {
|
|
||||||
Table table = theAnnotatedElement.getAnnotation(Table.class);
|
|
||||||
if (table != null) {
|
|
||||||
|
|
||||||
// Banned name because we already used it once
|
|
||||||
ArrayList<String> bannedNames = Lists.newArrayList("CDR_USER_2FA", "TRM_VALUESET_CODE");
|
|
||||||
Validate.isTrue(!bannedNames.contains(table.name().toUpperCase()));
|
|
||||||
|
|
||||||
Validate.isTrue(table.name().toUpperCase().equals(table.name()));
|
|
||||||
|
|
||||||
assertNotADuplicateName(table.name(), theNames);
|
|
||||||
for (UniqueConstraint nextConstraint : table.uniqueConstraints()) {
|
|
||||||
assertNotADuplicateName(nextConstraint.name(), theNames);
|
|
||||||
Validate.isTrue(nextConstraint.name().startsWith("IDX_"), nextConstraint.name() + " must start with IDX_");
|
|
||||||
}
|
|
||||||
for (Index nextConstraint : table.indexes()) {
|
|
||||||
assertNotADuplicateName(nextConstraint.name(), theNames);
|
|
||||||
Validate.isTrue(nextConstraint.name().startsWith("IDX_") || nextConstraint.name().startsWith("FK_"),
|
|
||||||
nextConstraint.name() + " must start with IDX_ or FK_ (last one when indexing a FK column)");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
JoinColumn joinColumn = theAnnotatedElement.getAnnotation(JoinColumn.class);
|
|
||||||
if (joinColumn != null) {
|
|
||||||
String columnName = joinColumn.name();
|
|
||||||
validateColumnName(columnName, theAnnotatedElement);
|
|
||||||
|
|
||||||
assertNotADuplicateName(columnName, null);
|
|
||||||
ForeignKey fk = joinColumn.foreignKey();
|
|
||||||
if (theIsSuperClass) {
|
|
||||||
Validate.isTrue(isBlank(fk.name()), "Foreign key on " + theAnnotatedElement + " has a name() and should not as it is a superclass");
|
|
||||||
} else {
|
|
||||||
Validate.notNull(fk);
|
|
||||||
Validate.isTrue(isNotBlank(fk.name()), "Foreign key on " + theAnnotatedElement + " has no name()");
|
|
||||||
|
|
||||||
// Validate FK naming.
|
|
||||||
// temporarily allow two hibernate legacy sp fk names until we fix them
|
|
||||||
List<String> legacySPHibernateFKNames = Arrays.asList(
|
|
||||||
"FKC97MPK37OKWU8QVTCEG2NH9VN", "FKGXSREUTYMMFJUWDSWV3Y887DO");
|
|
||||||
Validate.isTrue(fk.name().startsWith("FK_") || legacySPHibernateFKNames.contains(fk.name()),
|
|
||||||
"Foreign key " + fk.name() + " on " + theAnnotatedElement + " must start with FK_");
|
|
||||||
|
|
||||||
if ( ! duplicateNameValidationExceptionList.contains(fk.name())) {
|
|
||||||
assertNotADuplicateName(fk.name(), theNames);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Column column = theAnnotatedElement.getAnnotation(Column.class);
|
|
||||||
if (column != null) {
|
|
||||||
String columnName = column.name();
|
|
||||||
validateColumnName(columnName, theAnnotatedElement);
|
|
||||||
|
|
||||||
assertNotADuplicateName(columnName, null);
|
|
||||||
Validate.isTrue(column.unique() == false, "Should not use unique attribute on column (use named @UniqueConstraint instead) on " + theAnnotatedElement);
|
|
||||||
|
|
||||||
boolean hasLob = theAnnotatedElement.getAnnotation(Lob.class) != null;
|
|
||||||
Field field = (Field) theAnnotatedElement;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* For string columns, we want to make sure that an explicit max
|
|
||||||
* length is always specified, and that this max is always sensible.
|
|
||||||
* Unfortunately there is no way to differentiate between "explicitly
|
|
||||||
* set to 255" and "just using the default of 255" so we have banned
|
|
||||||
* the exact length of 255.
|
|
||||||
*/
|
|
||||||
if (field.getType().equals(String.class)) {
|
|
||||||
if (!hasLob) {
|
|
||||||
if (!theIsView && column.length() == 255) {
|
|
||||||
throw new IllegalStateException(Msg.code(1626) + "Field does not have an explicit maximum length specified: " + field);
|
|
||||||
}
|
|
||||||
if (column.length() > MAX_COL_LENGTH) {
|
|
||||||
throw new IllegalStateException(Msg.code(1627) + "Field is too long: " + field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Size size = theAnnotatedElement.getAnnotation(Size.class);
|
|
||||||
if (size != null) {
|
|
||||||
if (size.max() > MAX_COL_LENGTH) {
|
|
||||||
throw new IllegalStateException(Msg.code(1628) + "Field is too long: " + field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Length length = theAnnotatedElement.getAnnotation(Length.class);
|
|
||||||
if (length != null) {
|
|
||||||
if (length.max() > MAX_COL_LENGTH) {
|
|
||||||
throw new IllegalStateException(Msg.code(1629) + "Field is too long: " + field);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
GeneratedValue gen = theAnnotatedElement.getAnnotation(GeneratedValue.class);
|
|
||||||
SequenceGenerator sg = theAnnotatedElement.getAnnotation(SequenceGenerator.class);
|
|
||||||
Validate.isTrue((gen != null) == (sg != null));
|
|
||||||
if (gen != null) {
|
|
||||||
assertNotADuplicateName(gen.generator(), theNames);
|
|
||||||
assertNotADuplicateName(sg.name(), null);
|
|
||||||
assertNotADuplicateName(sg.sequenceName(), null);
|
|
||||||
assertEquals(gen.generator(), sg.name());
|
|
||||||
assertEquals(gen.generator(), sg.sequenceName());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void validateColumnName(String theColumnName, AnnotatedElement theElement) {
|
|
||||||
if (!theColumnName.equals(theColumnName.toUpperCase())) {
|
|
||||||
throw new IllegalArgumentException(Msg.code(1630) + "Column name must be all upper case: " + theColumnName + " found on " + theElement);
|
|
||||||
}
|
|
||||||
if (ourReservedWords.contains(theColumnName)) {
|
|
||||||
throw new IllegalArgumentException(Msg.code(1631) + "Column name is a reserved word: " + theColumnName + " found on " + theElement);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertEquals(String theGenerator, String theName) {
|
|
||||||
Validate.isTrue(theGenerator.equals(theName));
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void assertNotADuplicateName(String theName, Set<String> theNames) {
|
|
||||||
if (isBlank(theName)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Validate.isTrue(theName.length() <= MAX_LENGTH, "Identifier \"" + theName + "\" is " + theName.length() + " chars long");
|
|
||||||
if (theNames != null) {
|
|
||||||
Validate.isTrue(theNames.add(theName), "Duplicate name: " + theName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static InstantType getTimestamp(IBaseResource resource) {
|
public static InstantType getTimestamp(IBaseResource resource) {
|
||||||
return new InstantType(new Date(resource.getMeta().getLastUpdated().getTime()));
|
return new InstantType(new Date(resource.getMeta().getLastUpdated().getTime()));
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
@ -417,7 +417,7 @@
|
||||||
<plugins>
|
<plugins>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>de.jpdigital</groupId>
|
<groupId>de.jpdigital</groupId>
|
||||||
<artifactId>hibernate54-ddl-maven-plugin</artifactId>
|
<artifactId>hibernate56-ddl-maven-plugin</artifactId>
|
||||||
<configuration>
|
<configuration>
|
||||||
<dialects>
|
<dialects>
|
||||||
<param>h2</param>
|
<param>h2</param>
|
||||||
|
@ -460,6 +460,11 @@
|
||||||
<artifactId>hapi-fhir-jpaserver-model</artifactId>
|
<artifactId>hapi-fhir-jpaserver-model</artifactId>
|
||||||
<version>${project.version}</version>
|
<version>${project.version}</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-core</artifactId>
|
||||||
|
<version>${hibernate_version}</version>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
|
|
|
@ -35,7 +35,7 @@ import ca.uhn.fhir.jpa.entity.BulkExportJobEntity;
|
||||||
import ca.uhn.fhir.jpa.model.sched.HapiJob;
|
import ca.uhn.fhir.jpa.model.sched.HapiJob;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
import org.hl7.fhir.instance.model.api.IBaseBinary;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
|
@ -39,7 +39,7 @@ import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
import ca.uhn.fhir.jpa.dao.mdm.MdmExpansionCacheSvc;
|
import ca.uhn.fhir.jpa.dao.mdm.MdmExpansionCacheSvc;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.util.QueryChunker;
|
import ca.uhn.fhir.jpa.util.QueryChunker;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ca.uhn.fhir.jpa.api.svc.IIdHelperService;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.util.QueryChunker;
|
import ca.uhn.fhir.jpa.util.QueryChunker;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
|
@ -231,7 +231,7 @@ public class JpaConfig {
|
||||||
@Lazy
|
@Lazy
|
||||||
@Bean
|
@Bean
|
||||||
public ThreadSafeResourceDeleterSvc safeDeleter(DaoRegistry theDaoRegistry, IInterceptorBroadcaster theInterceptorBroadcaster, HapiTransactionService hapiTransactionService) {
|
public ThreadSafeResourceDeleterSvc safeDeleter(DaoRegistry theDaoRegistry, IInterceptorBroadcaster theInterceptorBroadcaster, HapiTransactionService hapiTransactionService) {
|
||||||
return new ThreadSafeResourceDeleterSvc(theDaoRegistry, theInterceptorBroadcaster, hapiTransactionService.getTransactionManager());
|
return new ThreadSafeResourceDeleterSvc(theDaoRegistry, theInterceptorBroadcaster, hapiTransactionService);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Lazy
|
@Lazy
|
||||||
|
@ -661,7 +661,7 @@ public class JpaConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public IIdHelperService idHelperService () {
|
public IIdHelperService idHelperService() {
|
||||||
return new IdHelperService();
|
return new IdHelperService();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -767,7 +767,7 @@ public class JpaConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ISynchronousSearchSvc synchronousSearchSvc(){
|
public ISynchronousSearchSvc synchronousSearchSvc() {
|
||||||
return new SynchronousSearchSvcImpl();
|
return new SynchronousSearchSvcImpl();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -38,8 +38,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
||||||
@EnableTransactionManagement
|
@EnableTransactionManagement
|
||||||
@Import({
|
@Import({
|
||||||
FhirContextDstu2Config.class,
|
FhirContextDstu2Config.class,
|
||||||
GeneratedDaoAndResourceProviderConfigDstu2.class,
|
GeneratedDaoAndResourceProviderConfigDstu2.class
|
||||||
JpaConfig.class
|
|
||||||
})
|
})
|
||||||
public class JpaDstu2Config {
|
public class JpaDstu2Config {
|
||||||
@Bean
|
@Bean
|
||||||
|
|
|
@ -31,6 +31,7 @@ import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceSearchViewDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceTagDao;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||||
|
@ -107,6 +108,8 @@ public class SearchConfig {
|
||||||
private PersistedJpaBundleProviderFactory myPersistedJpaBundleProviderFactory;
|
private PersistedJpaBundleProviderFactory myPersistedJpaBundleProviderFactory;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IRequestPartitionHelperSvc myRequestPartitionHelperService;
|
private IRequestPartitionHelperSvc myRequestPartitionHelperService;
|
||||||
|
@Autowired
|
||||||
|
private HapiTransactionService myHapiTransactionService;
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public ISearchCoordinatorSvc searchCoordinatorSvc() {
|
public ISearchCoordinatorSvc searchCoordinatorSvc() {
|
||||||
|
@ -114,7 +117,7 @@ public class SearchConfig {
|
||||||
myContext,
|
myContext,
|
||||||
myDaoConfig,
|
myDaoConfig,
|
||||||
myInterceptorBroadcaster,
|
myInterceptorBroadcaster,
|
||||||
myManagedTxManager,
|
myHapiTransactionService,
|
||||||
mySearchCacheSvc,
|
mySearchCacheSvc,
|
||||||
mySearchResultCacheSvc,
|
mySearchResultCacheSvc,
|
||||||
myDaoRegistry,
|
myDaoRegistry,
|
||||||
|
@ -160,7 +163,7 @@ public class SearchConfig {
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
public SearchTask createSearchTask(SearchTaskParameters theParams) {
|
public SearchTask createSearchTask(SearchTaskParameters theParams) {
|
||||||
return new SearchTask(theParams,
|
return new SearchTask(theParams,
|
||||||
myManagedTxManager,
|
myHapiTransactionService,
|
||||||
myContext,
|
myContext,
|
||||||
myInterceptorBroadcaster,
|
myInterceptorBroadcaster,
|
||||||
mySearchBuilderFactory,
|
mySearchBuilderFactory,
|
||||||
|
@ -176,7 +179,7 @@ public class SearchConfig {
|
||||||
@Scope("prototype")
|
@Scope("prototype")
|
||||||
public SearchContinuationTask createSearchContinuationTask(SearchTaskParameters theParams) {
|
public SearchContinuationTask createSearchContinuationTask(SearchTaskParameters theParams) {
|
||||||
return new SearchContinuationTask(theParams,
|
return new SearchContinuationTask(theParams,
|
||||||
myManagedTxManager,
|
myHapiTransactionService,
|
||||||
myContext,
|
myContext,
|
||||||
myInterceptorBroadcaster,
|
myInterceptorBroadcaster,
|
||||||
mySearchBuilderFactory,
|
mySearchBuilderFactory,
|
||||||
|
|
|
@ -1247,8 +1247,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
||||||
* @param entity the existing entity.
|
* @param entity the existing entity.
|
||||||
*/
|
*/
|
||||||
private void failIfPartitionMismatch(RequestDetails theRequest, ResourceTable entity) {
|
private void failIfPartitionMismatch(RequestDetails theRequest, ResourceTable entity) {
|
||||||
if (myPartitionSettings.isPartitioningEnabled() && theRequest != null && theRequest.getTenantId() != null && entity.getPartitionId() != null &&
|
if (myPartitionSettings.isPartitioningEnabled() && theRequest != null && theRequest.getTenantId() != null && entity.getPartitionId() != null) {
|
||||||
!ALL_PARTITIONS_NAME.equals(theRequest.getTenantId())) {
|
|
||||||
PartitionEntity partitionEntity = myPartitionLookupSvc.getPartitionByName(theRequest.getTenantId());
|
PartitionEntity partitionEntity = myPartitionLookupSvc.getPartitionByName(theRequest.getTenantId());
|
||||||
//partitionEntity should never be null
|
//partitionEntity should never be null
|
||||||
if (partitionEntity != null && !partitionEntity.getId().equals(entity.getPartitionId().getPartitionId())) {
|
if (partitionEntity != null && !partitionEntity.getId().equals(entity.getPartitionId().getPartitionId())) {
|
||||||
|
|
|
@ -57,7 +57,7 @@ import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProviderFactory;
|
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProviderFactory;
|
||||||
import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum;
|
import ca.uhn.fhir.jpa.search.cache.SearchCacheStatusEnum;
|
||||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.jpa.dao.expunge;
|
||||||
import ca.uhn.fhir.interceptor.api.HookParams;
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity;
|
import ca.uhn.fhir.jpa.entity.Batch2JobInstanceEntity;
|
||||||
import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity;
|
import ca.uhn.fhir.jpa.entity.Batch2WorkChunkEntity;
|
||||||
import ca.uhn.fhir.jpa.entity.BulkImportJobEntity;
|
import ca.uhn.fhir.jpa.entity.BulkImportJobEntity;
|
||||||
|
@ -77,12 +78,9 @@ import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import javax.persistence.PersistenceContext;
|
import javax.persistence.PersistenceContext;
|
||||||
import javax.persistence.PersistenceContextType;
|
import javax.persistence.PersistenceContextType;
|
||||||
|
@ -98,22 +96,15 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
||||||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||||
protected EntityManager myEntityManager;
|
protected EntityManager myEntityManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlatformTransactionManager myPlatformTransactionManager;
|
private HapiTransactionService myTxService;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected IInterceptorBroadcaster myInterceptorBroadcaster;
|
protected IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
|
|
||||||
private TransactionTemplate myTxTemplate;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private MemoryCacheService myMemoryCacheService;
|
private MemoryCacheService myMemoryCacheService;
|
||||||
|
|
||||||
private int deletedResourceEntityCount;
|
private int deletedResourceEntityCount;
|
||||||
|
|
||||||
@PostConstruct
|
|
||||||
public void initTxTemplate() {
|
|
||||||
myTxTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void expungeEverything(@Nullable RequestDetails theRequest) {
|
public void expungeEverything(@Nullable RequestDetails theRequest) {
|
||||||
|
|
||||||
|
@ -127,68 +118,64 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
||||||
CompositeInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING, hooks);
|
CompositeInterceptorBroadcaster.doCallHooks(myInterceptorBroadcaster, theRequest, Pointcut.STORAGE_PRESTORAGE_EXPUNGE_EVERYTHING, hooks);
|
||||||
|
|
||||||
ourLog.info("BEGINNING GLOBAL $expunge");
|
ourLog.info("BEGINNING GLOBAL $expunge");
|
||||||
myTxTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||||
myTxTemplate.execute(t -> {
|
|
||||||
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null"));
|
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null"));
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(Batch2WorkChunkEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, Batch2WorkChunkEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(Batch2JobInstanceEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, Batch2JobInstanceEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(NpmPackageVersionResourceEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, NpmPackageVersionResourceEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(NpmPackageVersionEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, NpmPackageVersionEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(NpmPackageEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, NpmPackageEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SearchParamPresentEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SearchParamPresentEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(BulkImportJobFileEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobFileEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(BulkImportJobEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ForcedId.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ForcedId.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamDate.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamDate.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamNumber.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamNumber.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamQuantity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamQuantity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamQuantityNormalized.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamQuantityNormalized.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamString.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamString.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamToken.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamToken.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamUri.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamUri.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamCoords.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamCoords.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedComboStringUnique.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedComboStringUnique.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedComboTokenNonUnique.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedComboTokenNonUnique.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceLink.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceLink.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SearchResult.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SearchResult.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SearchInclude.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SearchInclude.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermValueSetConceptDesignation.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermValueSetConceptDesignation.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermValueSetConcept.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermValueSetConcept.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermValueSet.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermValueSet.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptParentChildLink.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptParentChildLink.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMapGroupElementTarget.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMapGroupElementTarget.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMapGroupElement.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMapGroupElement.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMapGroup.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMapGroup.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMap.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMap.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptProperty.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptProperty.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptDesignation.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptDesignation.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConcept.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConcept.class));
|
||||||
myTxTemplate.execute(t -> {
|
myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||||
for (TermCodeSystem next : myEntityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) {
|
for (TermCodeSystem next : myEntityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) {
|
||||||
next.setCurrentVersion(null);
|
next.setCurrentVersion(null);
|
||||||
myEntityManager.merge(next);
|
myEntityManager.merge(next);
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermCodeSystemVersion.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermCodeSystemVersion.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermCodeSystem.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermCodeSystem.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SubscriptionTable.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SubscriptionTable.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceHistoryTag.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceHistoryTag.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceTag.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceTag.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TagDefinition.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TagDefinition.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceHistoryProvenanceEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceHistoryProvenanceEntity.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceHistoryTable.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceHistoryTable.class));
|
||||||
int counterBefore = counter.get();
|
int counterBefore = counter.get();
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceTable.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceTable.class));
|
||||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(PartitionEntity.class));
|
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, PartitionEntity.class));
|
||||||
|
|
||||||
deletedResourceEntityCount = counter.get() - counterBefore;
|
deletedResourceEntityCount = counter.get() - counterBefore;
|
||||||
|
|
||||||
myTxTemplate.execute(t -> {
|
myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + Search.class.getSimpleName() + " d"));
|
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + Search.class.getSimpleName() + " d"));
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
purgeAllCaches();
|
purgeAllCaches();
|
||||||
|
@ -202,19 +189,15 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void purgeAllCaches() {
|
private void purgeAllCaches() {
|
||||||
myTxTemplate.execute(t -> {
|
|
||||||
myMemoryCacheService.invalidateAllCaches();
|
myMemoryCacheService.invalidateAllCaches();
|
||||||
return null;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private int expungeEverythingByTypeWithoutPurging(Class<?> theEntityType) {
|
private int expungeEverythingByTypeWithoutPurging(RequestDetails theRequest, Class<?> theEntityType) {
|
||||||
int outcome = 0;
|
int outcome = 0;
|
||||||
while (true) {
|
while (true) {
|
||||||
StopWatch sw = new StopWatch();
|
StopWatch sw = new StopWatch();
|
||||||
|
|
||||||
@SuppressWarnings("ConstantConditions")
|
int count = myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||||
int count = myTxTemplate.execute(t -> {
|
|
||||||
CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();
|
CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();
|
||||||
CriteriaQuery<?> cq = cb.createQuery(theEntityType);
|
CriteriaQuery<?> cq = cb.createQuery(theEntityType);
|
||||||
cq.from(theEntityType);
|
cq.from(theEntityType);
|
||||||
|
@ -239,7 +222,7 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int expungeEverythingByType(Class<?> theEntityType) {
|
public int expungeEverythingByType(Class<?> theEntityType) {
|
||||||
int result = expungeEverythingByTypeWithoutPurging(theEntityType);
|
int result = expungeEverythingByTypeWithoutPurging(null, theEntityType);
|
||||||
purgeAllCaches();
|
purgeAllCaches();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.dao.mdm;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JPA Server - Master Data Management
|
* HAPI FHIR JPA Server
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||||
* %%
|
* %%
|
||||||
|
|
|
@ -28,6 +28,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.api.model.DeleteConflict;
|
import ca.uhn.fhir.jpa.api.model.DeleteConflict;
|
||||||
import ca.uhn.fhir.jpa.api.model.DeleteConflictList;
|
import ca.uhn.fhir.jpa.api.model.DeleteConflictList;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.IHapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
@ -42,42 +43,32 @@ import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
import org.springframework.retry.backoff.FixedBackOffPolicy;
|
||||||
import org.springframework.retry.policy.SimpleRetryPolicy;
|
import org.springframework.retry.policy.SimpleRetryPolicy;
|
||||||
import org.springframework.retry.support.RetryTemplate;
|
import org.springframework.retry.support.RetryTemplate;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used by {@link CascadingDeleteInterceptor} to handle {@link DeleteConflictList}s in a thead-safe way.
|
* Used by {@link CascadingDeleteInterceptor} to handle {@link DeleteConflictList}s in a thead-safe way.
|
||||||
*
|
* <p>
|
||||||
* Specifically, this class spawns an inner transaction for each {@link DeleteConflictList}. This class is meant to handle any potential delete collisions (ex {@link ResourceGoneException} or {@link ResourceVersionConflictException}. In the former case, we swallow the Exception in the inner transaction then continue. In the latter case, we retry according to the RETRY_BACKOFF_PERIOD and RETRY_MAX_ATTEMPTS before giving up.
|
* Specifically, this class spawns an inner transaction for each {@link DeleteConflictList}. This class is meant to handle any potential delete collisions (ex {@link ResourceGoneException} or {@link ResourceVersionConflictException}. In the former case, we swallow the Exception in the inner transaction then continue. In the latter case, we retry according to the RETRY_BACKOFF_PERIOD and RETRY_MAX_ATTEMPTS before giving up.
|
||||||
*/
|
*/
|
||||||
public class ThreadSafeResourceDeleterSvc {
|
public class ThreadSafeResourceDeleterSvc {
|
||||||
|
|
||||||
private static final String REQ_DET_KEY_IN_NEW_TRANSACTION = ThreadSafeResourceDeleterSvc.class.getName() + "REQ_DET_KEY_IN_NEW_TRANSACTION";
|
|
||||||
|
|
||||||
public static final long RETRY_BACKOFF_PERIOD = 100L;
|
public static final long RETRY_BACKOFF_PERIOD = 100L;
|
||||||
public static final int RETRY_MAX_ATTEMPTS = 4;
|
public static final int RETRY_MAX_ATTEMPTS = 4;
|
||||||
|
private static final String REQ_DET_KEY_IN_NEW_TRANSACTION = ThreadSafeResourceDeleterSvc.class.getName() + "REQ_DET_KEY_IN_NEW_TRANSACTION";
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(ThreadSafeResourceDeleterSvc.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(ThreadSafeResourceDeleterSvc.class);
|
||||||
private final DaoRegistry myDaoRegistry;
|
private final DaoRegistry myDaoRegistry;
|
||||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
private final TransactionTemplate myTxTemplateRequired;
|
|
||||||
private final TransactionTemplate myTxTemplateRequiresNew;
|
|
||||||
|
|
||||||
private final RetryTemplate myRetryTemplate = getRetryTemplate();
|
private final RetryTemplate myRetryTemplate = getRetryTemplate();
|
||||||
|
private final IHapiTransactionService myTransactionService;
|
||||||
|
|
||||||
public ThreadSafeResourceDeleterSvc(DaoRegistry theDaoRegistry, IInterceptorBroadcaster theInterceptorBroadcaster, PlatformTransactionManager thePlatformTransactionManager) {
|
public ThreadSafeResourceDeleterSvc(DaoRegistry theDaoRegistry, IInterceptorBroadcaster theInterceptorBroadcaster, IHapiTransactionService theTransactionService) {
|
||||||
myDaoRegistry = theDaoRegistry;
|
myDaoRegistry = theDaoRegistry;
|
||||||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||||
|
myTransactionService = theTransactionService;
|
||||||
myTxTemplateRequired = new TransactionTemplate(thePlatformTransactionManager);
|
|
||||||
myTxTemplateRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
|
|
||||||
myTxTemplateRequiresNew = new TransactionTemplate(thePlatformTransactionManager);
|
|
||||||
myTxTemplateRequiresNew.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,13 +112,20 @@ public class ThreadSafeResourceDeleterSvc {
|
||||||
|
|
||||||
// Avoid nesting multiple new transactions deep. This can easily cause
|
// Avoid nesting multiple new transactions deep. This can easily cause
|
||||||
// thread pools to get exhausted.
|
// thread pools to get exhausted.
|
||||||
|
Propagation propagation;
|
||||||
if (theRequest == null || previousNewTransactionValue != null) {
|
if (theRequest == null || previousNewTransactionValue != null) {
|
||||||
myTxTemplateRequired.execute(s -> doDelete(theRequest, theConflictList, theTransactionDetails, nextSource, dao));
|
propagation = Propagation.REQUIRED;
|
||||||
} else {
|
} else {
|
||||||
theRequest.getUserData().put(REQ_DET_KEY_IN_NEW_TRANSACTION, REQ_DET_KEY_IN_NEW_TRANSACTION);
|
theRequest.getUserData().put(REQ_DET_KEY_IN_NEW_TRANSACTION, REQ_DET_KEY_IN_NEW_TRANSACTION);
|
||||||
myTxTemplateRequiresNew.execute(s -> doDelete(theRequest, theConflictList, theTransactionDetails, nextSource, dao));
|
propagation = Propagation.REQUIRES_NEW;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
myTransactionService
|
||||||
|
.withRequest(theRequest)
|
||||||
|
.withTransactionDetails(theTransactionDetails)
|
||||||
|
.withPropagation(propagation)
|
||||||
|
.execute(() -> doDelete(theRequest, theConflictList, theTransactionDetails, nextSource, dao));
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
} catch (ResourceGoneException exception) {
|
} catch (ResourceGoneException exception) {
|
||||||
ourLog.info("{} is already deleted. Skipping cascade delete of this resource", nextSourceId);
|
ourLog.info("{} is already deleted. Skipping cascade delete of this resource", nextSourceId);
|
||||||
|
|
|
@ -40,7 +40,6 @@ import javax.persistence.OneToMany;
|
||||||
import javax.persistence.OneToOne;
|
import javax.persistence.OneToOne;
|
||||||
import javax.persistence.SequenceGenerator;
|
import javax.persistence.SequenceGenerator;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Transient;
|
|
||||||
import javax.persistence.UniqueConstraint;
|
import javax.persistence.UniqueConstraint;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -23,10 +23,8 @@ package ca.uhn.fhir.jpa.interceptor;
|
||||||
import ca.uhn.fhir.interceptor.api.Hook;
|
import ca.uhn.fhir.interceptor.api.Hook;
|
||||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.model.cross;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JPA Model
|
* HAPI FHIR JPA Server
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||||
* %%
|
* %%
|
||||||
|
|
|
@ -40,7 +40,7 @@ import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity;
|
||||||
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionResourceEntity;
|
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionResourceEntity;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
|
|
|
@ -35,7 +35,7 @@ import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.dao.data.INpmPackageVersionDao;
|
import ca.uhn.fhir.jpa.dao.data.INpmPackageVersionDao;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity;
|
import ca.uhn.fhir.jpa.model.entity.NpmPackageVersionEntity;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistryController;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistryController;
|
||||||
import ca.uhn.fhir.jpa.searchparam.util.SearchParameterHelper;
|
import ca.uhn.fhir.jpa.searchparam.util.SearchParameterHelper;
|
||||||
|
@ -49,14 +49,12 @@ import ca.uhn.fhir.util.FhirTerser;
|
||||||
import ca.uhn.fhir.util.SearchParameterUtil;
|
import ca.uhn.fhir.util.SearchParameterUtil;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import com.google.gson.Gson;
|
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.Identifier;
|
import org.hl7.fhir.r4.model.Identifier;
|
||||||
import org.hl7.fhir.utilities.json.model.JsonElement;
|
|
||||||
import org.hl7.fhir.utilities.json.model.JsonObject;
|
import org.hl7.fhir.utilities.json.model.JsonObject;
|
||||||
import org.hl7.fhir.utilities.npm.IPackageCacheManager;
|
import org.hl7.fhir.utilities.npm.IPackageCacheManager;
|
||||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||||
|
@ -72,9 +70,7 @@ import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.defaultString;
|
import static org.apache.commons.lang3.StringUtils.defaultString;
|
||||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.partition;
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -46,7 +47,7 @@ public interface IPartitionLookupSvc {
|
||||||
|
|
||||||
void clearCaches();
|
void clearCaches();
|
||||||
|
|
||||||
PartitionEntity createPartition(PartitionEntity thePartition);
|
PartitionEntity createPartition(PartitionEntity thePartition, RequestDetails theRequestDetails);
|
||||||
|
|
||||||
PartitionEntity updatePartition(PartitionEntity thePartition);
|
PartitionEntity updatePartition(PartitionEntity thePartition);
|
||||||
|
|
||||||
|
|
|
@ -22,16 +22,23 @@ package ca.uhn.fhir.jpa.partition;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
|
import ca.uhn.fhir.interceptor.api.HookParams;
|
||||||
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IPartitionDao;
|
import ca.uhn.fhir.jpa.dao.data.IPartitionDao;
|
||||||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
import ca.uhn.fhir.jpa.model.util.JpaConstants;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.sl.cache.CacheFactory;
|
import ca.uhn.fhir.sl.cache.CacheFactory;
|
||||||
import ca.uhn.fhir.sl.cache.CacheLoader;
|
import ca.uhn.fhir.sl.cache.CacheLoader;
|
||||||
import ca.uhn.fhir.sl.cache.LoadingCache;
|
import ca.uhn.fhir.sl.cache.LoadingCache;
|
||||||
|
import ca.uhn.fhir.util.ICallable;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
|
@ -42,6 +49,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.PostConstruct;
|
import javax.annotation.PostConstruct;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -58,15 +66,17 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
||||||
@Autowired
|
@Autowired
|
||||||
private PartitionSettings myPartitionSettings;
|
private PartitionSettings myPartitionSettings;
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlatformTransactionManager myTxManager;
|
private IInterceptorService myInterceptorService;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPartitionDao myPartitionDao;
|
private IPartitionDao myPartitionDao;
|
||||||
|
|
||||||
private LoadingCache<String, PartitionEntity> myNameToPartitionCache;
|
private LoadingCache<String, PartitionEntity> myNameToPartitionCache;
|
||||||
private LoadingCache<Integer, PartitionEntity> myIdToPartitionCache;
|
private LoadingCache<Integer, PartitionEntity> myIdToPartitionCache;
|
||||||
private TransactionTemplate myTxTemplate;
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myFhirCtx;
|
private FhirContext myFhirCtx;
|
||||||
|
@Autowired
|
||||||
|
private PlatformTransactionManager myTxManager;
|
||||||
|
private TransactionTemplate myTxTemplate;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -113,15 +123,25 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public PartitionEntity createPartition(PartitionEntity thePartition) {
|
public PartitionEntity createPartition(PartitionEntity thePartition, RequestDetails theRequestDetails) {
|
||||||
validateNotInUnnamedPartitionMode();
|
validateNotInUnnamedPartitionMode();
|
||||||
validateHaveValidPartitionIdAndName(thePartition);
|
validateHaveValidPartitionIdAndName(thePartition);
|
||||||
validatePartitionNameDoesntAlreadyExist(thePartition.getName());
|
validatePartitionNameDoesntAlreadyExist(thePartition.getName());
|
||||||
|
|
||||||
ourLog.info("Creating new partition with ID {} and Name {}", thePartition.getId(), thePartition.getName());
|
ourLog.info("Creating new partition with ID {} and Name {}", thePartition.getId(), thePartition.getName());
|
||||||
|
|
||||||
myPartitionDao.save(thePartition);
|
PartitionEntity retVal = myPartitionDao.save(thePartition);
|
||||||
return thePartition;
|
|
||||||
|
// Interceptor call: STORAGE_PARTITION_CREATED
|
||||||
|
if (myInterceptorService.hasHooks(Pointcut.STORAGE_PARTITION_CREATED)) {
|
||||||
|
HookParams params = new HookParams()
|
||||||
|
.add(RequestPartitionId.class, thePartition.toRequestPartitionId())
|
||||||
|
.add(RequestDetails.class, theRequestDetails)
|
||||||
|
.addIfMatchesType(ServletRequestDetails.class, theRequestDetails);
|
||||||
|
myInterceptorService.callHooks(Pointcut.STORAGE_PARTITION_CREATED, params);
|
||||||
|
}
|
||||||
|
|
||||||
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -167,7 +187,7 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<PartitionEntity> listPartitions() {
|
public List<PartitionEntity> listPartitions() {
|
||||||
List<PartitionEntity> allPartitions = myPartitionDao.findAll();
|
List<PartitionEntity> allPartitions = myPartitionDao.findAll();
|
||||||
return allPartitions;
|
return allPartitions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -202,16 +222,31 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private PartitionEntity lookupPartitionByName(@Nonnull String theName) {
|
||||||
|
return executeInTransaction(() -> myPartitionDao.findForName(theName))
|
||||||
|
.orElseThrow(() -> {
|
||||||
|
String msg = myFhirCtx.getLocalizer().getMessageSanitized(PartitionLookupSvcImpl.class, "invalidName", theName);
|
||||||
|
return new ResourceNotFoundException(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private PartitionEntity lookupPartitionById(@Nonnull Integer theId) {
|
||||||
|
return executeInTransaction(() -> myPartitionDao.findById(theId))
|
||||||
|
.orElseThrow(() -> {
|
||||||
|
String msg = myFhirCtx.getLocalizer().getMessageSanitized(PartitionLookupSvcImpl.class, "unknownPartitionId", theId);
|
||||||
|
return new ResourceNotFoundException(msg);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected <T> T executeInTransaction(ICallable<T> theCallable) {
|
||||||
|
return myTxTemplate.execute(tx -> theCallable.call());
|
||||||
|
}
|
||||||
|
|
||||||
private class NameToPartitionCacheLoader implements @NonNull CacheLoader<String, PartitionEntity> {
|
private class NameToPartitionCacheLoader implements @NonNull CacheLoader<String, PartitionEntity> {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public PartitionEntity load(@NonNull String theName) {
|
public PartitionEntity load(@NonNull String theName) {
|
||||||
return myTxTemplate.execute(t -> myPartitionDao
|
return lookupPartitionByName(theName);
|
||||||
.findForName(theName)
|
|
||||||
.orElseThrow(() -> {
|
|
||||||
String msg = myFhirCtx.getLocalizer().getMessageSanitized(PartitionLookupSvcImpl.class, "invalidName", theName);
|
|
||||||
return new ResourceNotFoundException(msg);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,12 +254,7 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
||||||
@Nullable
|
@Nullable
|
||||||
@Override
|
@Override
|
||||||
public PartitionEntity load(@NonNull Integer theId) {
|
public PartitionEntity load(@NonNull Integer theId) {
|
||||||
return myTxTemplate.execute(t -> myPartitionDao
|
return lookupPartitionById(theId);
|
||||||
.findById(theId)
|
|
||||||
.orElseThrow(() -> {
|
|
||||||
String msg = myFhirCtx.getLocalizer().getMessageSanitized(PartitionLookupSvcImpl.class, "unknownPartitionId", theId);
|
|
||||||
return new ResourceNotFoundException(msg);
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
import ca.uhn.fhir.rest.annotation.Operation;
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
import ca.uhn.fhir.rest.server.provider.ProviderConstants;
|
||||||
import ca.uhn.fhir.util.ParametersUtil;
|
import ca.uhn.fhir.util.ParametersUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.IBase;
|
||||||
|
@ -35,7 +35,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.partition.PartitionLookupSvcImpl.validatePartitionIdSupplied;
|
import static ca.uhn.fhir.jpa.partition.PartitionLookupSvcImpl.validatePartitionIdSupplied;
|
||||||
|
@ -70,14 +69,15 @@ public class PartitionManagementProvider {
|
||||||
@ResourceParam IBaseParameters theRequest,
|
@ResourceParam IBaseParameters theRequest,
|
||||||
@OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, min = 1, max = 1, typeName = "integer") IPrimitiveType<Integer> thePartitionId,
|
@OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_ID, min = 1, max = 1, typeName = "integer") IPrimitiveType<Integer> thePartitionId,
|
||||||
@OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME, min = 1, max = 1, typeName = "code") IPrimitiveType<String> thePartitionName,
|
@OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_NAME, min = 1, max = 1, typeName = "code") IPrimitiveType<String> thePartitionName,
|
||||||
@OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC, min = 0, max = 1, typeName = "string") IPrimitiveType<String> thePartitionDescription
|
@OperationParam(name = ProviderConstants.PARTITION_MANAGEMENT_PARTITION_DESC, min = 0, max = 1, typeName = "string") IPrimitiveType<String> thePartitionDescription,
|
||||||
|
RequestDetails theRequestDetails
|
||||||
) {
|
) {
|
||||||
validatePartitionIdSupplied(myCtx, toValueOrNull(thePartitionId));
|
validatePartitionIdSupplied(myCtx, toValueOrNull(thePartitionId));
|
||||||
|
|
||||||
PartitionEntity input = parseInput(thePartitionId, thePartitionName, thePartitionDescription);
|
PartitionEntity input = parseInput(thePartitionId, thePartitionName, thePartitionDescription);
|
||||||
|
|
||||||
// Note: Input validation happens inside IPartitionLookupSvc
|
// Note: Input validation happens inside IPartitionLookupSvc
|
||||||
PartitionEntity output = myPartitionLookupSvc.createPartition(input);
|
PartitionEntity output = myPartitionLookupSvc.createPartition(input, theRequestDetails);
|
||||||
|
|
||||||
IBaseParameters retVal = prepareOutput(output);
|
IBaseParameters retVal = prepareOutput(output);
|
||||||
|
|
||||||
|
|
|
@ -35,7 +35,7 @@ import java.util.Objects;
|
||||||
public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc {
|
public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IPartitionLookupSvc myPartitionConfigSvc;
|
IPartitionLookupSvc myPartitionConfigSvc;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) {
|
protected RequestPartitionId validateAndNormalizePartitionIds(RequestPartitionId theRequestPartitionId) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ import ca.uhn.fhir.jpa.api.pid.MixedResourcePidList;
|
||||||
import ca.uhn.fhir.jpa.api.svc.IBatch2DaoSvc;
|
import ca.uhn.fhir.jpa.api.svc.IBatch2DaoSvc;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
|
|
@ -34,6 +34,7 @@ import ca.uhn.fhir.jpa.dao.HistoryBuilderFactory;
|
||||||
import ca.uhn.fhir.jpa.dao.IJpaStorageResourceParser;
|
import ca.uhn.fhir.jpa.dao.IJpaStorageResourceParser;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.entity.Search;
|
import ca.uhn.fhir.jpa.entity.Search;
|
||||||
import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
|
import ca.uhn.fhir.jpa.entity.SearchTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
|
@ -59,11 +60,6 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.TransactionStatus;
|
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
|
@ -82,9 +78,9 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
/*
|
/*
|
||||||
* Autowired fields
|
* Autowired fields
|
||||||
*/
|
*/
|
||||||
private final RequestDetails myRequest;
|
protected final RequestDetails myRequest;
|
||||||
@Autowired
|
@Autowired
|
||||||
protected PlatformTransactionManager myTxManager;
|
protected HapiTransactionService myTxService;
|
||||||
@PersistenceContext
|
@PersistenceContext
|
||||||
private EntityManager myEntityManager;
|
private EntityManager myEntityManager;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
@ -213,10 +209,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
final ISearchBuilder sb = mySearchBuilderFactory.newSearchBuilder(dao, resourceName, resourceType);
|
final ISearchBuilder sb = mySearchBuilderFactory.newSearchBuilder(dao, resourceName, resourceType);
|
||||||
|
|
||||||
final List<JpaPid> pidsSubList = mySearchCoordinatorSvc.getResources(myUuid, theFromIndex, theToIndex, myRequest);
|
final List<JpaPid> pidsSubList = mySearchCoordinatorSvc.getResources(myUuid, theFromIndex, theToIndex, myRequest);
|
||||||
|
return myTxService.withRequest(myRequest).execute(() -> toResourceList(sb, pidsSubList));
|
||||||
TransactionTemplate template = new TransactionTemplate(myTxManager);
|
|
||||||
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
return template.execute(theStatus -> toResourceList(sb, pidsSubList));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -225,7 +218,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
*/
|
*/
|
||||||
public boolean ensureSearchEntityLoaded() {
|
public boolean ensureSearchEntityLoaded() {
|
||||||
if (mySearchEntity == null) {
|
if (mySearchEntity == null) {
|
||||||
Optional<Search> searchOpt = mySearchCacheSvc.fetchByUuid(myUuid);
|
Optional<Search> searchOpt = myTxService.withRequest(myRequest).execute(() -> mySearchCacheSvc.fetchByUuid(myUuid));
|
||||||
if (!searchOpt.isPresent()) {
|
if (!searchOpt.isPresent()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -262,7 +255,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
key = MemoryCacheService.HistoryCountKey.forSystem();
|
key = MemoryCacheService.HistoryCountKey.forSystem();
|
||||||
}
|
}
|
||||||
|
|
||||||
Function<MemoryCacheService.HistoryCountKey, Integer> supplier = k -> new TransactionTemplate(myTxManager).execute(t -> {
|
Function<MemoryCacheService.HistoryCountKey, Integer> supplier = k -> myTxService.withRequest(myRequest).execute(() -> {
|
||||||
HistoryBuilder historyBuilder = myHistoryBuilderFactory.newHistoryBuilder(mySearchEntity.getResourceType(), mySearchEntity.getResourceId(), mySearchEntity.getLastUpdatedLow(), mySearchEntity.getLastUpdatedHigh());
|
HistoryBuilder historyBuilder = myHistoryBuilderFactory.newHistoryBuilder(mySearchEntity.getResourceType(), mySearchEntity.getResourceId(), mySearchEntity.getLastUpdatedLow(), mySearchEntity.getLastUpdatedHigh());
|
||||||
Long count = historyBuilder.fetchCount(getRequestPartitionIdForHistory());
|
Long count = historyBuilder.fetchCount(getRequestPartitionIdForHistory());
|
||||||
return count.intValue();
|
return count.intValue();
|
||||||
|
@ -299,14 +292,9 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
@Nonnull
|
@Nonnull
|
||||||
@Override
|
@Override
|
||||||
public List<IBaseResource> getResources(final int theFromIndex, final int theToIndex) {
|
public List<IBaseResource> getResources(final int theFromIndex, final int theToIndex) {
|
||||||
TransactionTemplate template = new TransactionTemplate(myTxManager);
|
myTxService.withRequest(myRequest).execute(() -> {
|
||||||
|
boolean entityLoaded = ensureSearchEntityLoaded();
|
||||||
template.execute(new TransactionCallbackWithoutResult() {
|
assert entityLoaded;
|
||||||
@Override
|
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) {
|
|
||||||
boolean entityLoaded = ensureSearchEntityLoaded();
|
|
||||||
assert entityLoaded;
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
assert mySearchEntity != null;
|
assert mySearchEntity != null;
|
||||||
|
@ -314,7 +302,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
|
|
||||||
switch (mySearchEntity.getSearchType()) {
|
switch (mySearchEntity.getSearchType()) {
|
||||||
case HISTORY:
|
case HISTORY:
|
||||||
return template.execute(theStatus -> doHistoryInTransaction(mySearchEntity.getOffset(), theFromIndex, theToIndex));
|
return myTxService.withRequest(myRequest).execute(() -> doHistoryInTransaction(mySearchEntity.getOffset(), theFromIndex, theToIndex));
|
||||||
case SEARCH:
|
case SEARCH:
|
||||||
case EVERYTHING:
|
case EVERYTHING:
|
||||||
default:
|
default:
|
||||||
|
@ -365,8 +353,8 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
public void setTxManagerForUnitTest(PlatformTransactionManager theTxManager) {
|
public void setTxServiceForUnitTest(HapiTransactionService theTxManager) {
|
||||||
myTxManager = theTxManager;
|
myTxService = theTxManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Leave as protected, HSPC depends on this
|
// Note: Leave as protected, HSPC depends on this
|
||||||
|
@ -388,7 +376,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
||||||
if (mySearchEntity.getSearchType() == SearchTypeEnum.HISTORY) {
|
if (mySearchEntity.getSearchType() == SearchTypeEnum.HISTORY) {
|
||||||
return null;
|
return null;
|
||||||
} else {
|
} else {
|
||||||
return mySearchCoordinatorSvc.getSearchTotal(myUuid).orElse(null);
|
return mySearchCoordinatorSvc.getSearchTotal(myUuid, myRequest).orElse(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -34,8 +34,6 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -70,9 +68,7 @@ public class PersistedJpaSearchFirstPageBundleProvider extends PersistedJpaBundl
|
||||||
final List<JpaPid> pids = mySearchTask.getResourcePids(theFromIndex, theToIndex);
|
final List<JpaPid> pids = mySearchTask.getResourcePids(theFromIndex, theToIndex);
|
||||||
ourLog.trace("Done fetching search resource PIDs");
|
ourLog.trace("Done fetching search resource PIDs");
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
List<IBaseResource> retVal = myTxService.withRequest(myRequest).execute(() -> toResourceList(mySearchBuilder, pids));
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
List<IBaseResource> retVal = txTemplate.execute(theStatus -> toResourceList(mySearchBuilder, pids));
|
|
||||||
|
|
||||||
long totalCountWanted = theToIndex - theFromIndex;
|
long totalCountWanted = theToIndex - theFromIndex;
|
||||||
long totalCountMatch = (int) retVal
|
long totalCountMatch = (int) retVal
|
||||||
|
|
|
@ -36,6 +36,7 @@ import ca.uhn.fhir.jpa.dao.BaseStorageDao;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
import ca.uhn.fhir.jpa.dao.search.ResourceNotFoundInIndexException;
|
import ca.uhn.fhir.jpa.dao.search.ResourceNotFoundInIndexException;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.entity.Search;
|
import ca.uhn.fhir.jpa.entity.Search;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
||||||
|
@ -62,6 +63,7 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
|
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
import ca.uhn.fhir.rest.server.util.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.util.AsyncUtil;
|
import ca.uhn.fhir.util.AsyncUtil;
|
||||||
|
import ca.uhn.fhir.util.ICallable;
|
||||||
import ca.uhn.fhir.util.StopWatch;
|
import ca.uhn.fhir.util.StopWatch;
|
||||||
import ca.uhn.fhir.util.UrlUtil;
|
import ca.uhn.fhir.util.UrlUtil;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -72,11 +74,7 @@ import org.springframework.data.domain.AbstractPageRequest;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.domain.Sort;
|
import org.springframework.data.domain.Sort;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.annotation.Propagation;
|
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -86,6 +84,7 @@ import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
@ -103,7 +102,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
private final FhirContext myContext;
|
private final FhirContext myContext;
|
||||||
private final DaoConfig myDaoConfig;
|
private final DaoConfig myDaoConfig;
|
||||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
private final PlatformTransactionManager myManagedTxManager;
|
private final HapiTransactionService myTxService;
|
||||||
private final ISearchCacheSvc mySearchCacheSvc;
|
private final ISearchCacheSvc mySearchCacheSvc;
|
||||||
private final ISearchResultCacheSvc mySearchResultCacheSvc;
|
private final ISearchResultCacheSvc mySearchResultCacheSvc;
|
||||||
private final DaoRegistry myDaoRegistry;
|
private final DaoRegistry myDaoRegistry;
|
||||||
|
@ -115,18 +114,15 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
private final SearchStrategyFactory mySearchStrategyFactory;
|
private final SearchStrategyFactory mySearchStrategyFactory;
|
||||||
private final ExceptionService myExceptionSvc;
|
private final ExceptionService myExceptionSvc;
|
||||||
private final BeanFactory myBeanFactory;
|
private final BeanFactory myBeanFactory;
|
||||||
|
|
||||||
private Integer myLoadingThrottleForUnitTests = null;
|
|
||||||
private long myMaxMillisToWaitForRemoteResults = DateUtils.MILLIS_PER_MINUTE;
|
|
||||||
private boolean myNeverUseLocalSearchForUnitTests;
|
|
||||||
|
|
||||||
private int mySyncSize = DEFAULT_SYNC_SIZE;
|
|
||||||
|
|
||||||
private final ConcurrentHashMap<String, SearchTask> myIdToSearchTask = new ConcurrentHashMap<>();
|
private final ConcurrentHashMap<String, SearchTask> myIdToSearchTask = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
private final Consumer<String> myOnRemoveSearchTask = (theId) -> myIdToSearchTask.remove(theId);
|
private final Consumer<String> myOnRemoveSearchTask = (theId) -> myIdToSearchTask.remove(theId);
|
||||||
|
|
||||||
private final StorageInterceptorHooksFacade myStorageInterceptorHooks;
|
private final StorageInterceptorHooksFacade myStorageInterceptorHooks;
|
||||||
|
private Integer myLoadingThrottleForUnitTests = null;
|
||||||
|
private long myMaxMillisToWaitForRemoteResults = DateUtils.MILLIS_PER_MINUTE;
|
||||||
|
private boolean myNeverUseLocalSearchForUnitTests;
|
||||||
|
private int mySyncSize = DEFAULT_SYNC_SIZE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -135,7 +131,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
FhirContext theContext,
|
FhirContext theContext,
|
||||||
DaoConfig theDaoConfig,
|
DaoConfig theDaoConfig,
|
||||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||||
PlatformTransactionManager theManagedTxManager,
|
HapiTransactionService theTxService,
|
||||||
ISearchCacheSvc theSearchCacheSvc,
|
ISearchCacheSvc theSearchCacheSvc,
|
||||||
ISearchResultCacheSvc theSearchResultCacheSvc,
|
ISearchResultCacheSvc theSearchResultCacheSvc,
|
||||||
DaoRegistry theDaoRegistry,
|
DaoRegistry theDaoRegistry,
|
||||||
|
@ -152,7 +148,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
myDaoConfig = theDaoConfig;
|
myDaoConfig = theDaoConfig;
|
||||||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||||
myManagedTxManager = theManagedTxManager;
|
myTxService = theTxService;
|
||||||
mySearchCacheSvc = theSearchCacheSvc;
|
mySearchCacheSvc = theSearchCacheSvc;
|
||||||
mySearchResultCacheSvc = theSearchResultCacheSvc;
|
mySearchResultCacheSvc = theSearchResultCacheSvc;
|
||||||
myDaoRegistry = theDaoRegistry;
|
myDaoRegistry = theDaoRegistry;
|
||||||
|
@ -208,10 +204,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
* fetch resources.
|
* fetch resources.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
@Transactional(propagation = Propagation.NEVER)
|
|
||||||
public List<JpaPid> getResources(final String theUuid, int theFrom, int theTo, @Nullable RequestDetails theRequestDetails) {
|
public List<JpaPid> getResources(final String theUuid, int theFrom, int theTo, @Nullable RequestDetails theRequestDetails) {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
assert !TransactionSynchronizationManager.isActualTransactionActive();
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
|
|
||||||
// If we're actively searching right now, don't try to do anything until at least one batch has been
|
// If we're actively searching right now, don't try to do anything until at least one batch has been
|
||||||
// persisted in the DB
|
// persisted in the DB
|
||||||
|
@ -244,9 +238,14 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
search = mySearchCacheSvc
|
Callable<Search> searchCallback = () -> mySearchCacheSvc
|
||||||
.fetchByUuid(theUuid)
|
.fetchByUuid(theUuid)
|
||||||
.orElseThrow(() -> myExceptionSvc.newUnknownSearchException(theUuid));
|
.orElseThrow(() -> myExceptionSvc.newUnknownSearchException(theUuid));
|
||||||
|
if (theRequestDetails != null) {
|
||||||
|
search = myTxService.withRequest(theRequestDetails).execute(searchCallback);
|
||||||
|
} else {
|
||||||
|
search = HapiTransactionService.invokeCallableAndHandleAnyException(searchCallback);
|
||||||
|
}
|
||||||
|
|
||||||
QueryParameterUtils.verifySearchHasntFailedOrThrowInternalErrorException(search);
|
QueryParameterUtils.verifySearchHasntFailedOrThrowInternalErrorException(search);
|
||||||
if (search.getStatus() == SearchStatusEnum.FINISHED) {
|
if (search.getStatus() == SearchStatusEnum.FINISHED) {
|
||||||
|
@ -299,16 +298,22 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
|
|
||||||
ourLog.trace("Finished looping");
|
ourLog.trace("Finished looping");
|
||||||
|
|
||||||
List<JpaPid> pids = mySearchResultCacheSvc.fetchResultPids(search, theFrom, theTo);
|
List<JpaPid> pids = fetchResultPids(theUuid, theFrom, theTo, theRequestDetails, search);
|
||||||
if (pids == null) {
|
|
||||||
throw myExceptionSvc.newUnknownSearchException(theUuid);
|
|
||||||
}
|
|
||||||
|
|
||||||
ourLog.trace("Fetched {} results", pids.size());
|
ourLog.trace("Fetched {} results", pids.size());
|
||||||
|
|
||||||
return pids;
|
return pids;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nonnull
|
||||||
|
private List<JpaPid> fetchResultPids(String theUuid, int theFrom, int theTo, @Nullable RequestDetails theRequestDetails, Search theSearch) {
|
||||||
|
List<JpaPid> pids = myTxService.withRequest(theRequestDetails).execute(() -> mySearchResultCacheSvc.fetchResultPids(theSearch, theFrom, theTo));
|
||||||
|
if (pids == null) {
|
||||||
|
throw myExceptionSvc.newUnknownSearchException(theUuid);
|
||||||
|
}
|
||||||
|
return pids;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IBundleProvider registerSearch(final IFhirResourceDao<?> theCallingDao, final SearchParameterMap theParams, String theResourceType, CacheControlDirective theCacheControlDirective, RequestDetails theRequestDetails, RequestPartitionId theRequestPartitionId) {
|
public IBundleProvider registerSearch(final IFhirResourceDao<?> theCallingDao, final SearchParameterMap theParams, String theResourceType, CacheControlDirective theCacheControlDirective, RequestDetails theRequestDetails, RequestPartitionId theRequestPartitionId) {
|
||||||
final String searchUuid = UUID.randomUUID().toString();
|
final String searchUuid = UUID.randomUUID().toString();
|
||||||
|
@ -337,7 +342,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
if (theParams.isLoadSynchronous() || loadSynchronousUpTo != null || isOffsetQuery) {
|
if (theParams.isLoadSynchronous() || loadSynchronousUpTo != null || isOffsetQuery) {
|
||||||
if (mySearchStrategyFactory.isSupportsHSearchDirect(theResourceType, theParams, theRequestDetails)) {
|
if (mySearchStrategyFactory.isSupportsHSearchDirect(theResourceType, theParams, theRequestDetails)) {
|
||||||
ourLog.info("Search {} is using direct load strategy", searchUuid);
|
ourLog.info("Search {} is using direct load strategy", searchUuid);
|
||||||
SearchStrategyFactory.ISearchStrategy direct = mySearchStrategyFactory.makeDirectStrategy(searchUuid, theResourceType, theParams, theRequestDetails);
|
SearchStrategyFactory.ISearchStrategy direct = mySearchStrategyFactory.makeDirectStrategy(searchUuid, theResourceType, theParams, theRequestDetails);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return direct.get();
|
return direct.get();
|
||||||
|
@ -429,7 +434,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Optional<Integer> getSearchTotal(String theUuid) {
|
public Optional<Integer> getSearchTotal(String theUuid, @Nullable RequestDetails theRequestDetails) {
|
||||||
SearchTask task = myIdToSearchTask.get(theUuid);
|
SearchTask task = myIdToSearchTask.get(theUuid);
|
||||||
if (task != null) {
|
if (task != null) {
|
||||||
return Optional.ofNullable(task.awaitInitialSync());
|
return Optional.ofNullable(task.awaitInitialSync());
|
||||||
|
@ -439,9 +444,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
* In case there is no running search, if the total is listed as accurate we know one is coming
|
* In case there is no running search, if the total is listed as accurate we know one is coming
|
||||||
* so let's wait a bit for it to show up
|
* so let's wait a bit for it to show up
|
||||||
*/
|
*/
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
Optional<Search> search = myTxService.withRequest(theRequestDetails).execute(()->mySearchCacheSvc.fetchByUuid(theUuid));
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
Optional<Search> search = mySearchCacheSvc.fetchByUuid(theUuid);
|
|
||||||
if (search.isPresent()) {
|
if (search.isPresent()) {
|
||||||
Optional<SearchParameterMap> searchParameterMap = search.get().getSearchParameterMap();
|
Optional<SearchParameterMap> searchParameterMap = search.get().getSearchParameterMap();
|
||||||
if (searchParameterMap.isPresent() && searchParameterMap.get().getSearchTotalMode() == SearchTotalModeEnum.ACCURATE) {
|
if (searchParameterMap.isPresent() && searchParameterMap.get().getSearchTotalMode() == SearchTotalModeEnum.ACCURATE) {
|
||||||
|
@ -487,10 +490,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private PersistedJpaBundleProvider findCachedQuery(SearchParameterMap theParams, String theResourceType, RequestDetails theRequestDetails, String theQueryString, RequestPartitionId theRequestPartitionId) {
|
private PersistedJpaBundleProvider findCachedQuery(SearchParameterMap theParams, String theResourceType, RequestDetails theRequestDetails, String theQueryString, RequestPartitionId theRequestPartitionId) {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
|
||||||
|
|
||||||
// May be null
|
// May be null
|
||||||
return txTemplate.execute(t -> {
|
return myTxService.withRequest(theRequestDetails).execute(() -> {
|
||||||
|
|
||||||
// Interceptor call: STORAGE_PRECHECK_FOR_CACHED_SEARCH
|
// Interceptor call: STORAGE_PRECHECK_FOR_CACHED_SEARCH
|
||||||
HookParams params = new HookParams()
|
HookParams params = new HookParams()
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
|
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
|
@ -48,9 +49,6 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
|
import ca.uhn.fhir.rest.server.util.CompositeInterceptorBroadcaster;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
import javax.persistence.EntityManager;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -79,7 +77,7 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
||||||
private DaoRegistry myDaoRegistry;
|
private DaoRegistry myDaoRegistry;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private PlatformTransactionManager myManagedTxManager;
|
private HapiTransactionService myTxService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
|
@ -89,6 +87,7 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
||||||
|
|
||||||
private int mySyncSize = 250;
|
private int mySyncSize = 250;
|
||||||
|
|
||||||
|
@Override
|
||||||
public IBundleProvider executeQuery(SearchParameterMap theParams, RequestDetails theRequestDetails, String theSearchUuid, ISearchBuilder theSb, Integer theLoadSynchronousUpTo, RequestPartitionId theRequestPartitionId) {
|
public IBundleProvider executeQuery(SearchParameterMap theParams, RequestDetails theRequestDetails, String theSearchUuid, ISearchBuilder theSb, Integer theLoadSynchronousUpTo, RequestPartitionId theRequestPartitionId) {
|
||||||
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(theRequestDetails, theSearchUuid);
|
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(theRequestDetails, theSearchUuid);
|
||||||
searchRuntimeDetails.setLoadSynchronous(true);
|
searchRuntimeDetails.setLoadSynchronous(true);
|
||||||
|
@ -98,10 +97,8 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
||||||
boolean wantCount = theParamWantOnlyCount || theParamOrConfigWantCount;
|
boolean wantCount = theParamWantOnlyCount || theParamOrConfigWantCount;
|
||||||
|
|
||||||
// Execute the query and make sure we return distinct results
|
// Execute the query and make sure we return distinct results
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
return myTxService.withRequest(theRequestDetails).readOnly().execute(() -> {
|
||||||
txTemplate.setReadOnly(theParams.isLoadSynchronous() || theParams.isOffsetQuery());
|
|
||||||
return txTemplate.execute(t -> {
|
|
||||||
|
|
||||||
// Load the results synchronously
|
// Load the results synchronously
|
||||||
final List<JpaPid> pids = new ArrayList<>();
|
final List<JpaPid> pids = new ArrayList<>();
|
||||||
|
|
|
@ -25,14 +25,14 @@ import ca.uhn.fhir.interceptor.api.IInterceptorBroadcaster;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
import ca.uhn.fhir.jpa.model.search.SearchStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.search.ExceptionService;
|
import ca.uhn.fhir.jpa.search.ExceptionService;
|
||||||
import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc;
|
import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc;
|
||||||
import ca.uhn.fhir.jpa.search.cache.ISearchResultCacheSvc;
|
import ca.uhn.fhir.jpa.search.cache.ISearchResultCacheSvc;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.server.IPagingProvider;
|
import ca.uhn.fhir.rest.server.IPagingProvider;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
@ -41,10 +41,11 @@ public class SearchContinuationTask extends SearchTask {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchContinuationTask.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchContinuationTask.class);
|
||||||
|
|
||||||
private final ExceptionService myExceptionSvc;
|
private final ExceptionService myExceptionSvc;
|
||||||
|
private final RequestDetails myRequestDetails;
|
||||||
|
|
||||||
public SearchContinuationTask(
|
public SearchContinuationTask(
|
||||||
SearchTaskParameters theCreationParams,
|
SearchTaskParameters theCreationParams,
|
||||||
PlatformTransactionManager theManagedTxManager,
|
HapiTransactionService theTxService,
|
||||||
FhirContext theContext,
|
FhirContext theContext,
|
||||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||||
SearchBuilderFactory theSearchBuilderFactory,
|
SearchBuilderFactory theSearchBuilderFactory,
|
||||||
|
@ -56,7 +57,7 @@ public class SearchContinuationTask extends SearchTask {
|
||||||
) {
|
) {
|
||||||
super(
|
super(
|
||||||
theCreationParams,
|
theCreationParams,
|
||||||
theManagedTxManager,
|
theTxService,
|
||||||
theContext,
|
theContext,
|
||||||
theInterceptorBroadcaster,
|
theInterceptorBroadcaster,
|
||||||
theSearchBuilderFactory,
|
theSearchBuilderFactory,
|
||||||
|
@ -66,15 +67,14 @@ public class SearchContinuationTask extends SearchTask {
|
||||||
thePagingProvider
|
thePagingProvider
|
||||||
);
|
);
|
||||||
|
|
||||||
|
myRequestDetails = theCreationParams.Request;
|
||||||
myExceptionSvc = theExceptionSvc;
|
myExceptionSvc = theExceptionSvc;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void call() {
|
public Void call() {
|
||||||
try {
|
try {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
myTxService.withRequest(myRequestDetails).execute(() -> {
|
||||||
txTemplate.afterPropertiesSet();
|
|
||||||
txTemplate.execute(t -> {
|
|
||||||
List<JpaPid> previouslyAddedResourcePids = mySearchResultCacheSvc.fetchAllResultPids(getSearch());
|
List<JpaPid> previouslyAddedResourcePids = mySearchResultCacheSvc.fetchAllResultPids(getSearch());
|
||||||
if (previouslyAddedResourcePids == null) {
|
if (previouslyAddedResourcePids == null) {
|
||||||
throw myExceptionSvc.newUnknownSearchException(getSearch().getUuid());
|
throw myExceptionSvc.newUnknownSearchException(getSearch().getUuid());
|
||||||
|
@ -82,8 +82,8 @@ public class SearchContinuationTask extends SearchTask {
|
||||||
|
|
||||||
ourLog.trace("Have {} previously added IDs in search: {}", previouslyAddedResourcePids.size(), getSearch().getUuid());
|
ourLog.trace("Have {} previously added IDs in search: {}", previouslyAddedResourcePids.size(), getSearch().getUuid());
|
||||||
setPreviouslyAddedResourcePids(previouslyAddedResourcePids);
|
setPreviouslyAddedResourcePids(previouslyAddedResourcePids);
|
||||||
return null;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} catch (Throwable e) {
|
} catch (Throwable e) {
|
||||||
ourLog.error("Failure processing search", e);
|
ourLog.error("Failure processing search", e);
|
||||||
getSearch().setFailureMessage(e.getMessage());
|
getSearch().setFailureMessage(e.getMessage());
|
||||||
|
|
|
@ -31,6 +31,7 @@ import ca.uhn.fhir.jpa.api.dao.IDao;
|
||||||
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
||||||
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
import ca.uhn.fhir.jpa.dao.ISearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.entity.Search;
|
import ca.uhn.fhir.jpa.entity.Search;
|
||||||
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
|
import ca.uhn.fhir.jpa.interceptor.JpaPreResourceAccessDetails;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
|
@ -57,14 +58,8 @@ import co.elastic.apm.api.Transaction;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.springframework.orm.jpa.JpaDialect;
|
import org.springframework.transaction.annotation.Isolation;
|
||||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
import org.springframework.orm.jpa.vendor.HibernateJpaDialect;
|
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
|
||||||
import org.springframework.transaction.TransactionDefinition;
|
|
||||||
import org.springframework.transaction.TransactionStatus;
|
|
||||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
|
||||||
import org.springframework.transaction.support.TransactionTemplate;
|
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -123,10 +118,8 @@ public class SearchTask implements Callable<Void> {
|
||||||
private final int mySyncSize;
|
private final int mySyncSize;
|
||||||
private final Integer myLoadingThrottleForUnitTests;
|
private final Integer myLoadingThrottleForUnitTests;
|
||||||
|
|
||||||
private boolean myCustomIsolationSupported;
|
|
||||||
|
|
||||||
// injected beans
|
// injected beans
|
||||||
protected final PlatformTransactionManager myManagedTxManager;
|
protected final HapiTransactionService myTxService;
|
||||||
protected final FhirContext myContext;
|
protected final FhirContext myContext;
|
||||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||||
private final SearchBuilderFactory<JpaPid> mySearchBuilderFactory;
|
private final SearchBuilderFactory<JpaPid> mySearchBuilderFactory;
|
||||||
|
@ -140,7 +133,7 @@ public class SearchTask implements Callable<Void> {
|
||||||
*/
|
*/
|
||||||
public SearchTask(
|
public SearchTask(
|
||||||
SearchTaskParameters theCreationParams,
|
SearchTaskParameters theCreationParams,
|
||||||
PlatformTransactionManager theManagedTxManager,
|
HapiTransactionService theManagedTxManager,
|
||||||
FhirContext theContext,
|
FhirContext theContext,
|
||||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||||
SearchBuilderFactory theSearchBuilderFactory,
|
SearchBuilderFactory theSearchBuilderFactory,
|
||||||
|
@ -150,7 +143,7 @@ public class SearchTask implements Callable<Void> {
|
||||||
IPagingProvider thePagingProvider
|
IPagingProvider thePagingProvider
|
||||||
) {
|
) {
|
||||||
// beans
|
// beans
|
||||||
myManagedTxManager = theManagedTxManager;
|
myTxService = theManagedTxManager;
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||||
mySearchBuilderFactory = theSearchBuilderFactory;
|
mySearchBuilderFactory = theSearchBuilderFactory;
|
||||||
|
@ -174,17 +167,6 @@ public class SearchTask implements Callable<Void> {
|
||||||
mySearchRuntimeDetails.setQueryString(myParams.toNormalizedQueryString(myCallingDao.getContext()));
|
mySearchRuntimeDetails.setQueryString(myParams.toNormalizedQueryString(myCallingDao.getContext()));
|
||||||
myRequestPartitionId = theCreationParams.RequestPartitionId;
|
myRequestPartitionId = theCreationParams.RequestPartitionId;
|
||||||
myParentTransaction = ElasticApm.currentTransaction();
|
myParentTransaction = ElasticApm.currentTransaction();
|
||||||
|
|
||||||
if (myManagedTxManager instanceof JpaTransactionManager) {
|
|
||||||
JpaDialect jpaDialect = ((JpaTransactionManager) myManagedTxManager).getJpaDialect();
|
|
||||||
if (jpaDialect instanceof HibernateJpaDialect) {
|
|
||||||
myCustomIsolationSupported = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!myCustomIsolationSupported) {
|
|
||||||
ourLog.warn("JPA dialect does not support transaction isolation! This can have an impact on search performance.");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -285,23 +267,11 @@ public class SearchTask implements Callable<Void> {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void saveSearch() {
|
public void saveSearch() {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
myTxService.execute(myRequest, null, Propagation.REQUIRES_NEW, Isolation.DEFAULT, ()->doSaveSearch());
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
|
||||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
|
||||||
@Override
|
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theArg0) {
|
|
||||||
doSaveSearch();
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void saveUnsynced(final IResultIterator theResultIter) {
|
private void saveUnsynced(final IResultIterator theResultIter) {
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
myTxService.withRequest(myRequest).execute(()->{
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
|
||||||
@Override
|
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theArg0) {
|
|
||||||
if (mySearch.getId() == null) {
|
if (mySearch.getId() == null) {
|
||||||
doSaveSearch();
|
doSaveSearch();
|
||||||
}
|
}
|
||||||
|
@ -380,8 +350,7 @@ public class SearchTask implements Callable<Void> {
|
||||||
doSaveSearch();
|
doSaveSearch();
|
||||||
|
|
||||||
ourLog.trace("saveUnsynced() - pre-commit");
|
ourLog.trace("saveUnsynced() - pre-commit");
|
||||||
}
|
});
|
||||||
});
|
|
||||||
ourLog.trace("saveUnsynced() - post-commit");
|
ourLog.trace("saveUnsynced() - post-commit");
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -418,19 +387,7 @@ public class SearchTask implements Callable<Void> {
|
||||||
// Create an initial search in the DB and give it an ID
|
// Create an initial search in the DB and give it an ID
|
||||||
saveSearch();
|
saveSearch();
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
myTxService.execute(myRequest, null, Propagation.REQUIRED, Isolation.READ_COMMITTED, ()->doSearch());
|
||||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
|
||||||
|
|
||||||
if (myCustomIsolationSupported) {
|
|
||||||
txTemplate.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED);
|
|
||||||
}
|
|
||||||
|
|
||||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
|
||||||
@Override
|
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) {
|
|
||||||
doSearch();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
mySearchRuntimeDetails.setSearchStatus(mySearch.getStatus());
|
mySearchRuntimeDetails.setSearchStatus(mySearch.getStatus());
|
||||||
if (mySearch.getStatus() == SearchStatusEnum.FINISHED) {
|
if (mySearch.getStatus() == SearchStatusEnum.FINISHED) {
|
||||||
|
@ -549,16 +506,12 @@ public class SearchTask implements Callable<Void> {
|
||||||
|
|
||||||
ourLog.trace("Got count {}", count);
|
ourLog.trace("Got count {}", count);
|
||||||
|
|
||||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
myTxService.withRequest(myRequest).execute(()->{
|
||||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
mySearch.setTotalCount(count.intValue());
|
||||||
@Override
|
if (myParamWantOnlyCount) {
|
||||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theArg0) {
|
mySearch.setStatus(SearchStatusEnum.FINISHED);
|
||||||
mySearch.setTotalCount(count.intValue());
|
|
||||||
if (myParamWantOnlyCount) {
|
|
||||||
mySearch.setStatus(SearchStatusEnum.FINISHED);
|
|
||||||
}
|
|
||||||
doSaveSearch();
|
|
||||||
}
|
}
|
||||||
|
doSaveSearch();
|
||||||
});
|
});
|
||||||
if (myParamWantOnlyCount) {
|
if (myParamWantOnlyCount) {
|
||||||
return;
|
return;
|
||||||
|
|
|
@ -15,7 +15,7 @@ import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
import ca.uhn.fhir.jpa.dao.mdm.MdmExpansionCacheSvc;
|
import ca.uhn.fhir.jpa.dao.mdm.MdmExpansionCacheSvc;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
import ca.uhn.fhir.jpa.model.search.SearchRuntimeDetails;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
|
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -23,7 +23,7 @@ package ca.uhn.fhir.cql.dstu3.provider;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
|
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
|
|
@ -24,7 +24,7 @@ import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
|
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
|
|
@ -2,7 +2,7 @@ package ca.uhn.fhir.cql.dstu3;
|
||||||
|
|
||||||
import ca.uhn.fhir.cql.BaseCqlDstu3Test;
|
import ca.uhn.fhir.cql.BaseCqlDstu3Test;
|
||||||
import ca.uhn.fhir.cql.dstu3.provider.MeasureOperationsProvider;
|
import ca.uhn.fhir.cql.dstu3.provider.MeasureOperationsProvider;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.util.BundleUtil;
|
import ca.uhn.fhir.util.BundleUtil;
|
||||||
import org.hamcrest.Matchers;
|
import org.hamcrest.Matchers;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -21,7 +21,7 @@ import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
import ca.uhn.fhir.jpa.model.entity.NormalizedQuantitySearchLevel;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.search.CompositeSearchParameterTestCases;
|
import ca.uhn.fhir.jpa.search.CompositeSearchParameterTestCases;
|
||||||
import ca.uhn.fhir.jpa.search.QuantitySearchParameterTestCases;
|
import ca.uhn.fhir.jpa.search.QuantitySearchParameterTestCases;
|
||||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||||
|
|
|
@ -17,7 +17,7 @@ import ca.uhn.fhir.jpa.entity.TermValueSet;
|
||||||
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
import ca.uhn.fhir.jpa.entity.TermValueSetPreExpansionStatusEnum;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermCodeSystemStorageSvc;
|
||||||
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
import ca.uhn.fhir.jpa.term.api.ITermDeferredStorageSvc;
|
||||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.term;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.config.TestR4ConfigWithElasticHSearch;
|
import ca.uhn.fhir.jpa.config.TestR4ConfigWithElasticHSearch;
|
||||||
import ca.uhn.fhir.jpa.test.BaseValueSetHSearchExpansionR4Test;
|
import ca.uhn.fhir.jpa.test.BaseValueSetHSearchExpansionR4Test;
|
||||||
|
import ca.uhn.fhir.test.utilities.docker.RequiresDocker;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
|
@ -11,6 +12,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||||
*/
|
*/
|
||||||
@ExtendWith(SpringExtension.class)
|
@ExtendWith(SpringExtension.class)
|
||||||
@ContextConfiguration(classes = TestR4ConfigWithElasticHSearch.class)
|
@ContextConfiguration(classes = TestR4ConfigWithElasticHSearch.class)
|
||||||
|
@RequiresDocker
|
||||||
public class ValueSetHSearchExpansionR4ElasticIT extends BaseValueSetHSearchExpansionR4Test {
|
public class ValueSetHSearchExpansionR4ElasticIT extends BaseValueSetHSearchExpansionR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
|
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
|
||||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
|
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionLoader;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionLoader;
|
||||||
|
|
|
@ -28,7 +28,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.api.pid.HomogeneousResourcePidList;
|
import ca.uhn.fhir.jpa.api.pid.HomogeneousResourcePidList;
|
||||||
import ca.uhn.fhir.jpa.api.pid.IResourcePidList;
|
import ca.uhn.fhir.jpa.api.pid.IResourcePidList;
|
||||||
import ca.uhn.fhir.jpa.api.svc.IGoldenResourceSearchSvc;
|
import ca.uhn.fhir.jpa.api.svc.IGoldenResourceSearchSvc;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||||
|
|
|
@ -26,7 +26,7 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
import ca.uhn.fhir.jpa.model.entity.TagTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||||
|
|
|
@ -24,7 +24,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
|
import ca.uhn.fhir.mdm.svc.MdmSearchParamSvc;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
import ca.uhn.fhir.mdm.api.IMdmSettings;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
|
|
@ -21,7 +21,7 @@ import ca.uhn.fhir.jpa.mdm.svc.MdmMatchLinkSvc;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
|
import ca.uhn.fhir.jpa.partition.IPartitionLookupSvc;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl;
|
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryImpl;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
|
import ca.uhn.fhir.jpa.subscription.match.config.SubscriptionProcessorConfig;
|
||||||
|
|
|
@ -9,7 +9,7 @@ import ca.uhn.fhir.jpa.mdm.helper.testmodels.MDMLinkResults;
|
||||||
import ca.uhn.fhir.jpa.mdm.helper.testmodels.MDMState;
|
import ca.uhn.fhir.jpa.mdm.helper.testmodels.MDMState;
|
||||||
import ca.uhn.fhir.jpa.mdm.helper.testmodels.MdmTestLinkExpression;
|
import ca.uhn.fhir.jpa.mdm.helper.testmodels.MdmTestLinkExpression;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
|
|
|
@ -3,7 +3,6 @@ package ca.uhn.fhir.jpa.mdm.provider;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
|
||||||
import ca.uhn.fhir.mdm.rules.config.MdmSettings;
|
import ca.uhn.fhir.mdm.rules.config.MdmSettings;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||||
|
@ -18,23 +17,18 @@ import org.hl7.fhir.r4.model.StringType;
|
||||||
import org.junit.jupiter.api.AfterEach;
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.Named;
|
import org.junit.jupiter.api.Named;
|
||||||
import org.junit.jupiter.api.Tag;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.params.ParameterizedTest;
|
import org.junit.jupiter.params.ParameterizedTest;
|
||||||
import org.junit.jupiter.params.provider.Arguments;
|
import org.junit.jupiter.params.provider.Arguments;
|
||||||
import org.junit.jupiter.params.provider.MethodSource;
|
import org.junit.jupiter.params.provider.MethodSource;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
import javax.servlet.Servlet;
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.containsString;
|
import static org.hamcrest.Matchers.containsString;
|
||||||
import static org.hamcrest.Matchers.either;
|
import static org.hamcrest.Matchers.either;
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.jupiter.api.Assertions.fail;
|
import static org.junit.jupiter.api.Assertions.fail;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
|
@ -49,7 +49,7 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testCreateLinkWithMatchResultOnSamePartition() {
|
public void testCreateLinkWithMatchResultOnSamePartition() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
assertLinkCount(1);
|
assertLinkCount(1);
|
||||||
|
|
||||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||||
|
@ -73,8 +73,8 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testCreateLinkWithMatchResultOnDifferentPartitions() {
|
public void testCreateLinkWithMatchResultOnDifferentPartitions() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||||
assertLinkCount(1);
|
assertLinkCount(1);
|
||||||
|
|
||||||
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package ca.uhn.fhir.jpa.mdm.provider;
|
package ca.uhn.fhir.jpa.mdm.provider;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.mdm.api.MdmConstants;
|
import ca.uhn.fhir.mdm.api.MdmConstants;
|
||||||
import com.google.common.collect.Ordering;
|
import com.google.common.collect.Ordering;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
|
|
@ -47,6 +47,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
||||||
myToGoldenPatientId = new StringType(myToGoldenPatient.getIdElement().getValue());
|
myToGoldenPatientId = new StringType(myToGoldenPatient.getIdElement().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void after() throws IOException {
|
public void after() throws IOException {
|
||||||
myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
|
myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
|
||||||
|
@ -112,7 +113,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testMergeOnSamePartition() {
|
public void testMergeOnSamePartition() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||||
Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
||||||
StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
|
StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
|
||||||
|
@ -147,9 +148,9 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testMergeOnDifferentPartitions() {
|
public void testMergeOnDifferentPartitions() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||||
Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
||||||
StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
|
StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
|
||||||
|
|
|
@ -43,6 +43,7 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
|
||||||
myTargetPatientId = new StringType(myTargetPatient.getIdElement().getValue());
|
myTargetPatientId = new StringType(myTargetPatient.getIdElement().getValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void after() throws IOException {
|
public void after() throws IOException {
|
||||||
myPartitionSettings.setPartitioningEnabled(false);
|
myPartitionSettings.setPartitioningEnabled(false);
|
||||||
|
@ -86,7 +87,7 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
|
||||||
@Test
|
@Test
|
||||||
public void testNotDuplicateGoldenResourceOnSamePartition() {
|
public void testNotDuplicateGoldenResourceOnSamePartition() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||||
Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
||||||
StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
|
StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
|
||||||
|
@ -106,9 +107,9 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
|
||||||
@Test
|
@Test
|
||||||
public void testNotDuplicateGoldenResourceOnDifferentPartitions() {
|
public void testNotDuplicateGoldenResourceOnDifferentPartitions() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||||
Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
||||||
StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
|
StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
|
||||||
|
|
|
@ -59,7 +59,7 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateLinkMatchOnSamePartition() {
|
public void testUpdateLinkMatchOnSamePartition() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||||
Patient patient = createPatientAndUpdateLinksOnPartition(buildFrankPatient(), requestPartitionId);
|
Patient patient = createPatientAndUpdateLinksOnPartition(buildFrankPatient(), requestPartitionId);
|
||||||
StringType patientId = new StringType(patient.getIdElement().getValue());
|
StringType patientId = new StringType(patient.getIdElement().getValue());
|
||||||
|
@ -84,8 +84,8 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateLinkMatchOnDifferentPartitions() {
|
public void testUpdateLinkMatchOnDifferentPartitions() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||||
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
||||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||||
Patient patient = createPatientOnPartition(buildFrankPatient(), true, false, requestPartitionId1);
|
Patient patient = createPatientOnPartition(buildFrankPatient(), true, false, requestPartitionId1);
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
||||||
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
import ca.uhn.fhir.interceptor.api.IInterceptorService;
|
||||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
|
import ca.uhn.fhir.mdm.api.IMdmSubmitSvc;
|
||||||
import ca.uhn.fhir.mdm.svc.MdmSubmitSvcImpl;
|
import ca.uhn.fhir.mdm.svc.MdmSubmitSvcImpl;
|
||||||
import ca.uhn.test.concurrency.PointcutLatch;
|
import ca.uhn.test.concurrency.PointcutLatch;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
import ca.uhn.fhir.jpa.mdm.provider.BaseLinkR4Test;
|
import ca.uhn.fhir.jpa.mdm.provider.BaseLinkR4Test;
|
||||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.test.Batch2JobHelper;
|
import ca.uhn.fhir.jpa.test.Batch2JobHelper;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
|
import ca.uhn.fhir.mdm.api.IMdmControllerSvc;
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||||
|
@ -65,8 +65,8 @@ public class MdmControllerSvcImplTest extends BaseLinkR4Test {
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
super.before();
|
super.before();
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||||
myInterceptorService.registerInterceptor(myPartitionInterceptor);
|
myInterceptorService.registerInterceptor(myPartitionInterceptor);
|
||||||
myMdmSettings.setEnabled(true);
|
myMdmSettings.setEnabled(true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,7 +3,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmLink;
|
import ca.uhn.fhir.mdm.api.IMdmLink;
|
||||||
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
|
import ca.uhn.fhir.mdm.api.IMdmLinkUpdaterSvc;
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
|
|
|
@ -7,9 +7,11 @@ import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
import ca.uhn.fhir.mdm.api.MdmMatchOutcome;
|
||||||
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
import ca.uhn.fhir.mdm.model.MdmTransactionContext;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.MATCH;
|
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.MATCH;
|
||||||
|
@ -22,6 +24,13 @@ class MdmLinkUpdaterSvcImplTest extends BaseMdmR4Test {
|
||||||
@Autowired
|
@Autowired
|
||||||
private IMdmLinkUpdaterSvc myMdmLinkUpdaterSvc;
|
private IMdmLinkUpdaterSvc myMdmLinkUpdaterSvc;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@AfterEach
|
||||||
|
public void after() throws IOException {
|
||||||
|
super.after();
|
||||||
|
myMdmSettings.getMdmRules().setVersion("1");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUpdateLinkNoMatch() {
|
public void testUpdateLinkNoMatch() {
|
||||||
// setup
|
// setup
|
||||||
|
|
|
@ -4,7 +4,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
import ca.uhn.fhir.mdm.util.MdmResourceUtil;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
|
@ -25,6 +25,7 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
|
||||||
@Autowired
|
@Autowired
|
||||||
MdmResourceDaoSvc myResourceDaoSvc;
|
MdmResourceDaoSvc myResourceDaoSvc;
|
||||||
|
|
||||||
|
@Override
|
||||||
@AfterEach
|
@AfterEach
|
||||||
public void after() throws IOException {
|
public void after() throws IOException {
|
||||||
myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
|
myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
|
||||||
|
@ -63,7 +64,7 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testSearchGoldenResourceOnSamePartition() {
|
public void testSearchGoldenResourceOnSamePartition() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||||
Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
||||||
Patient goodSourcePatient = addExternalEID(patientOnPartition, TEST_EID);
|
Patient goodSourcePatient = addExternalEID(patientOnPartition, TEST_EID);
|
||||||
|
@ -79,9 +80,9 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testSearchGoldenResourceOnDifferentPartitions() {
|
public void testSearchGoldenResourceOnDifferentPartitions() {
|
||||||
myPartitionSettings.setPartitioningEnabled(true);
|
myPartitionSettings.setPartitioningEnabled(true);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||||
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
||||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||||
Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
||||||
Patient goodSourcePatient = addExternalEID(patientOnPartition, TEST_EID);
|
Patient goodSourcePatient = addExternalEID(patientOnPartition, TEST_EID);
|
||||||
|
|
|
@ -6,7 +6,7 @@ import ca.uhn.fhir.batch2.model.JobInstance;
|
||||||
import ca.uhn.fhir.jpa.entity.MdmLink;
|
import ca.uhn.fhir.jpa.entity.MdmLink;
|
||||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||||
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
|
import ca.uhn.fhir.jpa.mdm.helper.MdmHelperR4;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
import ca.uhn.fhir.mdm.api.MdmLinkSourceEnum;
|
||||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.model.dao;
|
package ca.uhn.fhir.jpa.model.dao;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Model
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
import ca.uhn.fhir.rest.api.server.storage.BaseResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.BaseResourcePersistentId;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
|
@ -0,0 +1,117 @@
|
||||||
|
package ca.uhn.fhir.jpa.model.dialect;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Model
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||||
|
import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
|
import org.apache.commons.lang3.Validate;
|
||||||
|
import org.hibernate.HibernateException;
|
||||||
|
import org.hibernate.MappingException;
|
||||||
|
import org.hibernate.boot.model.relational.Database;
|
||||||
|
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
|
||||||
|
import org.hibernate.boot.registry.StandardServiceInitiator;
|
||||||
|
import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl;
|
||||||
|
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||||
|
import org.hibernate.id.BulkInsertionCapableIdentifierGenerator;
|
||||||
|
import org.hibernate.id.IdentifierGenerator;
|
||||||
|
import org.hibernate.id.PersistentIdentifierGenerator;
|
||||||
|
import org.hibernate.id.enhanced.SequenceStyleGenerator;
|
||||||
|
import org.hibernate.id.enhanced.StandardOptimizerDescriptor;
|
||||||
|
import org.hibernate.service.Service;
|
||||||
|
import org.hibernate.service.ServiceRegistry;
|
||||||
|
import org.hibernate.service.spi.ServiceRegistryImplementor;
|
||||||
|
import org.hibernate.type.Type;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.ObjectUtils.defaultIfNull;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is a sequence generator that wraps the Hibernate default sequence generator {@link SequenceStyleGenerator}
|
||||||
|
* and by default will therefore work exactly as the default would, but allows for customization.
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class HapiSequenceStyleGenerator implements IdentifierGenerator, PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator {
|
||||||
|
private final SequenceStyleGenerator myGen = new SequenceStyleGenerator();
|
||||||
|
@Autowired
|
||||||
|
private ModelConfig myModelConfig;
|
||||||
|
private ISequenceValueMassager myIdMassager;
|
||||||
|
private boolean myConfigured;
|
||||||
|
private String myGeneratorName;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsBulkInsertionIdentifierGeneration() {
|
||||||
|
return myGen.supportsBulkInsertionIdentifierGeneration();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String determineBulkInsertionIdentifierGenerationSelectFragment(SqlStringGenerationContext theContext) {
|
||||||
|
return myGen.determineBulkInsertionIdentifierGenerationSelectFragment(theContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Serializable generate(SharedSessionContractImplementor theSession, Object theObject) throws HibernateException {
|
||||||
|
Long next = (Long) myGen.generate(theSession, theObject);
|
||||||
|
return myIdMassager.massage(myGeneratorName, next);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(Type theType, Properties theParams, ServiceRegistry theServiceRegistry) throws MappingException {
|
||||||
|
|
||||||
|
// Instantiate the ID massager
|
||||||
|
// ModelConfig should only be null when running in the DDL generation maven plugin
|
||||||
|
if (myModelConfig != null) {
|
||||||
|
myIdMassager = ReflectionUtil.newInstance(myModelConfig.getSequenceValueMassagerClass());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a HAPI FHIR sequence style generator
|
||||||
|
myGeneratorName = theParams.getProperty(IdentifierGenerator.GENERATOR_NAME);
|
||||||
|
Validate.notBlank(myGeneratorName, "No generator name found");
|
||||||
|
|
||||||
|
Properties props = new Properties(theParams);
|
||||||
|
props.put(SequenceStyleGenerator.OPT_PARAM, StandardOptimizerDescriptor.POOLED.getExternalName());
|
||||||
|
props.put(SequenceStyleGenerator.INITIAL_PARAM, "1");
|
||||||
|
props.put(SequenceStyleGenerator.INCREMENT_PARAM, "50");
|
||||||
|
|
||||||
|
myGen.configure(theType, props, theServiceRegistry);
|
||||||
|
|
||||||
|
myConfigured = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerExportables(Database database) {
|
||||||
|
myGen.registerExportables(database);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void initialize(SqlStringGenerationContext context) {
|
||||||
|
myGen.initialize(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean supportsJdbcBatchInserts() {
|
||||||
|
return myGen.supportsJdbcBatchInserts();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.dao.tx;
|
package ca.uhn.fhir.jpa.model.dialect;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
* HAPI FHIR JPA Server
|
* HAPI FHIR JPA Model
|
||||||
* %%
|
* %%
|
||||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||||
* %%
|
* %%
|
||||||
|
@ -20,18 +20,25 @@ package ca.uhn.fhir.jpa.dao.tx;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
|
|
||||||
import static java.lang.annotation.ElementType.METHOD;
|
|
||||||
import static java.lang.annotation.ElementType.TYPE;
|
|
||||||
import static java.lang.annotation.RetentionPolicy.RUNTIME;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see HapiTransactionalAspect
|
* This is an internal API and may change or disappear without notice
|
||||||
* @since 5.1.0
|
*
|
||||||
|
* Implementations of this interface can modify the automatically generated sequence values created by hibernate seuqnece generator
|
||||||
*/
|
*/
|
||||||
@Retention(RUNTIME)
|
public interface ISequenceValueMassager {
|
||||||
@Target({METHOD, TYPE})
|
|
||||||
public @interface HapiTransactional {
|
Long massage(String theGeneratorName, Long theId);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
final class NoopSequenceValueMassager implements ISequenceValueMassager {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long massage(String theGeneratorName, Long theId) {
|
||||||
|
return theId;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -1,5 +1,25 @@
|
||||||
package ca.uhn.fhir.jpa.model.entity;
|
package ca.uhn.fhir.jpa.model.entity;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR JPA Model
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.model.entity;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.ParserOptions;
|
import ca.uhn.fhir.context.ParserOptions;
|
||||||
import ca.uhn.fhir.i18n.Msg;
|
import ca.uhn.fhir.i18n.Msg;
|
||||||
|
import ca.uhn.fhir.jpa.model.dialect.ISequenceValueMassager;
|
||||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ResponseTerminologyTranslationSvc;
|
import ca.uhn.fhir.rest.server.interceptor.ResponseTerminologyTranslationSvc;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
@ -111,10 +112,9 @@ public class ModelConfig {
|
||||||
*/
|
*/
|
||||||
private boolean myUseOrdinalDatesForDayPrecisionSearches = true;
|
private boolean myUseOrdinalDatesForDayPrecisionSearches = true;
|
||||||
private boolean mySuppressStringIndexingInTokens = false;
|
private boolean mySuppressStringIndexingInTokens = false;
|
||||||
|
private Class<? extends ISequenceValueMassager> mySequenceValueMassagerClass;
|
||||||
private IPrimitiveType<Date> myPeriodIndexStartOfTime;
|
private IPrimitiveType<Date> myPeriodIndexStartOfTime;
|
||||||
private IPrimitiveType<Date> myPeriodIndexEndOfTime;
|
private IPrimitiveType<Date> myPeriodIndexEndOfTime;
|
||||||
|
|
||||||
private NormalizedQuantitySearchLevel myNormalizedQuantitySearchLevel;
|
private NormalizedQuantitySearchLevel myNormalizedQuantitySearchLevel;
|
||||||
private Set<String> myAutoVersionReferenceAtPaths = Collections.emptySet();
|
private Set<String> myAutoVersionReferenceAtPaths = Collections.emptySet();
|
||||||
private Map<String, Set<String>> myTypeToAutoVersionReferenceAtPaths = Collections.emptyMap();
|
private Map<String, Set<String>> myTypeToAutoVersionReferenceAtPaths = Collections.emptyMap();
|
||||||
|
@ -124,16 +124,35 @@ public class ModelConfig {
|
||||||
private boolean myAllowMdmExpansion = false;
|
private boolean myAllowMdmExpansion = false;
|
||||||
private boolean myAutoSupportDefaultSearchParams = true;
|
private boolean myAutoSupportDefaultSearchParams = true;
|
||||||
private boolean myIndexIdentifierOfType = false;
|
private boolean myIndexIdentifierOfType = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
*/
|
*/
|
||||||
public ModelConfig() {
|
public ModelConfig() {
|
||||||
|
setSequenceValueMassagerClass(ISequenceValueMassager.NoopSequenceValueMassager.class);
|
||||||
setPeriodIndexStartOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_START_OF_TIME));
|
setPeriodIndexStartOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_START_OF_TIME));
|
||||||
setPeriodIndexEndOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_END_OF_TIME));
|
setPeriodIndexEndOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_END_OF_TIME));
|
||||||
setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
setNormalizedQuantitySearchLevel(NormalizedQuantitySearchLevel.NORMALIZED_QUANTITY_SEARCH_NOT_SUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an internal API and may change or disappear without notice
|
||||||
|
*
|
||||||
|
* @since 6.2.0
|
||||||
|
*/
|
||||||
|
public Class<? extends ISequenceValueMassager> getSequenceValueMassagerClass() {
|
||||||
|
return mySequenceValueMassagerClass;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is an internal API and may change or disappear without notice
|
||||||
|
*
|
||||||
|
* @since 6.2.0
|
||||||
|
*/
|
||||||
|
public void setSequenceValueMassagerClass(Class<? extends ISequenceValueMassager> theSequenceValueMassagerClass) {
|
||||||
|
Validate.notNull(theSequenceValueMassagerClass, "theSequenceValueMassagerClass must not be null");
|
||||||
|
mySequenceValueMassagerClass = theSequenceValueMassagerClass;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to <code>true</code> (default is <code>false</code>) the
|
* If set to <code>true</code> (default is <code>false</code>) the
|
||||||
* <code>:of-type</code> modifier on token search parameters for
|
* <code>:of-type</code> modifier on token search parameters for
|
||||||
|
@ -887,18 +906,6 @@ public class ModelConfig {
|
||||||
myAutoSupportDefaultSearchParams = theAutoSupportDefaultSearchParams;
|
myAutoSupportDefaultSearchParams = theAutoSupportDefaultSearchParams;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
|
||||||
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
|
||||||
|
|
||||||
int starIdx = theUrl.indexOf('*');
|
|
||||||
if (starIdx != -1) {
|
|
||||||
if (starIdx != theUrl.length() - 1) {
|
|
||||||
throw new IllegalArgumentException(Msg.code(1525) + "Base URL wildcard character (*) can only appear at the end of the string: " + theUrl);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If enabled, the server will support cross-partition subscription.
|
* If enabled, the server will support cross-partition subscription.
|
||||||
* This subscription will be the responsible for all the requests from all the partitions on this server.
|
* This subscription will be the responsible for all the requests from all the partitions on this server.
|
||||||
|
@ -929,4 +936,16 @@ public class ModelConfig {
|
||||||
myCrossPartitionSubscription = theAllowCrossPartitionSubscription;
|
myCrossPartitionSubscription = theAllowCrossPartitionSubscription;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static void validateTreatBaseUrlsAsLocal(String theUrl) {
|
||||||
|
Validate.notBlank(theUrl, "Base URL must not be null or empty");
|
||||||
|
|
||||||
|
int starIdx = theUrl.indexOf('*');
|
||||||
|
if (starIdx != -1) {
|
||||||
|
if (starIdx != theUrl.length() - 1) {
|
||||||
|
throw new IllegalArgumentException(Msg.code(1525) + "Base URL wildcard character (*) can only appear at the end of the string: " + theUrl);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,20 +60,20 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||||
})
|
})
|
||||||
/**
|
/**
|
||||||
* Support UCUM service
|
* Support UCUM service
|
||||||
* @since 5.3.0
|
* @since 5.3.0
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIndexedSearchParamQuantity {
|
public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIndexedSearchParamQuantity {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@SequenceGenerator(name = "SEQ_SPIDX_QUANTITY_NRML", sequenceName = "SEQ_SPIDX_QUANTITY_NRML")
|
@SequenceGenerator(name = "SEQ_SPIDX_QUANTITY_NRML", sequenceName = "SEQ_SPIDX_QUANTITY_NRML")
|
||||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY_NRML")
|
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_SPIDX_QUANTITY_NRML")
|
||||||
@Column(name = "SP_ID")
|
@Column(name = "SP_ID")
|
||||||
private Long myId;
|
private Long myId;
|
||||||
|
|
||||||
// Changed to double here for storing the value after converted to the CanonicalForm due to BigDecimal maps NUMBER(19,2)
|
// Changed to double here for storing the value after converted to the CanonicalForm due to BigDecimal maps NUMBER(19,2)
|
||||||
// The precision may lost even to store 1.2cm which is 0.012m in the CanonicalForm
|
// The precision may lost even to store 1.2cm which is 0.012m in the CanonicalForm
|
||||||
@Column(name = "SP_VALUE", nullable = true)
|
@Column(name = "SP_VALUE", nullable = true)
|
||||||
@ScaledNumberField
|
@ScaledNumberField
|
||||||
|
@ -110,7 +110,7 @@ public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIn
|
||||||
setHashIdentityAndUnits(source.getHashIdentityAndUnits());
|
setHashIdentityAndUnits(source.getHashIdentityAndUnits());
|
||||||
setHashIdentitySystemAndUnits(source.getHashIdentitySystemAndUnits());
|
setHashIdentitySystemAndUnits(source.getHashIdentitySystemAndUnits());
|
||||||
}
|
}
|
||||||
|
|
||||||
//- myValue
|
//- myValue
|
||||||
public Double getValue() {
|
public Double getValue() {
|
||||||
return myValue;
|
return myValue;
|
||||||
|
@ -134,7 +134,7 @@ public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIn
|
||||||
public void setId(Long theId) {
|
public void setId(Long theId) {
|
||||||
myId = theId;
|
myId = theId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IQueryParameterType toQueryParameterType() {
|
public IQueryParameterType toQueryParameterType() {
|
||||||
return new QuantityParam(null, getValue(), getSystem(), getUnits());
|
return new QuantityParam(null, getValue(), getSystem(), getUnits());
|
||||||
|
@ -175,10 +175,10 @@ public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIn
|
||||||
b.append(getValue(), obj.getValue());
|
b.append(getValue(), obj.getValue());
|
||||||
return b.isEquals();
|
return b.isEquals();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean matches(IQueryParameterType theParam) {
|
public boolean matches(IQueryParameterType theParam) {
|
||||||
|
|
||||||
if (!(theParam instanceof QuantityParam)) {
|
if (!(theParam instanceof QuantityParam)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -191,14 +191,14 @@ public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIn
|
||||||
if (quantityValue != null)
|
if (quantityValue != null)
|
||||||
quantityDoubleValue = quantityValue.doubleValue();
|
quantityDoubleValue = quantityValue.doubleValue();
|
||||||
String quantityUnits = defaultString(quantity.getUnits());
|
String quantityUnits = defaultString(quantity.getUnits());
|
||||||
|
|
||||||
//-- convert the value/unit to the canonical form if any, otherwise store the original value/units pair
|
//-- convert the value/unit to the canonical form if any, otherwise store the original value/units pair
|
||||||
Pair canonicalForm = UcumServiceUtil.getCanonicalForm(quantitySystem, quantityValue, quantityUnits);
|
Pair canonicalForm = UcumServiceUtil.getCanonicalForm(quantitySystem, quantityValue, quantityUnits);
|
||||||
if (canonicalForm != null) {
|
if (canonicalForm != null) {
|
||||||
quantityDoubleValue = Double.parseDouble(canonicalForm.getValue().asDecimal());
|
quantityDoubleValue = Double.parseDouble(canonicalForm.getValue().asDecimal());
|
||||||
quantityUnits = canonicalForm.getCode();
|
quantityUnits = canonicalForm.getCode();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only match on system if it wasn't specified
|
// Only match on system if it wasn't specified
|
||||||
if (quantitySystem == null && isBlank(quantityUnits)) {
|
if (quantitySystem == null && isBlank(quantityUnits)) {
|
||||||
if (Objects.equals(getValue(), quantityDoubleValue)) {
|
if (Objects.equals(getValue(), quantityDoubleValue)) {
|
||||||
|
@ -224,7 +224,7 @@ public class ResourceIndexedSearchParamQuantityNormalized extends BaseResourceIn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
import org.hibernate.Session;
|
import org.hibernate.Session;
|
||||||
import org.hibernate.annotations.GenerationTime;
|
import org.hibernate.annotations.GenerationTime;
|
||||||
import org.hibernate.annotations.GeneratorType;
|
import org.hibernate.annotations.GeneratorType;
|
||||||
|
@ -63,7 +64,7 @@ import javax.persistence.OneToMany;
|
||||||
import javax.persistence.OneToOne;
|
import javax.persistence.OneToOne;
|
||||||
import javax.persistence.PrePersist;
|
import javax.persistence.PrePersist;
|
||||||
import javax.persistence.PreUpdate;
|
import javax.persistence.PreUpdate;
|
||||||
import javax.persistence.SequenceGenerator;
|
import org.hibernate.annotations.GenericGenerator;
|
||||||
import javax.persistence.Table;
|
import javax.persistence.Table;
|
||||||
import javax.persistence.Transient;
|
import javax.persistence.Transient;
|
||||||
import javax.persistence.Version;
|
import javax.persistence.Version;
|
||||||
|
@ -113,7 +114,7 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
||||||
private boolean myHasLinks;
|
private boolean myHasLinks;
|
||||||
|
|
||||||
@Id
|
@Id
|
||||||
@SequenceGenerator(name = "SEQ_RESOURCE_ID", sequenceName = "SEQ_RESOURCE_ID")
|
@GenericGenerator(name = "SEQ_RESOURCE_ID", strategy = "ca.uhn.fhir.jpa.model.dialect.HapiSequenceStyleGenerator")
|
||||||
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESOURCE_ID")
|
@GeneratedValue(strategy = GenerationType.AUTO, generator = "SEQ_RESOURCE_ID")
|
||||||
@Column(name = "RES_ID")
|
@Column(name = "RES_ID")
|
||||||
@GenericField(projectable = Projectable.YES)
|
@GenericField(projectable = Projectable.YES)
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.deliver.BaseSubscriptionDeliverySubscriber;
|
import ca.uhn.fhir.jpa.subscription.match.deliver.BaseSubscriptionDeliverySubscriber;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||||
|
|
|
@ -23,7 +23,7 @@ package ca.uhn.fhir.jpa.subscription.match.matcher.subscriber;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionConstants;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionConstants;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscriptionChannelType;
|
||||||
|
|
|
@ -24,7 +24,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
|
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
|
||||||
|
|
|
@ -27,7 +27,7 @@ import ca.uhn.fhir.jpa.cache.IResourceChangeListener;
|
||||||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCache;
|
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCache;
|
||||||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.searchparam.retry.Retrier;
|
import ca.uhn.fhir.jpa.searchparam.retry.Retrier;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionActivatingSubscriber;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionActivatingSubscriber;
|
||||||
|
|
|
@ -29,7 +29,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionMatchingStrategy;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionCriteriaParser;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionCriteriaParser;
|
||||||
|
|
|
@ -32,7 +32,7 @@ import ca.uhn.fhir.jpa.api.svc.ISearchSvc;
|
||||||
import ca.uhn.fhir.jpa.model.sched.HapiJob;
|
import ca.uhn.fhir.jpa.model.sched.HapiJob;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
import ca.uhn.fhir.jpa.model.sched.ScheduledJobDefinition;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.IResourceModifiedConsumer;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.IResourceModifiedConsumer;
|
||||||
|
|
|
@ -22,7 +22,7 @@ package ca.uhn.fhir.jpa.subscription.util;
|
||||||
|
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
import ca.uhn.fhir.jpa.model.entity.PartitionablePartitionId;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
import ca.uhn.fhir.jpa.subscription.model.CanonicalSubscription;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
import ca.uhn.fhir.jpa.api.config.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.matching.SubscriptionStrategyEvaluator;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionConstants;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionConstants;
|
||||||
|
|
|
@ -4,7 +4,7 @@ import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionCanonicalizer;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
|
import ca.uhn.fhir.jpa.subscription.match.registry.SubscriptionRegistry;
|
||||||
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
|
import ca.uhn.fhir.jpa.subscription.model.ResourceModifiedJsonMessage;
|
||||||
|
|
|
@ -6,7 +6,7 @@ import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCache;
|
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerCache;
|
||||||
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
import ca.uhn.fhir.jpa.cache.IResourceChangeListenerRegistry;
|
||||||
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
import ca.uhn.fhir.jpa.model.sched.ISchedulerService;
|
||||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionActivatingSubscriber;
|
import ca.uhn.fhir.jpa.subscription.match.matcher.subscriber.SubscriptionActivatingSubscriber;
|
||||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
<parent>
|
<parent>
|
||||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||||
<artifactId>hapi-deployable-pom</artifactId>
|
<artifactId>hapi-deployable-pom</artifactId>
|
||||||
<version>6.3.4-SNAPSHOT</version>
|
<version>6.3.5-SNAPSHOT</version>
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||||
</parent>
|
</parent>
|
||||||
|
|
||||||
|
|
|
@ -6,12 +6,14 @@ import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
import ca.uhn.fhir.jpa.dao.IResultIterator;
|
||||||
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
import ca.uhn.fhir.jpa.dao.SearchBuilderFactory;
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
import ca.uhn.fhir.jpa.model.dao.JpaPid;
|
||||||
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
import ca.uhn.fhir.jpa.search.builder.SearchBuilder;
|
||||||
import ca.uhn.fhir.jpa.util.BaseIterator;
|
import ca.uhn.fhir.jpa.util.BaseIterator;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.mockito.Answers;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.Spy;
|
import org.mockito.Spy;
|
||||||
import org.mockito.stubbing.Answer;
|
import org.mockito.stubbing.Answer;
|
||||||
|
@ -31,9 +33,8 @@ public class BaseSearchSvc {
|
||||||
protected int myExpectedNumberOfSearchBuildersCreated = 2;
|
protected int myExpectedNumberOfSearchBuildersCreated = 2;
|
||||||
@Mock
|
@Mock
|
||||||
protected SearchBuilderFactory<JpaPid> mySearchBuilderFactory;
|
protected SearchBuilderFactory<JpaPid> mySearchBuilderFactory;
|
||||||
|
@Spy
|
||||||
@Mock
|
protected HapiTransactionService myTransactionService = new MockHapiTransactionService();
|
||||||
protected PlatformTransactionManager myTxManager;
|
|
||||||
@Mock
|
@Mock
|
||||||
protected SearchBuilder mySearchBuilder;
|
protected SearchBuilder mySearchBuilder;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
package ca.uhn.fhir.jpa.search;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.dao.tx.HapiTransactionService;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import ca.uhn.fhir.rest.api.server.storage.TransactionDetails;
|
||||||
|
import org.springframework.transaction.annotation.Isolation;
|
||||||
|
import org.springframework.transaction.annotation.Propagation;
|
||||||
|
import org.springframework.transaction.support.TransactionCallback;
|
||||||
|
|
||||||
|
import javax.annotation.Nonnull;
|
||||||
|
import javax.annotation.Nullable;
|
||||||
|
import java.util.concurrent.Callable;
|
||||||
|
|
||||||
|
public class MockHapiTransactionService extends HapiTransactionService {
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
@Override
|
||||||
|
protected <T> T doExecute(ExecutionBuilder theExecutionBuilder, TransactionCallback<T> theCallback) {
|
||||||
|
return theCallback.doInTransaction(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue