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>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -111,6 +111,7 @@
|
|||
<ignoredResourcePattern>.*\.txt$</ignoredResourcePattern>
|
||||
<ignoredResourcePattern>.*\.html$</ignoredResourcePattern>
|
||||
<ignoredResourcePattern>schemaorg_apache_xmlbeans.*</ignoredResourcePattern>
|
||||
<ignoredResource>classpath.index</ignoredResource>
|
||||
<ignoredResource>javac.bat</ignoredResource>
|
||||
<ignoredResource>about.html</ignoredResource>
|
||||
<ignoredResource>changelog.xml</ignoredResource>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -1898,6 +1898,8 @@ public enum Pointcut implements IPointcut {
|
|||
* <p>
|
||||
* Hooks must return an instance of <code>ca.uhn.fhir.interceptor.model.RequestPartitionId</code>.
|
||||
* </p>
|
||||
*
|
||||
* @see #STORAGE_PARTITION_IDENTIFY_ANY For an alternative that is not read/write specific
|
||||
*/
|
||||
STORAGE_PARTITION_IDENTIFY_CREATE(
|
||||
// Return type
|
||||
|
@ -1938,6 +1940,8 @@ public enum Pointcut implements IPointcut {
|
|||
* <p>
|
||||
* Hooks must return an instance of <code>ca.uhn.fhir.interceptor.model.RequestPartitionId</code>.
|
||||
* </p>
|
||||
*
|
||||
* @see #STORAGE_PARTITION_IDENTIFY_ANY For an alternative that is not read/write specific
|
||||
*/
|
||||
STORAGE_PARTITION_IDENTIFY_READ(
|
||||
// Return type
|
||||
|
@ -1948,6 +1952,95 @@ public enum Pointcut implements IPointcut {
|
|||
"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>
|
||||
* 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.stream.Collectors;
|
||||
|
||||
// TODO: JA maybe add an enummap for pointcuts registered?
|
||||
public abstract class BaseInterceptorService<POINTCUT extends IPointcut> implements IBaseInterceptorService<POINTCUT>, IBaseInterceptorBroadcaster<POINTCUT> {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseInterceptorService.class);
|
||||
private final List<Object> myInterceptors = new ArrayList<>();
|
||||
|
|
|
@ -4,14 +4,14 @@
|
|||
<modelVersion>4.0.0</modelVersion>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-bom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<packaging>pom</packaging>
|
||||
<name>HAPI FHIR BOM</name>
|
||||
|
||||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-cli</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../../hapi-deployable-pom</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</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 href="/hapi-fhir/docs/images/job-definition.svg"/>
|
||||
<img src="/hapi-fhir/docs/images/job-definition.svg"/>
|
||||
|
||||
### Submitting a Job
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
|
|
@ -20,75 +20,12 @@ package ca.uhn.fhir.jpa.util;
|
|||
* #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.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.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 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
|
||||
|
@ -97,288 +34,6 @@ public class TestUtil {
|
|||
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) {
|
||||
return new InstantType(new Date(resource.getMeta().getLastUpdated().getTime()));
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
@ -417,7 +417,7 @@
|
|||
<plugins>
|
||||
<plugin>
|
||||
<groupId>de.jpdigital</groupId>
|
||||
<artifactId>hibernate54-ddl-maven-plugin</artifactId>
|
||||
<artifactId>hibernate56-ddl-maven-plugin</artifactId>
|
||||
<configuration>
|
||||
<dialects>
|
||||
<param>h2</param>
|
||||
|
@ -460,6 +460,11 @@
|
|||
<artifactId>hapi-fhir-jpaserver-model</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-core</artifactId>
|
||||
<version>${hibernate_version}</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</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.ISchedulerService;
|
||||
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.hl7.fhir.instance.model.api.IBaseBinary;
|
||||
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.model.dao.JpaPid;
|
||||
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.util.QueryChunker;
|
||||
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.model.dao.JpaPid;
|
||||
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.util.QueryChunker;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
|
|
@ -231,7 +231,7 @@ public class JpaConfig {
|
|||
@Lazy
|
||||
@Bean
|
||||
public ThreadSafeResourceDeleterSvc safeDeleter(DaoRegistry theDaoRegistry, IInterceptorBroadcaster theInterceptorBroadcaster, HapiTransactionService hapiTransactionService) {
|
||||
return new ThreadSafeResourceDeleterSvc(theDaoRegistry, theInterceptorBroadcaster, hapiTransactionService.getTransactionManager());
|
||||
return new ThreadSafeResourceDeleterSvc(theDaoRegistry, theInterceptorBroadcaster, hapiTransactionService);
|
||||
}
|
||||
|
||||
@Lazy
|
||||
|
@ -661,7 +661,7 @@ public class JpaConfig {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public IIdHelperService idHelperService () {
|
||||
public IIdHelperService idHelperService() {
|
||||
return new IdHelperService();
|
||||
}
|
||||
|
||||
|
@ -767,7 +767,7 @@ public class JpaConfig {
|
|||
}
|
||||
|
||||
@Bean
|
||||
public ISynchronousSearchSvc synchronousSearchSvc(){
|
||||
public ISynchronousSearchSvc synchronousSearchSvc() {
|
||||
return new SynchronousSearchSvcImpl();
|
||||
}
|
||||
|
||||
|
|
|
@ -38,8 +38,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
|
|||
@EnableTransactionManagement
|
||||
@Import({
|
||||
FhirContextDstu2Config.class,
|
||||
GeneratedDaoAndResourceProviderConfigDstu2.class,
|
||||
JpaConfig.class
|
||||
GeneratedDaoAndResourceProviderConfigDstu2.class
|
||||
})
|
||||
public class JpaDstu2Config {
|
||||
@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.data.IResourceSearchViewDao;
|
||||
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.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.partition.IRequestPartitionHelperSvc;
|
||||
|
@ -107,6 +108,8 @@ public class SearchConfig {
|
|||
private PersistedJpaBundleProviderFactory myPersistedJpaBundleProviderFactory;
|
||||
@Autowired
|
||||
private IRequestPartitionHelperSvc myRequestPartitionHelperService;
|
||||
@Autowired
|
||||
private HapiTransactionService myHapiTransactionService;
|
||||
|
||||
@Bean
|
||||
public ISearchCoordinatorSvc searchCoordinatorSvc() {
|
||||
|
@ -114,7 +117,7 @@ public class SearchConfig {
|
|||
myContext,
|
||||
myDaoConfig,
|
||||
myInterceptorBroadcaster,
|
||||
myManagedTxManager,
|
||||
myHapiTransactionService,
|
||||
mySearchCacheSvc,
|
||||
mySearchResultCacheSvc,
|
||||
myDaoRegistry,
|
||||
|
@ -160,7 +163,7 @@ public class SearchConfig {
|
|||
@Scope("prototype")
|
||||
public SearchTask createSearchTask(SearchTaskParameters theParams) {
|
||||
return new SearchTask(theParams,
|
||||
myManagedTxManager,
|
||||
myHapiTransactionService,
|
||||
myContext,
|
||||
myInterceptorBroadcaster,
|
||||
mySearchBuilderFactory,
|
||||
|
@ -176,7 +179,7 @@ public class SearchConfig {
|
|||
@Scope("prototype")
|
||||
public SearchContinuationTask createSearchContinuationTask(SearchTaskParameters theParams) {
|
||||
return new SearchContinuationTask(theParams,
|
||||
myManagedTxManager,
|
||||
myHapiTransactionService,
|
||||
myContext,
|
||||
myInterceptorBroadcaster,
|
||||
mySearchBuilderFactory,
|
||||
|
|
|
@ -1247,8 +1247,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
* @param entity the existing entity.
|
||||
*/
|
||||
private void failIfPartitionMismatch(RequestDetails theRequest, ResourceTable entity) {
|
||||
if (myPartitionSettings.isPartitioningEnabled() && theRequest != null && theRequest.getTenantId() != null && entity.getPartitionId() != null &&
|
||||
!ALL_PARTITIONS_NAME.equals(theRequest.getTenantId())) {
|
||||
if (myPartitionSettings.isPartitioningEnabled() && theRequest != null && theRequest.getTenantId() != null && entity.getPartitionId() != null) {
|
||||
PartitionEntity partitionEntity = myPartitionLookupSvc.getPartitionByName(theRequest.getTenantId());
|
||||
//partitionEntity should never be null
|
||||
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.util.JpaConstants;
|
||||
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.PersistedJpaBundleProviderFactory;
|
||||
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.IInterceptorBroadcaster;
|
||||
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.Batch2WorkChunkEntity;
|
||||
import ca.uhn.fhir.jpa.entity.BulkImportJobEntity;
|
||||
|
@ -77,12 +78,9 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.PersistenceContext;
|
||||
import javax.persistence.PersistenceContextType;
|
||||
|
@ -98,22 +96,15 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
|||
@PersistenceContext(type = PersistenceContextType.TRANSACTION)
|
||||
protected EntityManager myEntityManager;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myPlatformTransactionManager;
|
||||
private HapiTransactionService myTxService;
|
||||
@Autowired
|
||||
protected IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
||||
private TransactionTemplate myTxTemplate;
|
||||
|
||||
@Autowired
|
||||
private MemoryCacheService myMemoryCacheService;
|
||||
|
||||
private int deletedResourceEntityCount;
|
||||
|
||||
@PostConstruct
|
||||
public void initTxTemplate() {
|
||||
myTxTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
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);
|
||||
|
||||
ourLog.info("BEGINNING GLOBAL $expunge");
|
||||
myTxTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
myTxTemplate.execute(t -> {
|
||||
myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||
counter.addAndGet(doExpungeEverythingQuery("UPDATE " + TermCodeSystem.class.getSimpleName() + " d SET d.myCurrentVersion = null"));
|
||||
return null;
|
||||
});
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(Batch2WorkChunkEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(Batch2JobInstanceEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(NpmPackageVersionResourceEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(NpmPackageVersionEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(NpmPackageEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SearchParamPresentEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(BulkImportJobFileEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(BulkImportJobEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ForcedId.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamDate.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamNumber.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamQuantity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamQuantityNormalized.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamString.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamToken.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamUri.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedSearchParamCoords.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedComboStringUnique.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceIndexedComboTokenNonUnique.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceLink.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SearchResult.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SearchInclude.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermValueSetConceptDesignation.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermValueSetConcept.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermValueSet.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptParentChildLink.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMapGroupElementTarget.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMapGroupElement.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMapGroup.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptMap.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptProperty.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConceptDesignation.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermConcept.class));
|
||||
myTxTemplate.execute(t -> {
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, Batch2WorkChunkEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, Batch2JobInstanceEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, NpmPackageVersionResourceEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, NpmPackageVersionEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, NpmPackageEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SearchParamPresentEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobFileEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, BulkImportJobEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ForcedId.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamDate.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamNumber.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamQuantity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamQuantityNormalized.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamString.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamToken.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamUri.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedSearchParamCoords.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedComboStringUnique.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceIndexedComboTokenNonUnique.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceLink.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SearchResult.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SearchInclude.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermValueSetConceptDesignation.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermValueSetConcept.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermValueSet.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptParentChildLink.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMapGroupElementTarget.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMapGroupElement.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMapGroup.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptMap.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptProperty.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConceptDesignation.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermConcept.class));
|
||||
myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||
for (TermCodeSystem next : myEntityManager.createQuery("SELECT c FROM " + TermCodeSystem.class.getName() + " c", TermCodeSystem.class).getResultList()) {
|
||||
next.setCurrentVersion(null);
|
||||
myEntityManager.merge(next);
|
||||
}
|
||||
return null;
|
||||
});
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermCodeSystemVersion.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TermCodeSystem.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(SubscriptionTable.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceHistoryTag.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceTag.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(TagDefinition.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceHistoryProvenanceEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceHistoryTable.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermCodeSystemVersion.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TermCodeSystem.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, SubscriptionTable.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceHistoryTag.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceTag.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, TagDefinition.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceHistoryProvenanceEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceHistoryTable.class));
|
||||
int counterBefore = counter.get();
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(ResourceTable.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(PartitionEntity.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, ResourceTable.class));
|
||||
counter.addAndGet(expungeEverythingByTypeWithoutPurging(theRequest, PartitionEntity.class));
|
||||
|
||||
deletedResourceEntityCount = counter.get() - counterBefore;
|
||||
|
||||
myTxTemplate.execute(t -> {
|
||||
myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||
counter.addAndGet(doExpungeEverythingQuery("DELETE from " + Search.class.getSimpleName() + " d"));
|
||||
return null;
|
||||
});
|
||||
|
||||
purgeAllCaches();
|
||||
|
@ -202,19 +189,15 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
|||
}
|
||||
|
||||
private void purgeAllCaches() {
|
||||
myTxTemplate.execute(t -> {
|
||||
myMemoryCacheService.invalidateAllCaches();
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
private int expungeEverythingByTypeWithoutPurging(Class<?> theEntityType) {
|
||||
private int expungeEverythingByTypeWithoutPurging(RequestDetails theRequest, Class<?> theEntityType) {
|
||||
int outcome = 0;
|
||||
while (true) {
|
||||
StopWatch sw = new StopWatch();
|
||||
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
int count = myTxTemplate.execute(t -> {
|
||||
int count = myTxService.withRequest(theRequest).withPropagation(Propagation.REQUIRES_NEW).execute(()-> {
|
||||
CriteriaBuilder cb = myEntityManager.getCriteriaBuilder();
|
||||
CriteriaQuery<?> cq = cb.createQuery(theEntityType);
|
||||
cq.from(theEntityType);
|
||||
|
@ -239,7 +222,7 @@ public class ExpungeEverythingService implements IExpungeEverythingService {
|
|||
|
||||
@Override
|
||||
public int expungeEverythingByType(Class<?> theEntityType) {
|
||||
int result = expungeEverythingByTypeWithoutPurging(theEntityType);
|
||||
int result = expungeEverythingByTypeWithoutPurging(null, theEntityType);
|
||||
purgeAllCaches();
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.dao.mdm;
|
|||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server - Master Data Management
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* 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.DeleteConflict;
|
||||
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.model.primitive.IdDt;
|
||||
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.policy.SimpleRetryPolicy;
|
||||
import org.springframework.retry.support.RetryTemplate;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
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 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 final DaoRegistry myDaoRegistry;
|
||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
private final TransactionTemplate myTxTemplateRequired;
|
||||
private final TransactionTemplate myTxTemplateRequiresNew;
|
||||
|
||||
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;
|
||||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||
|
||||
myTxTemplateRequired = new TransactionTemplate(thePlatformTransactionManager);
|
||||
myTxTemplateRequired.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
|
||||
myTxTemplateRequiresNew = new TransactionTemplate(thePlatformTransactionManager);
|
||||
myTxTemplateRequiresNew.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
myTransactionService = theTransactionService;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -121,13 +112,20 @@ public class ThreadSafeResourceDeleterSvc {
|
|||
|
||||
// Avoid nesting multiple new transactions deep. This can easily cause
|
||||
// thread pools to get exhausted.
|
||||
Propagation propagation;
|
||||
if (theRequest == null || previousNewTransactionValue != null) {
|
||||
myTxTemplateRequired.execute(s -> doDelete(theRequest, theConflictList, theTransactionDetails, nextSource, dao));
|
||||
propagation = Propagation.REQUIRED;
|
||||
} else {
|
||||
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;
|
||||
} catch (ResourceGoneException exception) {
|
||||
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.SequenceGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.UniqueConstraint;
|
||||
import java.io.Serializable;
|
||||
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.Interceptor;
|
||||
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.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
||||
/**
|
||||
|
|
|
@ -2,7 +2,7 @@ package ca.uhn.fhir.jpa.model.cross;
|
|||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Model
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* 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.ResourceTable;
|
||||
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.EncodingEnum;
|
||||
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.model.config.PartitionSettings;
|
||||
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.registry.ISearchParamRegistryController;
|
||||
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 com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.Lists;
|
||||
import com.google.gson.Gson;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import 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.npm.IPackageCacheManager;
|
||||
import org.hl7.fhir.utilities.npm.NpmPackage;
|
||||
|
@ -72,9 +70,7 @@ import java.io.IOException;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
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.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -46,7 +47,7 @@ public interface IPartitionLookupSvc {
|
|||
|
||||
void clearCaches();
|
||||
|
||||
PartitionEntity createPartition(PartitionEntity thePartition);
|
||||
PartitionEntity createPartition(PartitionEntity thePartition, RequestDetails theRequestDetails);
|
||||
|
||||
PartitionEntity updatePartition(PartitionEntity thePartition);
|
||||
|
||||
|
|
|
@ -22,16 +22,23 @@ package ca.uhn.fhir.jpa.partition;
|
|||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
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.entity.PartitionEntity;
|
||||
import ca.uhn.fhir.jpa.model.config.PartitionSettings;
|
||||
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.MethodNotAllowedException;
|
||||
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.CacheLoader;
|
||||
import ca.uhn.fhir.sl.cache.LoadingCache;
|
||||
import ca.uhn.fhir.util.ICallable;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
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.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
@ -58,15 +66,17 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
|||
@Autowired
|
||||
private PartitionSettings myPartitionSettings;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTxManager;
|
||||
private IInterceptorService myInterceptorService;
|
||||
@Autowired
|
||||
private IPartitionDao myPartitionDao;
|
||||
|
||||
private LoadingCache<String, PartitionEntity> myNameToPartitionCache;
|
||||
private LoadingCache<Integer, PartitionEntity> myIdToPartitionCache;
|
||||
private TransactionTemplate myTxTemplate;
|
||||
@Autowired
|
||||
private FhirContext myFhirCtx;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTxManager;
|
||||
private TransactionTemplate myTxTemplate;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -113,15 +123,25 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
|||
|
||||
@Override
|
||||
@Transactional
|
||||
public PartitionEntity createPartition(PartitionEntity thePartition) {
|
||||
public PartitionEntity createPartition(PartitionEntity thePartition, RequestDetails theRequestDetails) {
|
||||
validateNotInUnnamedPartitionMode();
|
||||
validateHaveValidPartitionIdAndName(thePartition);
|
||||
validatePartitionNameDoesntAlreadyExist(thePartition.getName());
|
||||
|
||||
ourLog.info("Creating new partition with ID {} and Name {}", thePartition.getId(), thePartition.getName());
|
||||
|
||||
myPartitionDao.save(thePartition);
|
||||
return thePartition;
|
||||
PartitionEntity retVal = myPartitionDao.save(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
|
||||
|
@ -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> {
|
||||
@Nullable
|
||||
@Override
|
||||
public PartitionEntity load(@NonNull String theName) {
|
||||
return myTxTemplate.execute(t -> myPartitionDao
|
||||
.findForName(theName)
|
||||
.orElseThrow(() -> {
|
||||
String msg = myFhirCtx.getLocalizer().getMessageSanitized(PartitionLookupSvcImpl.class, "invalidName", theName);
|
||||
return new ResourceNotFoundException(msg);
|
||||
}));
|
||||
return lookupPartitionByName(theName);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,12 +254,7 @@ public class PartitionLookupSvcImpl implements IPartitionLookupSvc {
|
|||
@Nullable
|
||||
@Override
|
||||
public PartitionEntity load(@NonNull Integer theId) {
|
||||
return myTxTemplate.execute(t -> myPartitionDao
|
||||
.findById(theId)
|
||||
.orElseThrow(() -> {
|
||||
String msg = myFhirCtx.getLocalizer().getMessageSanitized(PartitionLookupSvcImpl.class, "unknownPartitionId", theId);
|
||||
return new ResourceNotFoundException(msg);
|
||||
}));
|
||||
return lookupPartitionById(theId);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
|||
import ca.uhn.fhir.rest.annotation.Operation;
|
||||
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||
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.util.ParametersUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBase;
|
||||
|
@ -35,7 +35,6 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
|
||||
import javax.annotation.Nonnull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.jpa.partition.PartitionLookupSvcImpl.validatePartitionIdSupplied;
|
||||
|
@ -70,14 +69,15 @@ public class PartitionManagementProvider {
|
|||
@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_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));
|
||||
|
||||
PartitionEntity input = parseInput(thePartitionId, thePartitionName, thePartitionDescription);
|
||||
|
||||
// Note: Input validation happens inside IPartitionLookupSvc
|
||||
PartitionEntity output = myPartitionLookupSvc.createPartition(input);
|
||||
PartitionEntity output = myPartitionLookupSvc.createPartition(input, theRequestDetails);
|
||||
|
||||
IBaseParameters retVal = prepareOutput(output);
|
||||
|
||||
|
|
|
@ -35,7 +35,7 @@ import java.util.Objects;
|
|||
public class RequestPartitionHelperSvc extends BaseRequestPartitionHelperSvc {
|
||||
|
||||
@Autowired
|
||||
private IPartitionLookupSvc myPartitionConfigSvc;
|
||||
IPartitionLookupSvc myPartitionConfigSvc;
|
||||
|
||||
@Override
|
||||
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.dao.data.IResourceTableDao;
|
||||
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.SearchParameterMap;
|
||||
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.ISearchBuilder;
|
||||
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.SearchTypeEnum;
|
||||
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.LoggerFactory;
|
||||
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.persistence.EntityManager;
|
||||
|
@ -82,9 +78,9 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
/*
|
||||
* Autowired fields
|
||||
*/
|
||||
private final RequestDetails myRequest;
|
||||
protected final RequestDetails myRequest;
|
||||
@Autowired
|
||||
protected PlatformTransactionManager myTxManager;
|
||||
protected HapiTransactionService myTxService;
|
||||
@PersistenceContext
|
||||
private EntityManager myEntityManager;
|
||||
@Autowired
|
||||
|
@ -213,10 +209,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
final ISearchBuilder sb = mySearchBuilderFactory.newSearchBuilder(dao, resourceName, resourceType);
|
||||
|
||||
final List<JpaPid> pidsSubList = mySearchCoordinatorSvc.getResources(myUuid, theFromIndex, theToIndex, myRequest);
|
||||
|
||||
TransactionTemplate template = new TransactionTemplate(myTxManager);
|
||||
template.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
return template.execute(theStatus -> toResourceList(sb, pidsSubList));
|
||||
return myTxService.withRequest(myRequest).execute(() -> toResourceList(sb, pidsSubList));
|
||||
}
|
||||
|
||||
|
||||
|
@ -225,7 +218,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
*/
|
||||
public boolean ensureSearchEntityLoaded() {
|
||||
if (mySearchEntity == null) {
|
||||
Optional<Search> searchOpt = mySearchCacheSvc.fetchByUuid(myUuid);
|
||||
Optional<Search> searchOpt = myTxService.withRequest(myRequest).execute(() -> mySearchCacheSvc.fetchByUuid(myUuid));
|
||||
if (!searchOpt.isPresent()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -262,7 +255,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
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());
|
||||
Long count = historyBuilder.fetchCount(getRequestPartitionIdForHistory());
|
||||
return count.intValue();
|
||||
|
@ -299,14 +292,9 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
@Nonnull
|
||||
@Override
|
||||
public List<IBaseResource> getResources(final int theFromIndex, final int theToIndex) {
|
||||
TransactionTemplate template = new TransactionTemplate(myTxManager);
|
||||
|
||||
template.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theStatus) {
|
||||
myTxService.withRequest(myRequest).execute(() -> {
|
||||
boolean entityLoaded = ensureSearchEntityLoaded();
|
||||
assert entityLoaded;
|
||||
}
|
||||
});
|
||||
|
||||
assert mySearchEntity != null;
|
||||
|
@ -314,7 +302,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
|
||||
switch (mySearchEntity.getSearchType()) {
|
||||
case HISTORY:
|
||||
return template.execute(theStatus -> doHistoryInTransaction(mySearchEntity.getOffset(), theFromIndex, theToIndex));
|
||||
return myTxService.withRequest(myRequest).execute(() -> doHistoryInTransaction(mySearchEntity.getOffset(), theFromIndex, theToIndex));
|
||||
case SEARCH:
|
||||
case EVERYTHING:
|
||||
default:
|
||||
|
@ -365,8 +353,8 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void setTxManagerForUnitTest(PlatformTransactionManager theTxManager) {
|
||||
myTxManager = theTxManager;
|
||||
public void setTxServiceForUnitTest(HapiTransactionService theTxManager) {
|
||||
myTxService = theTxManager;
|
||||
}
|
||||
|
||||
// Note: Leave as protected, HSPC depends on this
|
||||
|
@ -388,7 +376,7 @@ public class PersistedJpaBundleProvider implements IBundleProvider {
|
|||
if (mySearchEntity.getSearchType() == SearchTypeEnum.HISTORY) {
|
||||
return null;
|
||||
} 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.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.List;
|
||||
|
@ -70,9 +68,7 @@ public class PersistedJpaSearchFirstPageBundleProvider extends PersistedJpaBundl
|
|||
final List<JpaPid> pids = mySearchTask.getResourcePids(theFromIndex, theToIndex);
|
||||
ourLog.trace("Done fetching search resource PIDs");
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
List<IBaseResource> retVal = txTemplate.execute(theStatus -> toResourceList(mySearchBuilder, pids));
|
||||
List<IBaseResource> retVal = myTxService.withRequest(myRequest).execute(() -> toResourceList(mySearchBuilder, pids));
|
||||
|
||||
long totalCountWanted = theToIndex - theFromIndex;
|
||||
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.SearchBuilderFactory;
|
||||
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.model.dao.JpaPid;
|
||||
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.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.util.AsyncUtil;
|
||||
import ca.uhn.fhir.util.ICallable;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
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.Sort;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -86,6 +84,7 @@ import java.util.List;
|
|||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Consumer;
|
||||
|
@ -103,7 +102,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
private final FhirContext myContext;
|
||||
private final DaoConfig myDaoConfig;
|
||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
private final PlatformTransactionManager myManagedTxManager;
|
||||
private final HapiTransactionService myTxService;
|
||||
private final ISearchCacheSvc mySearchCacheSvc;
|
||||
private final ISearchResultCacheSvc mySearchResultCacheSvc;
|
||||
private final DaoRegistry myDaoRegistry;
|
||||
|
@ -115,18 +114,15 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
private final SearchStrategyFactory mySearchStrategyFactory;
|
||||
private final ExceptionService myExceptionSvc;
|
||||
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 Consumer<String> myOnRemoveSearchTask = (theId) -> myIdToSearchTask.remove(theId);
|
||||
|
||||
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
|
||||
|
@ -135,7 +131,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
FhirContext theContext,
|
||||
DaoConfig theDaoConfig,
|
||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||
PlatformTransactionManager theManagedTxManager,
|
||||
HapiTransactionService theTxService,
|
||||
ISearchCacheSvc theSearchCacheSvc,
|
||||
ISearchResultCacheSvc theSearchResultCacheSvc,
|
||||
DaoRegistry theDaoRegistry,
|
||||
|
@ -152,7 +148,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
myContext = theContext;
|
||||
myDaoConfig = theDaoConfig;
|
||||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||
myManagedTxManager = theManagedTxManager;
|
||||
myTxService = theTxService;
|
||||
mySearchCacheSvc = theSearchCacheSvc;
|
||||
mySearchResultCacheSvc = theSearchResultCacheSvc;
|
||||
myDaoRegistry = theDaoRegistry;
|
||||
|
@ -208,10 +204,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
* fetch resources.
|
||||
*/
|
||||
@Override
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
public List<JpaPid> getResources(final String theUuid, int theFrom, int theTo, @Nullable RequestDetails theRequestDetails) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
assert !TransactionSynchronizationManager.isActualTransactionActive();
|
||||
|
||||
// If we're actively searching right now, don't try to do anything until at least one batch has been
|
||||
// persisted in the DB
|
||||
|
@ -244,9 +238,14 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
}
|
||||
}
|
||||
|
||||
search = mySearchCacheSvc
|
||||
Callable<Search> searchCallback = () -> mySearchCacheSvc
|
||||
.fetchByUuid(theUuid)
|
||||
.orElseThrow(() -> myExceptionSvc.newUnknownSearchException(theUuid));
|
||||
if (theRequestDetails != null) {
|
||||
search = myTxService.withRequest(theRequestDetails).execute(searchCallback);
|
||||
} else {
|
||||
search = HapiTransactionService.invokeCallableAndHandleAnyException(searchCallback);
|
||||
}
|
||||
|
||||
QueryParameterUtils.verifySearchHasntFailedOrThrowInternalErrorException(search);
|
||||
if (search.getStatus() == SearchStatusEnum.FINISHED) {
|
||||
|
@ -299,16 +298,22 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
|
||||
ourLog.trace("Finished looping");
|
||||
|
||||
List<JpaPid> pids = mySearchResultCacheSvc.fetchResultPids(search, theFrom, theTo);
|
||||
if (pids == null) {
|
||||
throw myExceptionSvc.newUnknownSearchException(theUuid);
|
||||
}
|
||||
List<JpaPid> pids = fetchResultPids(theUuid, theFrom, theTo, theRequestDetails, search);
|
||||
|
||||
ourLog.trace("Fetched {} results", pids.size());
|
||||
|
||||
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
|
||||
public IBundleProvider registerSearch(final IFhirResourceDao<?> theCallingDao, final SearchParameterMap theParams, String theResourceType, CacheControlDirective theCacheControlDirective, RequestDetails theRequestDetails, RequestPartitionId theRequestPartitionId) {
|
||||
final String searchUuid = UUID.randomUUID().toString();
|
||||
|
@ -429,7 +434,7 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> getSearchTotal(String theUuid) {
|
||||
public Optional<Integer> getSearchTotal(String theUuid, @Nullable RequestDetails theRequestDetails) {
|
||||
SearchTask task = myIdToSearchTask.get(theUuid);
|
||||
if (task != null) {
|
||||
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
|
||||
* so let's wait a bit for it to show up
|
||||
*/
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
Optional<Search> search = mySearchCacheSvc.fetchByUuid(theUuid);
|
||||
Optional<Search> search = myTxService.withRequest(theRequestDetails).execute(()->mySearchCacheSvc.fetchByUuid(theUuid));
|
||||
if (search.isPresent()) {
|
||||
Optional<SearchParameterMap> searchParameterMap = search.get().getSearchParameterMap();
|
||||
if (searchParameterMap.isPresent() && searchParameterMap.get().getSearchTotalMode() == SearchTotalModeEnum.ACCURATE) {
|
||||
|
@ -487,10 +490,8 @@ public class SearchCoordinatorSvcImpl implements ISearchCoordinatorSvc<JpaPid> {
|
|||
|
||||
@Nullable
|
||||
private PersistedJpaBundleProvider findCachedQuery(SearchParameterMap theParams, String theResourceType, RequestDetails theRequestDetails, String theQueryString, RequestPartitionId theRequestPartitionId) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
|
||||
// May be null
|
||||
return txTemplate.execute(t -> {
|
||||
return myTxService.withRequest(theRequestDetails).execute(() -> {
|
||||
|
||||
// Interceptor call: STORAGE_PRECHECK_FOR_CACHED_SEARCH
|
||||
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.ISearchBuilder;
|
||||
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.model.dao.JpaPid;
|
||||
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 org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
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 java.io.IOException;
|
||||
|
@ -79,7 +77,7 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
|||
private DaoRegistry myDaoRegistry;
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myManagedTxManager;
|
||||
private HapiTransactionService myTxService;
|
||||
|
||||
@Autowired
|
||||
private IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
|
@ -89,6 +87,7 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
|||
|
||||
private int mySyncSize = 250;
|
||||
|
||||
@Override
|
||||
public IBundleProvider executeQuery(SearchParameterMap theParams, RequestDetails theRequestDetails, String theSearchUuid, ISearchBuilder theSb, Integer theLoadSynchronousUpTo, RequestPartitionId theRequestPartitionId) {
|
||||
SearchRuntimeDetails searchRuntimeDetails = new SearchRuntimeDetails(theRequestDetails, theSearchUuid);
|
||||
searchRuntimeDetails.setLoadSynchronous(true);
|
||||
|
@ -98,10 +97,8 @@ public class SynchronousSearchSvcImpl implements ISynchronousSearchSvc {
|
|||
boolean wantCount = theParamWantOnlyCount || theParamOrConfigWantCount;
|
||||
|
||||
// Execute the query and make sure we return distinct results
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
txTemplate.setReadOnly(theParams.isLoadSynchronous() || theParams.isOffsetQuery());
|
||||
return txTemplate.execute(t -> {
|
||||
|
||||
return myTxService.withRequest(theRequestDetails).readOnly().execute(() -> {
|
||||
|
||||
// Load the results synchronously
|
||||
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.dao.SearchBuilderFactory;
|
||||
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.search.ExceptionService;
|
||||
import ca.uhn.fhir.jpa.search.cache.ISearchCacheSvc;
|
||||
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.exceptions.BaseServerResponseException;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
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 final ExceptionService myExceptionSvc;
|
||||
private final RequestDetails myRequestDetails;
|
||||
|
||||
public SearchContinuationTask(
|
||||
SearchTaskParameters theCreationParams,
|
||||
PlatformTransactionManager theManagedTxManager,
|
||||
HapiTransactionService theTxService,
|
||||
FhirContext theContext,
|
||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||
SearchBuilderFactory theSearchBuilderFactory,
|
||||
|
@ -56,7 +57,7 @@ public class SearchContinuationTask extends SearchTask {
|
|||
) {
|
||||
super(
|
||||
theCreationParams,
|
||||
theManagedTxManager,
|
||||
theTxService,
|
||||
theContext,
|
||||
theInterceptorBroadcaster,
|
||||
theSearchBuilderFactory,
|
||||
|
@ -66,15 +67,14 @@ public class SearchContinuationTask extends SearchTask {
|
|||
thePagingProvider
|
||||
);
|
||||
|
||||
myRequestDetails = theCreationParams.Request;
|
||||
myExceptionSvc = theExceptionSvc;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Void call() {
|
||||
try {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.afterPropertiesSet();
|
||||
txTemplate.execute(t -> {
|
||||
myTxService.withRequest(myRequestDetails).execute(() -> {
|
||||
List<JpaPid> previouslyAddedResourcePids = mySearchResultCacheSvc.fetchAllResultPids(getSearch());
|
||||
if (previouslyAddedResourcePids == null) {
|
||||
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());
|
||||
setPreviouslyAddedResourcePids(previouslyAddedResourcePids);
|
||||
return null;
|
||||
});
|
||||
|
||||
} catch (Throwable e) {
|
||||
ourLog.error("Failure processing search", e);
|
||||
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.ISearchBuilder;
|
||||
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.interceptor.JpaPreResourceAccessDetails;
|
||||
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.exception.ExceptionUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.orm.jpa.JpaDialect;
|
||||
import org.springframework.orm.jpa.JpaTransactionManager;
|
||||
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 org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.io.IOException;
|
||||
|
@ -123,10 +118,8 @@ public class SearchTask implements Callable<Void> {
|
|||
private final int mySyncSize;
|
||||
private final Integer myLoadingThrottleForUnitTests;
|
||||
|
||||
private boolean myCustomIsolationSupported;
|
||||
|
||||
// injected beans
|
||||
protected final PlatformTransactionManager myManagedTxManager;
|
||||
protected final HapiTransactionService myTxService;
|
||||
protected final FhirContext myContext;
|
||||
private final IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
private final SearchBuilderFactory<JpaPid> mySearchBuilderFactory;
|
||||
|
@ -140,7 +133,7 @@ public class SearchTask implements Callable<Void> {
|
|||
*/
|
||||
public SearchTask(
|
||||
SearchTaskParameters theCreationParams,
|
||||
PlatformTransactionManager theManagedTxManager,
|
||||
HapiTransactionService theManagedTxManager,
|
||||
FhirContext theContext,
|
||||
IInterceptorBroadcaster theInterceptorBroadcaster,
|
||||
SearchBuilderFactory theSearchBuilderFactory,
|
||||
|
@ -150,7 +143,7 @@ public class SearchTask implements Callable<Void> {
|
|||
IPagingProvider thePagingProvider
|
||||
) {
|
||||
// beans
|
||||
myManagedTxManager = theManagedTxManager;
|
||||
myTxService = theManagedTxManager;
|
||||
myContext = theContext;
|
||||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||
mySearchBuilderFactory = theSearchBuilderFactory;
|
||||
|
@ -174,17 +167,6 @@ public class SearchTask implements Callable<Void> {
|
|||
mySearchRuntimeDetails.setQueryString(myParams.toNormalizedQueryString(myCallingDao.getContext()));
|
||||
myRequestPartitionId = theCreationParams.RequestPartitionId;
|
||||
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() {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theArg0) {
|
||||
doSaveSearch();
|
||||
}
|
||||
|
||||
});
|
||||
myTxService.execute(myRequest, null, Propagation.REQUIRES_NEW, Isolation.DEFAULT, ()->doSaveSearch());
|
||||
}
|
||||
|
||||
private void saveUnsynced(final IResultIterator theResultIter) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theArg0) {
|
||||
myTxService.withRequest(myRequest).execute(()->{
|
||||
if (mySearch.getId() == null) {
|
||||
doSaveSearch();
|
||||
}
|
||||
|
@ -380,7 +350,6 @@ public class SearchTask implements Callable<Void> {
|
|||
doSaveSearch();
|
||||
|
||||
ourLog.trace("saveUnsynced() - pre-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
|
||||
saveSearch();
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
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();
|
||||
}
|
||||
});
|
||||
myTxService.execute(myRequest, null, Propagation.REQUIRED, Isolation.READ_COMMITTED, ()->doSearch());
|
||||
|
||||
mySearchRuntimeDetails.setSearchStatus(mySearch.getStatus());
|
||||
if (mySearch.getStatus() == SearchStatusEnum.FINISHED) {
|
||||
|
@ -549,16 +506,12 @@ public class SearchTask implements Callable<Void> {
|
|||
|
||||
ourLog.trace("Got count {}", count);
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myManagedTxManager);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(@Nonnull TransactionStatus theArg0) {
|
||||
myTxService.withRequest(myRequest).execute(()->{
|
||||
mySearch.setTotalCount(count.intValue());
|
||||
if (myParamWantOnlyCount) {
|
||||
mySearch.setStatus(SearchStatusEnum.FINISHED);
|
||||
}
|
||||
doSaveSearch();
|
||||
}
|
||||
});
|
||||
if (myParamWantOnlyCount) {
|
||||
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.model.dao.JpaPid;
|
||||
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.mdm.api.MdmMatchResultEnum;
|
||||
import ca.uhn.fhir.mdm.dao.IMdmLinkDao;
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ package ca.uhn.fhir.cql.dstu3.provider;
|
|||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.cql.common.provider.LibraryResolutionProvider;
|
||||
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.rest.api.server.RequestDetails;
|
||||
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.jpa.api.dao.DaoRegistry;
|
||||
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.rest.api.server.RequestDetails;
|
||||
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.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 org.hamcrest.Matchers;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</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.NormalizedQuantitySearchLevel;
|
||||
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.QuantitySearchParameterTestCases;
|
||||
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.model.dao.JpaPid;
|
||||
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.term.api.ITermCodeSystemStorageSvc;
|
||||
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.test.BaseValueSetHSearchExpansionR4Test;
|
||||
import ca.uhn.fhir.test.utilities.docker.RequiresDocker;
|
||||
import org.junit.jupiter.api.extension.ExtendWith;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit.jupiter.SpringExtension;
|
||||
|
@ -11,6 +12,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
|
|||
*/
|
||||
@ExtendWith(SpringExtension.class)
|
||||
@ContextConfiguration(classes = TestR4ConfigWithElasticHSearch.class)
|
||||
@RequiresDocker
|
||||
public class ValueSetHSearchExpansionR4ElasticIT extends BaseValueSetHSearchExpansionR4Test {
|
||||
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -25,7 +25,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.api.ChannelProducerSettings;
|
||||
import ca.uhn.fhir.jpa.subscription.channel.subscription.IChannelNamer;
|
||||
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.IResourcePidList;
|
||||
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.SearchParameterMap;
|
||||
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.model.DaoMethodOutcome;
|
||||
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.mdm.api.IMdmSettings;
|
||||
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.IFhirResourceDao;
|
||||
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.mdm.api.IMdmSettings;
|
||||
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.dao.JpaPid;
|
||||
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.registry.SearchParamRegistryImpl;
|
||||
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.MdmTestLinkExpression;
|
||||
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.MdmMatchOutcome;
|
||||
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.interceptor.api.IInterceptorService;
|
||||
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.rest.server.exceptions.InvalidRequestException;
|
||||
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.BeforeEach;
|
||||
import org.junit.jupiter.api.Named;
|
||||
import org.junit.jupiter.api.Tag;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.params.ParameterizedTest;
|
||||
import org.junit.jupiter.params.provider.Arguments;
|
||||
import org.junit.jupiter.params.provider.MethodSource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import javax.servlet.Servlet;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.either;
|
||||
import static org.hamcrest.Matchers.equalTo;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
|
|
@ -49,7 +49,7 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
|
|||
@Test
|
||||
public void testCreateLinkWithMatchResultOnSamePartition() {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||
assertLinkCount(1);
|
||||
|
||||
RequestPartitionId requestPartitionId = RequestPartitionId.fromPartitionId(1);
|
||||
|
@ -73,8 +73,8 @@ public class MdmProviderCreateLinkR4Test extends BaseLinkR4Test {
|
|||
@Test
|
||||
public void testCreateLinkWithMatchResultOnDifferentPartitions() {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||
assertLinkCount(1);
|
||||
|
||||
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
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 com.google.common.collect.Ordering;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
|
|
@ -47,6 +47,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
|||
myToGoldenPatientId = new StringType(myToGoldenPatient.getIdElement().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
public void after() throws IOException {
|
||||
myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
|
||||
|
@ -112,7 +113,7 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
|||
@Test
|
||||
public void testMergeOnSamePartition() {
|
||||
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);
|
||||
Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
||||
StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
|
||||
|
@ -147,9 +148,9 @@ public class MdmProviderMergeGoldenResourcesR4Test extends BaseProviderR4Test {
|
|||
@Test
|
||||
public void testMergeOnDifferentPartitions() {
|
||||
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);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||
Patient fromGoldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
||||
StringType fromGoldenPatientId = new StringType(fromGoldenPatient.getIdElement().getValue());
|
||||
|
|
|
@ -43,6 +43,7 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
|
|||
myTargetPatientId = new StringType(myTargetPatient.getIdElement().getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
public void after() throws IOException {
|
||||
myPartitionSettings.setPartitioningEnabled(false);
|
||||
|
@ -86,7 +87,7 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
|
|||
@Test
|
||||
public void testNotDuplicateGoldenResourceOnSamePartition() {
|
||||
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);
|
||||
Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
||||
StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
|
||||
|
@ -106,9 +107,9 @@ public class MdmProviderNotDuplicateGoldenResourceR4Test extends BaseProviderR4T
|
|||
@Test
|
||||
public void testNotDuplicateGoldenResourceOnDifferentPartitions() {
|
||||
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);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||
Patient goldenPatient = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
||||
StringType goldenPatientId = new StringType(goldenPatient.getIdElement().getValue());
|
||||
|
|
|
@ -59,7 +59,7 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
|
|||
@Test
|
||||
public void testUpdateLinkMatchOnSamePartition() {
|
||||
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);
|
||||
Patient patient = createPatientAndUpdateLinksOnPartition(buildFrankPatient(), requestPartitionId);
|
||||
StringType patientId = new StringType(patient.getIdElement().getValue());
|
||||
|
@ -84,8 +84,8 @@ public class MdmProviderUpdateLinkR4Test extends BaseLinkR4Test {
|
|||
@Test
|
||||
public void testUpdateLinkMatchOnDifferentPartitions() {
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||
RequestPartitionId requestPartitionId1 = RequestPartitionId.fromPartitionId(1);
|
||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||
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.Pointcut;
|
||||
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.svc.MdmSubmitSvcImpl;
|
||||
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.mdm.provider.BaseLinkR4Test;
|
||||
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.mdm.api.IMdmControllerSvc;
|
||||
import ca.uhn.fhir.mdm.api.MdmLinkJson;
|
||||
|
@ -65,8 +65,8 @@ public class MdmControllerSvcImplTest extends BaseLinkR4Test {
|
|||
public void before() throws Exception {
|
||||
super.before();
|
||||
myPartitionSettings.setPartitioningEnabled(true);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(1).setName(PARTITION_1), null);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||
myInterceptorService.registerInterceptor(myPartitionInterceptor);
|
||||
myMdmSettings.setEnabled(true);
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@ package ca.uhn.fhir.jpa.mdm.svc;
|
|||
import ca.uhn.fhir.i18n.Msg;
|
||||
import ca.uhn.fhir.jpa.api.model.DaoMethodOutcome;
|
||||
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.IMdmLinkUpdaterSvc;
|
||||
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.model.MdmTransactionContext;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static ca.uhn.fhir.mdm.api.MdmMatchResultEnum.MATCH;
|
||||
|
@ -22,6 +24,13 @@ class MdmLinkUpdaterSvcImplTest extends BaseMdmR4Test {
|
|||
@Autowired
|
||||
private IMdmLinkUpdaterSvc myMdmLinkUpdaterSvc;
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
public void after() throws IOException {
|
||||
super.after();
|
||||
myMdmSettings.getMdmRules().setVersion("1");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateLinkNoMatch() {
|
||||
// setup
|
||||
|
|
|
@ -4,7 +4,7 @@ import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
|||
import ca.uhn.fhir.jpa.entity.PartitionEntity;
|
||||
import ca.uhn.fhir.jpa.mdm.BaseMdmR4Test;
|
||||
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 org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
|
@ -25,6 +25,7 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
|
|||
@Autowired
|
||||
MdmResourceDaoSvc myResourceDaoSvc;
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
public void after() throws IOException {
|
||||
myPartitionSettings.setPartitioningEnabled(new PartitionSettings().isPartitioningEnabled());
|
||||
|
@ -63,7 +64,7 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
|
|||
@Test
|
||||
public void testSearchGoldenResourceOnSamePartition() {
|
||||
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);
|
||||
Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId);
|
||||
Patient goodSourcePatient = addExternalEID(patientOnPartition, TEST_EID);
|
||||
|
@ -79,9 +80,9 @@ public class MdmResourceDaoSvcTest extends BaseMdmR4Test {
|
|||
@Test
|
||||
public void testSearchGoldenResourceOnDifferentPartitions() {
|
||||
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);
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2));
|
||||
myPartitionLookupSvc.createPartition(new PartitionEntity().setId(2).setName(PARTITION_2), null);
|
||||
RequestPartitionId requestPartitionId2 = RequestPartitionId.fromPartitionId(2);
|
||||
Patient patientOnPartition = createPatientOnPartition(new Patient(), true, false, requestPartitionId1);
|
||||
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.mdm.BaseMdmR4Test;
|
||||
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.mdm.api.MdmLinkSourceEnum;
|
||||
import ca.uhn.fhir.mdm.api.MdmMatchResultEnum;
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -1,5 +1,25 @@
|
|||
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 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
|
||||
* HAPI FHIR JPA Server
|
||||
* HAPI FHIR JPA Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2022 Smile CDR, Inc.
|
||||
* %%
|
||||
|
@ -20,18 +20,25 @@ package ca.uhn.fhir.jpa.dao.tx;
|
|||
* #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
|
||||
* @since 5.1.0
|
||||
* This is an internal API and may change or disappear without notice
|
||||
*
|
||||
* Implementations of this interface can modify the automatically generated sequence values created by hibernate seuqnece generator
|
||||
*/
|
||||
@Retention(RUNTIME)
|
||||
@Target({METHOD, TYPE})
|
||||
public @interface HapiTransactional {
|
||||
public interface ISequenceValueMassager {
|
||||
|
||||
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;
|
||||
|
||||
/*-
|
||||
* #%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;
|
||||
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ package ca.uhn.fhir.jpa.model.entity;
|
|||
|
||||
import ca.uhn.fhir.context.ParserOptions;
|
||||
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.rest.server.interceptor.ResponseTerminologyTranslationSvc;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
@ -111,10 +112,9 @@ public class ModelConfig {
|
|||
*/
|
||||
private boolean myUseOrdinalDatesForDayPrecisionSearches = true;
|
||||
private boolean mySuppressStringIndexingInTokens = false;
|
||||
|
||||
private Class<? extends ISequenceValueMassager> mySequenceValueMassagerClass;
|
||||
private IPrimitiveType<Date> myPeriodIndexStartOfTime;
|
||||
private IPrimitiveType<Date> myPeriodIndexEndOfTime;
|
||||
|
||||
private NormalizedQuantitySearchLevel myNormalizedQuantitySearchLevel;
|
||||
private Set<String> myAutoVersionReferenceAtPaths = Collections.emptySet();
|
||||
private Map<String, Set<String>> myTypeToAutoVersionReferenceAtPaths = Collections.emptyMap();
|
||||
|
@ -124,16 +124,35 @@ public class ModelConfig {
|
|||
private boolean myAllowMdmExpansion = false;
|
||||
private boolean myAutoSupportDefaultSearchParams = true;
|
||||
private boolean myIndexIdentifierOfType = false;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ModelConfig() {
|
||||
setSequenceValueMassagerClass(ISequenceValueMassager.NoopSequenceValueMassager.class);
|
||||
setPeriodIndexStartOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_START_OF_TIME));
|
||||
setPeriodIndexEndOfTime(new DateTimeType(DEFAULT_PERIOD_INDEX_END_OF_TIME));
|
||||
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
|
||||
* <code>:of-type</code> modifier on token search parameters for
|
||||
|
@ -887,18 +906,6 @@ public class ModelConfig {
|
|||
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.
|
||||
* 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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.rest.api.Constants;
|
|||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.annotations.GenerationTime;
|
||||
import org.hibernate.annotations.GeneratorType;
|
||||
|
@ -63,7 +64,7 @@ import javax.persistence.OneToMany;
|
|||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.PrePersist;
|
||||
import javax.persistence.PreUpdate;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import org.hibernate.annotations.GenericGenerator;
|
||||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
import javax.persistence.Version;
|
||||
|
@ -113,7 +114,7 @@ public class ResourceTable extends BaseHasResource implements Serializable, IBas
|
|||
private boolean myHasLinks;
|
||||
|
||||
@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")
|
||||
@Column(name = "RES_ID")
|
||||
@GenericField(projectable = Projectable.YES)
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import ca.uhn.fhir.interceptor.api.Pointcut;
|
|||
import ca.uhn.fhir.interceptor.model.RequestPartitionId;
|
||||
import ca.uhn.fhir.jpa.api.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.api.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.partition.SystemRequestDetails;
|
||||
import ca.uhn.fhir.rest.api.server.SystemRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.subscription.match.deliver.BaseSubscriptionDeliverySubscriber;
|
||||
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.dao.DaoRegistry;
|
||||
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.SubscriptionConstants;
|
||||
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.jpa.api.dao.DaoRegistry;
|
||||
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.SubscriptionRegistry;
|
||||
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.IResourceChangeListenerRegistry;
|
||||
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.retry.Retrier;
|
||||
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.dao.DaoRegistry;
|
||||
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.SubscriptionStrategyEvaluator;
|
||||
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.ISchedulerService;
|
||||
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.SearchParameterMap;
|
||||
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.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.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.dao.DaoRegistry;
|
||||
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.registry.SubscriptionCanonicalizer;
|
||||
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.jpa.api.dao.DaoRegistry;
|
||||
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.SubscriptionRegistry;
|
||||
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.IResourceChangeListenerRegistry;
|
||||
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.subscription.match.matcher.subscriber.SubscriptionActivatingSubscriber;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
<parent>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<version>6.3.4-SNAPSHOT</version>
|
||||
<version>6.3.5-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</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.dao.IResultIterator;
|
||||
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.search.builder.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.util.BaseIterator;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.rest.api.server.storage.IResourcePersistentId;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.mockito.Answers;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.stubbing.Answer;
|
||||
|
@ -31,9 +33,8 @@ public class BaseSearchSvc {
|
|||
protected int myExpectedNumberOfSearchBuildersCreated = 2;
|
||||
@Mock
|
||||
protected SearchBuilderFactory<JpaPid> mySearchBuilderFactory;
|
||||
|
||||
@Mock
|
||||
protected PlatformTransactionManager myTxManager;
|
||||
@Spy
|
||||
protected HapiTransactionService myTransactionService = new MockHapiTransactionService();
|
||||
@Mock
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
|
@ -43,6 +43,8 @@ import org.slf4j.Logger;
|
|||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.annotation.Isolation;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.util.ArrayList;
|
||||
|
@ -109,6 +111,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
|
||||
private SearchCoordinatorSvcImpl mySvc;
|
||||
|
||||
@Override
|
||||
@AfterEach
|
||||
public void after() {
|
||||
HapiSystemProperties.disableUnitTestCaptureStack();
|
||||
|
@ -128,7 +131,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
myContext,
|
||||
myDaoConfig,
|
||||
myInterceptorBroadcaster,
|
||||
myTxManager,
|
||||
myTransactionService,
|
||||
mySearchCacheSvc,
|
||||
mySearchResultCacheSvc,
|
||||
myDaoRegistry,
|
||||
|
@ -292,8 +295,6 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
|
||||
private void initSearches() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
|
||||
when(myTxManager.getTransaction(any())).thenReturn(mock(TransactionStatus.class));
|
||||
}
|
||||
|
||||
private void initAsyncSearches() {
|
||||
|
@ -304,7 +305,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
ISearchBuilder<JpaPid> searchBuilder = t.getArgument(3, ISearchBuilder.class);
|
||||
PersistedJpaSearchFirstPageBundleProvider retVal = new PersistedJpaSearchFirstPageBundleProvider(search, searchTask, searchBuilder, requestDetails);
|
||||
retVal.setDaoConfigForUnitTest(new DaoConfig());
|
||||
retVal.setTxManagerForUnitTest(myTxManager);
|
||||
retVal.setTxServiceForUnitTest(myTransactionService);
|
||||
retVal.setSearchCoordinatorSvcForUnitTest(mySvc);
|
||||
return retVal;
|
||||
});
|
||||
|
@ -355,6 +356,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
// good
|
||||
}
|
||||
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
completionLatch.await(10, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
|
@ -440,7 +442,6 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
@Test
|
||||
public void testLoadSearchResultsFromDifferentCoordinator() {
|
||||
when(mySearchBuilderFactory.newSearchBuilder(any(), any(), any())).thenReturn(mySearchBuilder);
|
||||
when(myTxManager.getTransaction(any())).thenReturn(mock(TransactionStatus.class));
|
||||
|
||||
final String uuid = UUID.randomUUID().toString();
|
||||
|
||||
|
@ -485,7 +486,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
assertEquals("29", resources.get(9).getIdElement().getValueAsString());
|
||||
|
||||
provider = new PersistedJpaBundleProvider(null, uuid);
|
||||
provider.setTxManagerForUnitTest(myTxManager);
|
||||
provider.setTxServiceForUnitTest(myTransactionService);
|
||||
provider.setSearchCacheSvcForUnitTest(mySearchCacheSvc);
|
||||
provider.setContext(ourCtx);
|
||||
provider.setDaoRegistryForUnitTest(myDaoRegistry);
|
||||
|
@ -504,7 +505,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
private PersistedJpaBundleProvider newPersistedJpaBundleProvider(String theUuid) {
|
||||
PersistedJpaBundleProvider provider;
|
||||
provider = new PersistedJpaBundleProvider(null, theUuid);
|
||||
provider.setTxManagerForUnitTest(myTxManager);
|
||||
provider.setTxServiceForUnitTest(myTransactionService);
|
||||
provider.setSearchCacheSvcForUnitTest(mySearchCacheSvc);
|
||||
provider.setContext(ourCtx);
|
||||
provider.setSearchBuilderFactoryForUnitTest(mySearchBuilderFactory);
|
||||
|
@ -751,7 +752,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
case SearchConfig.SEARCH_TASK:
|
||||
return new SearchTask(
|
||||
invocation.getArgument(1),
|
||||
myTxManager,
|
||||
myTransactionService,
|
||||
ourCtx,
|
||||
myInterceptorBroadcaster,
|
||||
mySearchBuilderFactory,
|
||||
|
@ -763,7 +764,7 @@ public class SearchCoordinatorSvcImplTest extends BaseSearchSvc{
|
|||
case SearchConfig.CONTINUE_TASK:
|
||||
return new SearchContinuationTask(
|
||||
invocation.getArgument(1),
|
||||
myTxManager,
|
||||
myTransactionService,
|
||||
ourCtx,
|
||||
myInterceptorBroadcaster,
|
||||
mySearchBuilderFactory,
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue