Merge remote-tracking branch 'upstream/master'
This commit is contained in:
commit
ca3b17f3b9
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you 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.
|
||||
*/
|
||||
|
||||
import java.net.*;
|
||||
import java.io.*;
|
||||
import java.nio.channels.*;
|
||||
import java.util.Properties;
|
||||
|
||||
public class MavenWrapperDownloader {
|
||||
|
||||
/**
|
||||
* Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided.
|
||||
*/
|
||||
private static final String DEFAULT_DOWNLOAD_URL =
|
||||
"https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.4.2/maven-wrapper-0.4.2.jar";
|
||||
|
||||
/**
|
||||
* Path to the maven-wrapper.properties file, which might contain a downloadUrl property to
|
||||
* use instead of the default one.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_PROPERTIES_PATH =
|
||||
".mvn/wrapper/maven-wrapper.properties";
|
||||
|
||||
/**
|
||||
* Path where the maven-wrapper.jar will be saved to.
|
||||
*/
|
||||
private static final String MAVEN_WRAPPER_JAR_PATH =
|
||||
".mvn/wrapper/maven-wrapper.jar";
|
||||
|
||||
/**
|
||||
* Name of the property which should be used to override the default download url for the wrapper.
|
||||
*/
|
||||
private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl";
|
||||
|
||||
public static void main(String args[]) {
|
||||
System.out.println("- Downloader started");
|
||||
File baseDirectory = new File(args[0]);
|
||||
System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath());
|
||||
|
||||
// If the maven-wrapper.properties exists, read it and check if it contains a custom
|
||||
// wrapperUrl parameter.
|
||||
File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH);
|
||||
String url = DEFAULT_DOWNLOAD_URL;
|
||||
if(mavenWrapperPropertyFile.exists()) {
|
||||
FileInputStream mavenWrapperPropertyFileInputStream = null;
|
||||
try {
|
||||
mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile);
|
||||
Properties mavenWrapperProperties = new Properties();
|
||||
mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream);
|
||||
url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url);
|
||||
} catch (IOException e) {
|
||||
System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'");
|
||||
} finally {
|
||||
try {
|
||||
if(mavenWrapperPropertyFileInputStream != null) {
|
||||
mavenWrapperPropertyFileInputStream.close();
|
||||
}
|
||||
} catch (IOException e) {
|
||||
// Ignore ...
|
||||
}
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading from: : " + url);
|
||||
|
||||
File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH);
|
||||
if(!outputFile.getParentFile().exists()) {
|
||||
if(!outputFile.getParentFile().mkdirs()) {
|
||||
System.out.println(
|
||||
"- ERROR creating output direcrory '" + outputFile.getParentFile().getAbsolutePath() + "'");
|
||||
}
|
||||
}
|
||||
System.out.println("- Downloading to: " + outputFile.getAbsolutePath());
|
||||
try {
|
||||
downloadFileFromURL(url, outputFile);
|
||||
System.out.println("Done");
|
||||
System.exit(0);
|
||||
} catch (Throwable e) {
|
||||
System.out.println("- Error downloading");
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static void downloadFileFromURL(String urlString, File destination) throws Exception {
|
||||
URL website = new URL(urlString);
|
||||
ReadableByteChannel rbc;
|
||||
rbc = Channels.newChannel(website.openStream());
|
||||
FileOutputStream fos = new FileOutputStream(destination);
|
||||
fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE);
|
||||
fos.close();
|
||||
rbc.close();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.5.4/apache-maven-3.5.4-bin.zip
|
|
@ -92,6 +92,11 @@
|
|||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.slf4j</groupId>
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
package example;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.annotation.*;
|
||||
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
|
||||
import ca.uhn.fhir.rest.annotation.IdParam;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
|
@ -17,6 +13,12 @@ import ca.uhn.fhir.rest.server.IResourceProvider;
|
|||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.auth.*;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class AuthorizationInterceptors {
|
||||
|
@ -158,4 +160,47 @@ public class AuthorizationInterceptors {
|
|||
//END SNIPPET: patchAll
|
||||
|
||||
}
|
||||
|
||||
|
||||
//START SNIPPET: narrowing
|
||||
public class MyPatientSearchNarrowingInterceptor extends SearchNarrowingInterceptor {
|
||||
|
||||
/**
|
||||
* This method must be overridden to provide the list of compartments
|
||||
* and/or resources that the current user should have access to
|
||||
*/
|
||||
@Override
|
||||
protected AuthorizedList buildAuthorizedList(RequestDetails theRequestDetails) {
|
||||
// Process authorization header - The following is a fake
|
||||
// implementation. Obviously we'd want something more real
|
||||
// for a production scenario.
|
||||
//
|
||||
// In this basic example we have two hardcoded bearer tokens,
|
||||
// one which is for a user that has access to one patient, and
|
||||
// another that has full access.
|
||||
String authHeader = theRequestDetails.getHeader("Authorization");
|
||||
if ("Bearer dfw98h38r".equals(authHeader)) {
|
||||
|
||||
// This user will have access to two compartments
|
||||
return new AuthorizedList()
|
||||
.addCompartment("Patient/123")
|
||||
.addCompartment("Patient/456");
|
||||
|
||||
} else if ("Bearer 39ff939jgg".equals(authHeader)) {
|
||||
|
||||
// This user has access to everything
|
||||
return new AuthorizedList();
|
||||
|
||||
} else {
|
||||
|
||||
throw new AuthenticationException("Unknown bearer token");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
//END SNIPPET: narrowing
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
package example.interceptor;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage;
|
||||
|
||||
/**
|
||||
* Interceptor class
|
||||
*/
|
||||
@Interceptor
|
||||
public class MyTestInterceptor {
|
||||
|
||||
@Hook(Pointcut.SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY)
|
||||
public boolean beforeRestHookDelivery(ResourceDeliveryMessage theDeliveryMessage, CanonicalSubscription theSubscription) {
|
||||
|
||||
String header = "Authorization: Bearer 1234567";
|
||||
|
||||
theSubscription.addHeader(header);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
|
@ -162,12 +162,45 @@
|
|||
</instructions>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>buildnumber-maven-plugin</artifactId>
|
||||
<inherited>true</inherited>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>standard</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>create</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
<execution>
|
||||
<id>downstream</id>
|
||||
<phase>validate</phase>
|
||||
<goals>
|
||||
<goal>create-metadata</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<outputDirectory>${project.build.directory}/generated-sources/properties</outputDirectory>
|
||||
<outputName>ca/uhn/fhir/hapi-fhir-base-build.properties</outputName>
|
||||
<revisionPropertyName>hapifhir.buildnumber</revisionPropertyName>
|
||||
<timestampPropertyName>hapifhir.timestamp</timestampPropertyName>
|
||||
<timestampFormat>yyyy-MM-dd'T'HH:mm:ss.SXXX</timestampFormat>
|
||||
<versionPropertyName>hapifhir.version</versionPropertyName>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
<resources>
|
||||
<resource>
|
||||
<directory>src/main/resources</directory>
|
||||
<filtering>true</filtering>
|
||||
</resource>
|
||||
<resource>
|
||||
<directory>${project.build.directory}/generated-sources/properties</directory>
|
||||
<filtering>false</filtering>
|
||||
</resource>
|
||||
</resources>
|
||||
</build>
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package ca.uhn.fhir.rest.gclient;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
@ -98,6 +100,18 @@ public class ReferenceClientParam extends BaseClientParam implements IParam {
|
|||
return new StringCriterion<>(getParamName(), theIds);
|
||||
}
|
||||
|
||||
/**
|
||||
* Match the referenced resource if the resource has ANY of the given IDs
|
||||
* (this is an OR search, not an AND search), (this can be the logical ID or
|
||||
* the absolute URL of the resource). Note that to specify an AND search,
|
||||
* simply add a subsequent {@link IQuery#where(ICriterion) where} criteria
|
||||
* with the same parameter.
|
||||
*/
|
||||
public ICriterion<ReferenceClientParam> hasAnyOfIds(String... theIds) {
|
||||
Validate.notNull(theIds, "theIds must not be null");
|
||||
return hasAnyOfIds(Arrays.asList(theIds));
|
||||
}
|
||||
|
||||
private static class ReferenceChainCriterion implements ICriterion<ReferenceClientParam>, ICriterionInternal {
|
||||
|
||||
private final String myResourceTypeQualifier;
|
||||
|
|
|
@ -62,5 +62,10 @@ public abstract class BaseAndListParam<T extends IQueryParameterOr<?>> implement
|
|||
return myValues.toString();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns the number of AND parameters
|
||||
*/
|
||||
public int size() {
|
||||
return myValues.size();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -255,7 +255,15 @@ public class DateParam extends BaseParamWithPrefix<DateParam> implements /*IQuer
|
|||
return b.build();
|
||||
}
|
||||
|
||||
public class DateParamDateTimeHolder extends BaseDateTimeDt {
|
||||
public static class DateParamDateTimeHolder extends BaseDateTimeDt {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public DateParamDateTimeHolder() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected TemporalPrecisionEnum getDefaultPrecisionForDatatype() {
|
||||
return TemporalPrecisionEnum.SECOND;
|
||||
|
|
|
@ -20,8 +20,10 @@ import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -208,6 +210,13 @@ public class ParameterUtil {
|
|||
|| IPrimitiveType.class.isAssignableFrom(theClass);
|
||||
}
|
||||
|
||||
public static String escapeAndJoinOrList(Collection<String> theValues) {
|
||||
return theValues
|
||||
.stream()
|
||||
.map(ParameterUtil::escape)
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
public static int nonEscapedIndexOf(String theString, char theCharacter) {
|
||||
for (int i = 0; i < theString.length(); i++) {
|
||||
if (theString.charAt(i) == theCharacter) {
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import com.google.common.escape.Escaper;
|
||||
|
@ -172,8 +175,13 @@ public class UrlUtil {
|
|||
return true;
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
System.out.println(escapeUrlParam("http://snomed.info/sct?fhir_vs=isa/126851005"));
|
||||
public static RuntimeResourceDefinition parseUrlResourceType(FhirContext theCtx, String theUrl) throws DataFormatException {
|
||||
int paramIndex = theUrl.indexOf('?');
|
||||
String resourceName = theUrl.substring(0, paramIndex);
|
||||
if (resourceName.contains("/")) {
|
||||
resourceName = resourceName.substring(resourceName.lastIndexOf('/') + 1);
|
||||
}
|
||||
return theCtx.getResourceDefinition(resourceName);
|
||||
}
|
||||
|
||||
public static Map<String, String[]> parseQueryString(String theQueryString) {
|
||||
|
|
|
@ -20,9 +20,13 @@ package ca.uhn.fhir.util;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.util.Properties;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.defaultIfBlank;
|
||||
|
||||
/**
|
||||
* Used internally by HAPI to log the version of the HAPI FHIR framework
|
||||
* once, when the framework is first loaded by the classloader.
|
||||
|
@ -31,21 +35,43 @@ public class VersionUtil {
|
|||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(VersionUtil.class);
|
||||
private static String ourVersion;
|
||||
private static String ourBuildNumber;
|
||||
private static String ourBuildTime;
|
||||
|
||||
static {
|
||||
initialize();
|
||||
}
|
||||
|
||||
public static String getBuildNumber() {
|
||||
return ourBuildNumber;
|
||||
}
|
||||
|
||||
public static String getBuildTime() {
|
||||
return ourBuildTime;
|
||||
}
|
||||
|
||||
public static String getVersion() {
|
||||
return ourVersion;
|
||||
}
|
||||
|
||||
private static void initialize() {
|
||||
try (InputStream is = VersionUtil.class.getResourceAsStream("/ca/uhn/fhir/hapi-version.properties")) {
|
||||
try (InputStream is = VersionUtil.class.getResourceAsStream("/ca/uhn/fhir/hapi-fhir-base-build.properties")) {
|
||||
|
||||
Properties p = new Properties();
|
||||
if (is != null) {
|
||||
p.load(is);
|
||||
ourVersion = p.getProperty("version");
|
||||
ourLog.info("HAPI FHIR version is: " + ourVersion);
|
||||
}
|
||||
|
||||
ourVersion = p.getProperty("hapifhir.version");
|
||||
ourVersion = defaultIfBlank(ourVersion, "(unknown)");
|
||||
|
||||
ourBuildNumber = p.getProperty("hapifhir.buildnumber");
|
||||
ourBuildTime = p.getProperty("hapifhir.timestamp");
|
||||
|
||||
if (System.getProperty("suppress_hapi_fhir_version_log") == null) {
|
||||
ourLog.info("HAPI FHIR version {} - Rev {}", ourVersion, StringUtils.right(ourBuildNumber, 10));
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
ourLog.warn("Unable to determine HAPI version information", e);
|
||||
}
|
||||
|
|
|
@ -29,14 +29,14 @@ public interface IAnyResource extends IBaseResource {
|
|||
* Search parameter constant for <b>_language</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_language", path="", description="The language of the resource", type="string" )
|
||||
public static final String SP_RES_LANGUAGE = "_language";
|
||||
String SP_RES_LANGUAGE = "_language";
|
||||
|
||||
|
||||
/**
|
||||
* Search parameter constant for <b>_id</b>
|
||||
*/
|
||||
@SearchParamDefinition(name="_id", path="", description="The ID of the resource", type="token" )
|
||||
public static final String SP_RES_ID = "_id";
|
||||
String SP_RES_ID = "_id";
|
||||
|
||||
/**
|
||||
* <b>Fluent Client</b> search parameter constant for <b>_id</b>
|
||||
|
@ -46,7 +46,7 @@ public interface IAnyResource extends IBaseResource {
|
|||
* Path: <b>Resource._id</b><br>
|
||||
* </p>
|
||||
*/
|
||||
public static final TokenClientParam RES_ID = new TokenClientParam(IAnyResource.SP_RES_ID);
|
||||
TokenClientParam RES_ID = new TokenClientParam(IAnyResource.SP_RES_ID);
|
||||
|
||||
String getId();
|
||||
|
||||
|
@ -55,11 +55,11 @@ public interface IAnyResource extends IBaseResource {
|
|||
|
||||
IPrimitiveType<String> getLanguageElement();
|
||||
|
||||
public Object getUserData(String name);
|
||||
Object getUserData(String name);
|
||||
|
||||
@Override
|
||||
IAnyResource setId(String theId);
|
||||
|
||||
public void setUserData(String name, Object value);
|
||||
void setUserData(String name, Object value);
|
||||
|
||||
}
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
version=${project.version}
|
|
@ -0,0 +1,19 @@
|
|||
package ca.uhn.fhir.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.not;
|
||||
import static org.hamcrest.Matchers.blankOrNullString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class VersionUtilTest {
|
||||
|
||||
@Test
|
||||
public void testProperties() {
|
||||
assertThat(VersionUtil.getVersion(), not(blankOrNullString()));
|
||||
assertThat(VersionUtil.getBuildNumber(), not(blankOrNullString()));
|
||||
assertThat(VersionUtil.getBuildTime(), not(blankOrNullString()));
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -301,7 +301,7 @@ public abstract class RestfulClientFactory implements IRestfulClientFactory {
|
|||
conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute();
|
||||
} catch (FhirClientConnectionException e) {
|
||||
if (!myContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3) && e.getCause() instanceof DataFormatException) {
|
||||
capabilityStatementResourceName = "Conformance";
|
||||
capabilityStatementResourceName = "CapabilityStatement";
|
||||
implementingClass = myContext.getResourceDefinition(capabilityStatementResourceName).getImplementingClass();
|
||||
conformance = (IBaseResource) client.fetchConformance().ofType(implementingClass).execute();
|
||||
} else {
|
||||
|
|
|
@ -81,7 +81,7 @@ public abstract class BaseQueryParameter implements IParameter {
|
|||
String paramName = isNotBlank(qualifier) ? getName() + qualifier : getName();
|
||||
List<String> paramValues = theTargetQueryArguments.get(paramName);
|
||||
if (paramValues == null) {
|
||||
paramValues = new ArrayList<String>(value.size());
|
||||
paramValues = new ArrayList<>(value.size());
|
||||
theTargetQueryArguments.put(paramName, paramValues);
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,8 @@ import javax.annotation.Nonnull;
|
|||
@ComponentScan(basePackages = "ca.uhn.fhir.jpa", excludeFilters = {
|
||||
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = BaseConfig.class),
|
||||
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = WebSocketConfigurer.class),
|
||||
@ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*\\.test\\..*"),
|
||||
@ComponentScan.Filter(type = FilterType.REGEX, pattern = ".*Test.*"),
|
||||
@ComponentScan.Filter(type = FilterType.REGEX, pattern = "ca.uhn.fhir.jpa.subscription.module.standalone.*")})
|
||||
|
||||
public abstract class BaseConfig implements SchedulingConfigurer {
|
||||
|
|
|
@ -7,6 +7,9 @@ import ca.uhn.fhir.jpa.dao.index.IdHelperService;
|
|||
import ca.uhn.fhir.jpa.dao.index.SearchParamWithInlineReferencesExtractor;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorBroadcaster;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||
import ca.uhn.fhir.jpa.searchparam.ResourceMetaParams;
|
||||
|
@ -58,7 +61,6 @@ import org.hibernate.Session;
|
|||
import org.hibernate.internal.SessionImpl;
|
||||
import org.hl7.fhir.instance.model.api.*;
|
||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
||||
import org.hl7.fhir.r4.model.InstantType;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
|
@ -70,6 +72,8 @@ import org.springframework.data.domain.SliceImpl;
|
|||
import org.springframework.stereotype.Repository;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
@ -116,7 +120,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
public static final String OO_SEVERITY_INFO = "information";
|
||||
public static final String OO_SEVERITY_WARN = "warning";
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirDao.class);
|
||||
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<FhirVersionEnum, FhirContext>();
|
||||
private static final Map<FhirVersionEnum, FhirContext> ourRetrievalContexts = new HashMap<>();
|
||||
private static final String PROCESSING_SUB_REQUEST = "BaseHapiFhirDao.processingSubRequest";
|
||||
private static boolean ourValidationDisabledForUnitTest;
|
||||
private static boolean ourDisableIncrementOnUpdateForUnitTest = false;
|
||||
|
@ -126,6 +130,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
@Autowired
|
||||
protected IdHelperService myIdHelperService;
|
||||
@Autowired
|
||||
protected IInterceptorBroadcaster myInterceptorBroadcaster;
|
||||
@Autowired
|
||||
protected IForcedIdDao myForcedIdDao;
|
||||
@Autowired
|
||||
protected ISearchResultDao mySearchResultDao;
|
||||
|
@ -1421,9 +1427,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
return updateEntity(theRequest, theResource, entity, theDeletedTimestampOrNull, true, true, theUpdateTime, false, true);
|
||||
}
|
||||
|
||||
public ResourceTable updateInternal(RequestDetails theRequest, T theResource, boolean thePerformIndexing,
|
||||
boolean theForceUpdateVersion, RequestDetails theRequestDetails, ResourceTable theEntity, IIdType
|
||||
theResourceId, IBaseResource theOldResource) {
|
||||
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
||||
ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) {
|
||||
// Notify interceptors
|
||||
ActionRequestDetails requestDetails;
|
||||
if (theRequestDetails != null) {
|
||||
|
@ -1440,9 +1445,13 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
((IServerOperationInterceptor) next).resourcePreUpdate(theRequestDetails, theOldResource, theResource);
|
||||
}
|
||||
}
|
||||
HookParams hookParams = new HookParams()
|
||||
.add(IBaseResource.class, theOldResource)
|
||||
.add(IBaseResource.class, theResource);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRESTORAGE_RESOURCE_UPDATED, hookParams);
|
||||
|
||||
// Perform update
|
||||
ResourceTable savedEntity = updateEntity(theRequest, theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
||||
ResourceTable savedEntity = updateEntity(theRequestDetails, theResource, theEntity, null, thePerformIndexing, thePerformIndexing, new Date(), theForceUpdateVersion, thePerformIndexing);
|
||||
|
||||
/*
|
||||
* If we aren't indexing (meaning we're probably executing a sub-operation within a transaction),
|
||||
|
@ -1471,7 +1480,17 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
((IServerOperationInterceptor) next).resourceUpdated(theRequestDetails, theOldResource, theResource);
|
||||
}
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly) {
|
||||
HookParams hookParams = new HookParams()
|
||||
.add(IBaseResource.class, theOldResource)
|
||||
.add(IBaseResource.class, theResource);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, hookParams);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return savedEntity;
|
||||
}
|
||||
|
||||
|
@ -1481,6 +1500,10 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
|||
id = getContext().getVersion().newIdType().setValue(id.getValue());
|
||||
}
|
||||
|
||||
if (id.hasResourceType() == false) {
|
||||
id = id.withResourceType(theEntity.getResourceType());
|
||||
}
|
||||
|
||||
theResource.setId(id);
|
||||
if (theResource instanceof IResource) {
|
||||
ResourceMetadataKeyEnum.VERSION.put((IResource) theResource, id.getVersionIdPart());
|
||||
|
|
|
@ -26,6 +26,8 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.dao.r4.MatchResourceUrlService;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.HookParams;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.PersistedJpaBundleProvider;
|
||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||
|
@ -35,7 +37,9 @@ import ca.uhn.fhir.jpa.util.ExpungeOptions;
|
|||
import ca.uhn.fhir.jpa.util.ExpungeOutcome;
|
||||
import ca.uhn.fhir.jpa.util.jsonpatch.JsonPatchUtils;
|
||||
import ca.uhn.fhir.jpa.util.xmlpatch.XmlPatchUtils;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterAnd;
|
||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
|
@ -57,10 +61,11 @@ 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.TransactionSynchronizationAdapter;
|
||||
import org.springframework.transaction.support.TransactionSynchronizationManager;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.TypedQuery;
|
||||
|
@ -172,7 +177,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome delete(IIdType theId, List<DeleteConflict> theDeleteConflicts, RequestDetails theReques) {
|
||||
public DaoMethodOutcome delete(IIdType theId, List<DeleteConflict> theDeleteConflicts, RequestDetails theRequest) {
|
||||
if (theId == null || !theId.hasIdPart()) {
|
||||
throw new InvalidRequestException("Can not perform delete, no ID provided");
|
||||
}
|
||||
|
@ -205,12 +210,12 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
T resourceToDelete = toResource(myResourceType, entity, null, false);
|
||||
|
||||
// Notify IServerOperationInterceptors about pre-action call
|
||||
if (theReques != null) {
|
||||
theReques.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
||||
if (theRequest != null) {
|
||||
theRequest.getRequestOperationCallback().resourcePreDelete(resourceToDelete);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourcePreDelete(theReques, resourceToDelete);
|
||||
((IServerOperationInterceptor) next).resourcePreDelete(theRequest, resourceToDelete);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -219,25 +224,33 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
preDelete(resourceToDelete, entity);
|
||||
|
||||
// Notify interceptors
|
||||
if (theReques != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theReques, getContext(), theId.getResourceType(), theId);
|
||||
if (theRequest != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getContext(), theId.getResourceType(), theId);
|
||||
notifyInterceptors(RestOperationTypeEnum.DELETE, requestDetails);
|
||||
}
|
||||
|
||||
Date updateTime = new Date();
|
||||
ResourceTable savedEntity = updateEntity(theReques, null, entity, updateTime, updateTime);
|
||||
ResourceTable savedEntity = updateEntity(theRequest, null, entity, updateTime, updateTime);
|
||||
resourceToDelete.setId(entity.getIdDt());
|
||||
|
||||
// Notify JPA interceptors
|
||||
if (theReques != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theReques, getContext(), theId.getResourceType(), theId);
|
||||
theReques.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
||||
if (theRequest != null) {
|
||||
ActionRequestDetails requestDetails = new ActionRequestDetails(theRequest, getContext(), theId.getResourceType(), theId);
|
||||
theRequest.getRequestOperationCallback().resourceDeleted(resourceToDelete);
|
||||
}
|
||||
for (IServerInterceptor next : getConfig().getInterceptors()) {
|
||||
if (next instanceof IServerOperationInterceptor) {
|
||||
((IServerOperationInterceptor) next).resourceDeleted(theReques, resourceToDelete);
|
||||
((IServerOperationInterceptor) next).resourceDeleted(theRequest, resourceToDelete);
|
||||
}
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly) {
|
||||
HookParams hookParams = new HookParams()
|
||||
.add(IBaseResource.class, resourceToDelete);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
||||
}
|
||||
});
|
||||
|
||||
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, resourceToDelete).setCreated(true);
|
||||
|
||||
|
@ -320,6 +333,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
((IServerOperationInterceptor) next).resourceDeleted(theRequest, resourceToDelete);
|
||||
}
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly) {
|
||||
HookParams hookParams = new HookParams()
|
||||
.add(IBaseResource.class, resourceToDelete);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED, hookParams);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
IBaseOperationOutcome oo;
|
||||
|
@ -422,6 +443,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
((IServerOperationInterceptor) next).resourcePreCreate(theRequest, theResource);
|
||||
}
|
||||
}
|
||||
HookParams hookParams = new HookParams()
|
||||
.add(IBaseResource.class, theResource);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRESTORAGE_RESOURCE_CREATED, hookParams);
|
||||
|
||||
// Perform actual DB update
|
||||
ResourceTable updatedEntity = updateEntity(theRequest, theResource, entity, null, thePerformIndexing, thePerformIndexing, theUpdateTime, false, thePerformIndexing);
|
||||
|
@ -465,6 +489,14 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
}
|
||||
}
|
||||
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronizationAdapter() {
|
||||
@Override
|
||||
public void beforeCommit(boolean readOnly) {
|
||||
HookParams hookParams = new HookParams()
|
||||
.add(IBaseResource.class, theResource);
|
||||
myInterceptorBroadcaster.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED, hookParams);
|
||||
}
|
||||
});
|
||||
|
||||
DaoMethodOutcome outcome = toMethodOutcome(entity, theResource).setCreated(true);
|
||||
if (!thePerformIndexing) {
|
||||
|
@ -752,7 +784,6 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@SuppressWarnings("JpaQlInspection")
|
||||
@Override
|
||||
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, RequestDetails theRequestDetails) {
|
||||
// Notify interceptors
|
||||
|
@ -943,8 +974,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
|
||||
if (entity == null) {
|
||||
if (theId.hasVersionIdPart()) {
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager
|
||||
.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
||||
TypedQuery<ResourceHistoryTable> q = myEntityManager.createQuery("SELECT t from ResourceHistoryTable t WHERE t.myResourceId = :RID AND t.myResourceType = :RTYP AND t.myResourceVersion = :RVER", ResourceHistoryTable.class);
|
||||
q.setParameter("RID", pid);
|
||||
q.setParameter("RTYP", myResourceName);
|
||||
q.setParameter("RVER", theId.getVersionIdPartAsLong());
|
||||
|
@ -1304,7 +1334,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
/*
|
||||
* Otherwise, we're not in a transaction
|
||||
*/
|
||||
ResourceTable savedEntity = updateInternal(theRequestDetails, theResource, thePerformIndexing, theForceUpdateVersion, theRequestDetails, entity, resourceId, oldResource);
|
||||
ResourceTable savedEntity = updateInternal(theRequestDetails, theResource, thePerformIndexing, theForceUpdateVersion, entity, resourceId, oldResource);
|
||||
DaoMethodOutcome outcome = toMethodOutcome(savedEntity, theResource).setCreated(false);
|
||||
|
||||
if (!thePerformIndexing) {
|
||||
|
@ -1319,13 +1349,13 @@ public abstract class BaseHapiFhirResourceDao<T extends IBaseResource> extends B
|
|||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing, RequestDetails theRequestDetails) {
|
||||
return update(theResource, theMatchUrl, thePerformIndexing, false, theRequestDetails);
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, RequestDetails theRequestDetails) {
|
||||
return update(theResource, theMatchUrl, true, theRequestDetails);
|
||||
}
|
||||
|
||||
@Override
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, RequestDetails theRequestDetails) {
|
||||
return update(theResource, theMatchUrl, true, theRequestDetails);
|
||||
public DaoMethodOutcome update(T theResource, String theMatchUrl, boolean thePerformIndexing, RequestDetails theRequestDetails) {
|
||||
return update(theResource, theMatchUrl, thePerformIndexing, false, theRequestDetails);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -143,7 +143,6 @@ public class DaoConfig {
|
|||
private boolean myDisableHashBasedSearches;
|
||||
private boolean myEnableInMemorySubscriptionMatching = true;
|
||||
private ClientIdStrategyEnum myResourceClientIdStrategy = ClientIdStrategyEnum.ALPHANUMERIC;
|
||||
private boolean mySubscriptionMatchingEnabled = true;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -530,7 +529,7 @@ public class DaoConfig {
|
|||
* This may be used to optionally register server interceptors directly against the DAOs.
|
||||
*/
|
||||
public void setInterceptors(IServerInterceptor... theInterceptor) {
|
||||
setInterceptors(new ArrayList<IServerInterceptor>());
|
||||
setInterceptors(new ArrayList<>());
|
||||
if (theInterceptor != null && theInterceptor.length != 0) {
|
||||
getInterceptors().addAll(Arrays.asList(theInterceptor));
|
||||
}
|
||||
|
@ -1308,8 +1307,7 @@ public class DaoConfig {
|
|||
public void setSearchPreFetchThresholds(List<Integer> thePreFetchThresholds) {
|
||||
Validate.isTrue(thePreFetchThresholds.size() > 0, "thePreFetchThresholds must not be empty");
|
||||
int last = 0;
|
||||
for (Integer nextInteger : thePreFetchThresholds) {
|
||||
int nextInt = nextInteger.intValue();
|
||||
for (Integer nextInt : thePreFetchThresholds) {
|
||||
Validate.isTrue(nextInt > 0 || nextInt == -1, nextInt + " is not a valid prefetch threshold");
|
||||
Validate.isTrue(nextInt != last, "Prefetch thresholds must be sequential");
|
||||
Validate.isTrue(nextInt > last || nextInt == -1, "Prefetch thresholds must be sequential");
|
||||
|
@ -1398,7 +1396,7 @@ public class DaoConfig {
|
|||
*/
|
||||
|
||||
public boolean isSubscriptionMatchingEnabled() {
|
||||
return mySubscriptionMatchingEnabled;
|
||||
return myModelConfig.isSubscriptionMatchingEnabled();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1407,9 +1405,8 @@ public class DaoConfig {
|
|||
* @since 3.7.0
|
||||
*/
|
||||
|
||||
|
||||
public void setSubscriptionMatchingEnabled(boolean theSubscriptionMatchingEnabled) {
|
||||
mySubscriptionMatchingEnabled = theSubscriptionMatchingEnabled;
|
||||
myModelConfig.setSubscriptionMatchingEnabled(theSubscriptionMatchingEnabled);
|
||||
}
|
||||
|
||||
public ModelConfig getModelConfig() {
|
||||
|
|
|
@ -44,12 +44,8 @@ public class DaoSearchParamProvider implements ISearchParamProvider {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <SP extends IBaseResource> void refreshCache(BaseSearchParamRegistry<SP> theSearchParamRegistry, long theRefreshInterval) {
|
||||
public <SP extends IBaseResource> int refreshCache(BaseSearchParamRegistry<SP> theSearchParamRegistry, long theRefreshInterval) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.execute(t->{
|
||||
theSearchParamRegistry.doRefresh(theRefreshInterval);
|
||||
return null;
|
||||
});
|
||||
|
||||
return txTemplate.execute(t-> theSearchParamRegistry.doRefresh(theRefreshInterval));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -233,7 +233,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
Entry nextRespEntry = response.getEntry().get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails(theRequestDetails);
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
@ -492,7 +492,7 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
|
|||
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
|
||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
if (theUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateInternal(theRequestDetails, nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
updateInternal(theRequestDetails, nextResource, true, false, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
} else if (!theNonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||
updateEntity(theRequestDetails, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||
}
|
||||
|
|
|
@ -80,7 +80,6 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Scope;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.thymeleaf.util.ListUtils;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import javax.annotation.Nullable;
|
||||
|
@ -100,7 +99,6 @@ import static org.apache.commons.lang3.StringUtils.*;
|
|||
* The SearchBuilder is responsible for actually forming the SQL query that handles
|
||||
* searches for resources
|
||||
*/
|
||||
@SuppressWarnings("JpaQlInspection")
|
||||
@Component
|
||||
@Scope("prototype")
|
||||
public class SearchBuilder implements ISearchBuilder {
|
||||
|
@ -386,7 +384,8 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
|
||||
List<Predicate> codePredicates = new ArrayList<>();
|
||||
|
||||
for (IQueryParameterType nextOr : theList) {
|
||||
for (int orIdx = 0; orIdx < theList.size(); orIdx++) {
|
||||
IQueryParameterType nextOr = theList.get(orIdx);
|
||||
|
||||
if (nextOr instanceof ReferenceParam) {
|
||||
ReferenceParam ref = (ReferenceParam) nextOr;
|
||||
|
@ -497,6 +496,8 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
|
||||
boolean foundChainMatch = false;
|
||||
|
||||
for (Class<? extends IBaseResource> nextType : resourceTypes) {
|
||||
|
||||
String chain = ref.getChain();
|
||||
String remainingChain = null;
|
||||
int chainDotIndex = chain.indexOf('.');
|
||||
|
@ -505,7 +506,6 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
chain = chain.substring(0, chainDotIndex);
|
||||
}
|
||||
|
||||
for (Class<? extends IBaseResource> nextType : resourceTypes) {
|
||||
RuntimeResourceDefinition typeDef = myContext.getResourceDefinition(nextType);
|
||||
String subResourceName = typeDef.getName();
|
||||
|
||||
|
@ -532,37 +532,29 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
}
|
||||
}
|
||||
|
||||
IQueryParameterType chainValue;
|
||||
if (remainingChain != null) {
|
||||
if (param == null || param.getParamType() != RestSearchParameterTypeEnum.REFERENCE) {
|
||||
ourLog.debug("Type {} parameter {} is not a reference, can not chain {}", nextType.getSimpleName(), chain, remainingChain);
|
||||
ArrayList<IQueryParameterType> orValues = Lists.newArrayList();
|
||||
|
||||
for (IQueryParameterType next : theList) {
|
||||
String nextValue = next.getValueAsQueryToken(myContext);
|
||||
IQueryParameterType chainValue = mapReferenceChainToRawParamType(remainingChain, param, theParamName, qualifier, nextType, chain, isMeta, nextValue);
|
||||
if (chainValue == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
chainValue = new ReferenceParam();
|
||||
chainValue.setValueAsQueryToken(myContext, theParamName, qualifier, resourceId);
|
||||
((ReferenceParam) chainValue).setChain(remainingChain);
|
||||
} else if (isMeta) {
|
||||
IQueryParameterType type = myMatchUrlService.newInstanceType(chain);
|
||||
type.setValueAsQueryToken(myContext, theParamName, qualifier, resourceId);
|
||||
chainValue = type;
|
||||
} else {
|
||||
chainValue = toParameterType(param, qualifier, resourceId);
|
||||
}
|
||||
|
||||
foundChainMatch = true;
|
||||
orValues.add(chainValue);
|
||||
}
|
||||
|
||||
Subquery<Long> subQ = myResourceTableQuery.subquery(Long.class);
|
||||
Root<ResourceTable> subQfrom = subQ.from(ResourceTable.class);
|
||||
subQ.select(subQfrom.get("myId").as(Long.class));
|
||||
|
||||
List<List<? extends IQueryParameterType>> andOrParams = new ArrayList<>();
|
||||
andOrParams.add(Collections.singletonList(chainValue));
|
||||
andOrParams.add(orValues);
|
||||
|
||||
/*
|
||||
* We're doing a chain call, so push the current query root
|
||||
* and predicate list down and put new ones at the top of the
|
||||
* stack and run a subuery
|
||||
* stack and run a subquery
|
||||
*/
|
||||
Root<ResourceTable> stackRoot = myResourceTableRoot;
|
||||
ArrayList<Predicate> stackPredicates = myPredicates;
|
||||
|
@ -574,9 +566,11 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
// Create the subquery predicates
|
||||
myPredicates.add(myBuilder.equal(myResourceTableRoot.get("myResourceType"), subResourceName));
|
||||
myPredicates.add(myBuilder.isNull(myResourceTableRoot.get("myDeleted")));
|
||||
searchForIdsWithAndOr(subResourceName, chain, andOrParams);
|
||||
|
||||
if (foundChainMatch) {
|
||||
searchForIdsWithAndOr(subResourceName, chain, andOrParams);
|
||||
subQ.where(toArray(myPredicates));
|
||||
}
|
||||
|
||||
/*
|
||||
* Pop the old query root and predicate list back
|
||||
|
@ -594,6 +588,10 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
if (!foundChainMatch) {
|
||||
throw new InvalidRequestException(myContext.getLocalizer().getMessage(BaseHapiFhirResourceDao.class, "invalidParameterChain", theParamName + '.' + ref.getChain()));
|
||||
}
|
||||
|
||||
myPredicates.add(myBuilder.or(toArray(codePredicates)));
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
} else {
|
||||
|
@ -605,6 +603,28 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
myPredicates.add(myBuilder.or(toArray(codePredicates)));
|
||||
}
|
||||
|
||||
private IQueryParameterType mapReferenceChainToRawParamType(String remainingChain, RuntimeSearchParam param, String theParamName, String qualifier, Class<? extends IBaseResource> nextType, String chain, boolean isMeta, String resourceId) {
|
||||
IQueryParameterType chainValue;
|
||||
if (remainingChain != null) {
|
||||
if (param == null || param.getParamType() != RestSearchParameterTypeEnum.REFERENCE) {
|
||||
ourLog.debug("Type {} parameter {} is not a reference, can not chain {}", nextType.getSimpleName(), chain, remainingChain);
|
||||
return null;
|
||||
}
|
||||
|
||||
chainValue = new ReferenceParam();
|
||||
chainValue.setValueAsQueryToken(myContext, theParamName, qualifier, resourceId);
|
||||
((ReferenceParam) chainValue).setChain(remainingChain);
|
||||
} else if (isMeta) {
|
||||
IQueryParameterType type = myMatchUrlService.newInstanceType(chain);
|
||||
type.setValueAsQueryToken(myContext, theParamName, qualifier, resourceId);
|
||||
chainValue = type;
|
||||
} else {
|
||||
chainValue = toParameterType(param, qualifier, resourceId);
|
||||
}
|
||||
|
||||
return chainValue;
|
||||
}
|
||||
|
||||
private void addPredicateResourceId(List<List<? extends IQueryParameterType>> theValues) {
|
||||
for (List<? extends IQueryParameterType> nextValue : theValues) {
|
||||
Set<Long> orPids = new HashSet<>();
|
||||
|
@ -795,24 +815,27 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
|
||||
private void addPredicateToken(String theResourceName, String theParamName, List<? extends IQueryParameterType> theList) {
|
||||
|
||||
Join<ResourceTable, ResourceIndexedSearchParamToken> join = createOrReuseJoin(JoinEnum.TOKEN, theParamName);
|
||||
|
||||
if (theList.get(0).getMissing() != null) {
|
||||
Join<ResourceTable, ResourceIndexedSearchParamToken> join = createOrReuseJoin(JoinEnum.TOKEN, theParamName);
|
||||
addPredicateParamMissing(theResourceName, theParamName, theList.get(0).getMissing(), join);
|
||||
return;
|
||||
}
|
||||
|
||||
List<Predicate> codePredicates = new ArrayList<>();
|
||||
Join<ResourceTable, ResourceIndexedSearchParamToken> join = null;
|
||||
for (IQueryParameterType nextOr : theList) {
|
||||
|
||||
if (nextOr instanceof TokenParam) {
|
||||
TokenParam id = (TokenParam) nextOr;
|
||||
if (id.isText()) {
|
||||
addPredicateString(theResourceName, theParamName, theList);
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (join == null) {
|
||||
join = createOrReuseJoin(JoinEnum.TOKEN, theParamName);
|
||||
}
|
||||
Predicate singleCode = createPredicateToken(nextOr, theResourceName, theParamName, myBuilder, join);
|
||||
codePredicates.add(singleCode);
|
||||
}
|
||||
|
@ -973,8 +996,9 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> Join<ResourceTable, T> createOrReuseJoin(JoinEnum theType, String theSearchParameterName) {
|
||||
JoinKey key = new JoinKey(theSearchParameterName, theType);
|
||||
return (Join<ResourceTable, T>) myIndexJoins.computeIfAbsent(key, k -> {
|
||||
Join<ResourceTable, ResourceIndexedSearchParamDate> join = null;
|
||||
|
||||
switch (theType) {
|
||||
case DATE:
|
||||
join = myResourceTableRoot.join("myParamsDate", JoinType.LEFT);
|
||||
|
@ -998,13 +1022,8 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
join = myResourceTableRoot.join("myParamsToken", JoinType.LEFT);
|
||||
break;
|
||||
}
|
||||
|
||||
JoinKey key = new JoinKey(theSearchParameterName, theType);
|
||||
if (!myIndexJoins.containsKey(key)) {
|
||||
myIndexJoins.put(key, join);
|
||||
}
|
||||
|
||||
return (Join<ResourceTable, T>) join;
|
||||
return join;
|
||||
});
|
||||
}
|
||||
|
||||
private Predicate createPredicateDate(IQueryParameterType theParam, String theResourceName, String theParamName, CriteriaBuilder theBuilder, From<?, ResourceIndexedSearchParamDate> theFrom) {
|
||||
|
|
|
@ -89,6 +89,52 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
@Autowired
|
||||
private DaoRegistry myDaoRegistry;
|
||||
|
||||
public BUNDLE transaction(RequestDetails theRequestDetails, BUNDLE theRequest) {
|
||||
if (theRequestDetails != null) {
|
||||
IServerInterceptor.ActionRequestDetails requestDetails = new IServerInterceptor.ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
|
||||
myDao.notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
|
||||
}
|
||||
|
||||
String actionName = "Transaction";
|
||||
BUNDLE response = processTransactionAsSubRequest((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
public BUNDLE collection(final RequestDetails theRequestDetails, BUNDLE theRequest) {
|
||||
String transactionType = myVersionAdapter.getBundleType(theRequest);
|
||||
|
||||
if (!org.hl7.fhir.r4.model.Bundle.BundleType.COLLECTION.toCode().equals(transactionType)) {
|
||||
throw new InvalidRequestException("Can not process collection Bundle of type: " + transactionType);
|
||||
}
|
||||
|
||||
ourLog.info("Beginning storing collection with {} resources", myVersionAdapter.getEntries(theRequest).size());
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
|
||||
BUNDLE resp = myVersionAdapter.createBundle(org.hl7.fhir.r4.model.Bundle.BundleType.BATCHRESPONSE.toCode());
|
||||
|
||||
List<IBaseResource> resources = new ArrayList<>();
|
||||
for (final BUNDLEENTRY nextRequestEntry : myVersionAdapter.getEntries(theRequest)) {
|
||||
IBaseResource resource = myVersionAdapter.getResource(nextRequestEntry);
|
||||
resources.add(resource);
|
||||
}
|
||||
|
||||
BUNDLE transactionBundle = myVersionAdapter.createBundle("transaction");
|
||||
for (IBaseResource next : resources) {
|
||||
BUNDLEENTRY entry = myVersionAdapter.addEntry(transactionBundle);
|
||||
myVersionAdapter.setResource(entry, next);
|
||||
myVersionAdapter.setRequestVerb(entry, "PUT");
|
||||
myVersionAdapter.setRequestUrl(entry, next.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
transaction(theRequestDetails, transactionBundle);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
private void populateEntryWithOperationOutcome(BaseServerResponseException caughtEx, BUNDLEENTRY nextEntry) {
|
||||
myVersionAdapter.populateEntryWithOperationOutcome(caughtEx, nextEntry);
|
||||
}
|
||||
|
@ -160,16 +206,6 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
myDao = theDao;
|
||||
}
|
||||
|
||||
public BUNDLE transaction(RequestDetails theRequestDetails, BUNDLE theRequest) {
|
||||
if (theRequestDetails != null) {
|
||||
IServerInterceptor.ActionRequestDetails requestDetails = new IServerInterceptor.ActionRequestDetails(theRequestDetails, theRequest, "Bundle", null);
|
||||
myDao.notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
|
||||
}
|
||||
|
||||
String actionName = "Transaction";
|
||||
return processTransactionAsSubRequest((ServletRequestDetails) theRequestDetails, theRequest, actionName);
|
||||
}
|
||||
|
||||
private BUNDLE processTransactionAsSubRequest(ServletRequestDetails theRequestDetails, BUNDLE theRequest, String theActionName) {
|
||||
BaseHapiFhirDao.markRequestAsProcessingSubRequest(theRequestDetails);
|
||||
try {
|
||||
|
@ -179,40 +215,6 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
}
|
||||
}
|
||||
|
||||
public BUNDLE collection(final RequestDetails theRequestDetails, BUNDLE theRequest) {
|
||||
String transactionType = myVersionAdapter.getBundleType(theRequest);
|
||||
|
||||
if (!org.hl7.fhir.r4.model.Bundle.BundleType.COLLECTION.toCode().equals(transactionType)) {
|
||||
throw new InvalidRequestException("Can not process collection Bundle of type: " + transactionType);
|
||||
}
|
||||
|
||||
ourLog.info("Beginning storing collection with {} resources", myVersionAdapter.getEntries(theRequest).size());
|
||||
long start = System.currentTimeMillis();
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
|
||||
BUNDLE resp = myVersionAdapter.createBundle(org.hl7.fhir.r4.model.Bundle.BundleType.BATCHRESPONSE.toCode());
|
||||
|
||||
List<IBaseResource> resources = new ArrayList<>();
|
||||
for (final BUNDLEENTRY nextRequestEntry : myVersionAdapter.getEntries(theRequest)) {
|
||||
IBaseResource resource = myVersionAdapter.getResource(nextRequestEntry);
|
||||
resources.add(resource);
|
||||
}
|
||||
|
||||
BUNDLE transactionBundle = myVersionAdapter.createBundle("transaction");
|
||||
for (IBaseResource next : resources) {
|
||||
BUNDLEENTRY entry = myVersionAdapter.addEntry(transactionBundle);
|
||||
myVersionAdapter.setResource(entry, next);
|
||||
myVersionAdapter.setRequestVerb(entry, "PUT");
|
||||
myVersionAdapter.setRequestUrl(entry, next.getIdElement().toUnqualifiedVersionless().getValue());
|
||||
}
|
||||
|
||||
transaction(theRequestDetails, transactionBundle);
|
||||
|
||||
return resp;
|
||||
}
|
||||
|
||||
private BUNDLE batch(final RequestDetails theRequestDetails, BUNDLE theRequest) {
|
||||
ourLog.info("Beginning batch with {} resources", myVersionAdapter.getEntries(theRequest).size());
|
||||
long start = System.currentTimeMillis();
|
||||
|
@ -234,8 +236,7 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
BUNDLE subRequestBundle = myVersionAdapter.createBundle(org.hl7.fhir.r4.model.Bundle.BundleType.TRANSACTION.toCode());
|
||||
myVersionAdapter.addEntry(subRequestBundle, nextRequestEntry);
|
||||
|
||||
BUNDLE subResponseBundle = processTransactionAsSubRequest((ServletRequestDetails) theRequestDetails, subRequestBundle, "Batch sub-request");
|
||||
return subResponseBundle;
|
||||
return processTransactionAsSubRequest((ServletRequestDetails) theRequestDetails, subRequestBundle, "Batch sub-request");
|
||||
};
|
||||
|
||||
try {
|
||||
|
@ -384,7 +385,7 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
|
||||
BUNDLEENTRY nextRespEntry = myVersionAdapter.getEntries(response).get(originalOrder);
|
||||
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
|
||||
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails(theRequestDetails);
|
||||
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
|
||||
requestDetails.setRequestType(RequestTypeEnum.GET);
|
||||
requestDetails.setServer(theRequestDetails.getServer());
|
||||
|
@ -472,10 +473,6 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource));
|
||||
}
|
||||
|
||||
public void setEntityManager(EntityManager theEntityManager) {
|
||||
myEntityManager = theEntityManager;
|
||||
}
|
||||
|
||||
private void validateDependencies() {
|
||||
Validate.notNull(myEntityManager);
|
||||
Validate.notNull(myContext);
|
||||
|
@ -526,7 +523,7 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
}
|
||||
}
|
||||
|
||||
if (nextResourceId.hasIdPart() && nextResourceId.getIdPart().matches("[a-zA-Z]+\\:.*") && !isPlaceholder(nextResourceId)) {
|
||||
if (nextResourceId.hasIdPart() && nextResourceId.getIdPart().matches("[a-zA-Z]+:.*") && !isPlaceholder(nextResourceId)) {
|
||||
throw new InvalidRequestException("Invalid placeholder ID found: " + nextResourceId.getIdPart() + " - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'");
|
||||
}
|
||||
|
||||
|
@ -631,7 +628,7 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
version = ParameterUtil.parseETagValue(myVersionAdapter.getEntryRequestIfMatch(nextReqEntry));
|
||||
}
|
||||
res.setId(newIdType(parts.getResourceType(), parts.getResourceId(), version));
|
||||
outcome = resourceDao.update(res, null, false, theRequestDetails);
|
||||
outcome = resourceDao.update(res, null, false, false, theRequestDetails);
|
||||
} else {
|
||||
res.setId((String) null);
|
||||
String matchUrl;
|
||||
|
@ -641,7 +638,7 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
matchUrl = parts.getResourceType();
|
||||
}
|
||||
matchUrl = performIdSubstitutionsInMatchUrl(theIdSubstitutions, matchUrl);
|
||||
outcome = resourceDao.update(res, matchUrl, false, theRequestDetails);
|
||||
outcome = resourceDao.update(res, matchUrl, false, false, theRequestDetails);
|
||||
if (Boolean.TRUE.equals(outcome.getCreated())) {
|
||||
conditionalRequestUrls.put(matchUrl, res.getClass());
|
||||
}
|
||||
|
@ -727,7 +724,7 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
|||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||
|
||||
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||
myDao.updateInternal(theRequestDetails, nextResource, true, false, theRequestDetails, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
myDao.updateInternal(theRequestDetails, nextResource, true, false, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||
myDao.updateEntity(theRequestDetails, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||
}
|
||||
|
|
|
@ -99,7 +99,7 @@ public class SearchParamWithInlineReferencesExtractor {
|
|||
|
||||
extractInlineReferences(theResource);
|
||||
|
||||
myResourceLinkExtractor.extractResourceLinks(theParams, theEntity, theResource, theUpdateTime, myDaoResourceLinkResolver);
|
||||
myResourceLinkExtractor.extractResourceLinks(theParams, theEntity, theResource, theUpdateTime, myDaoResourceLinkResolver, true);
|
||||
|
||||
/*
|
||||
* If the existing resource already has links and those match links we still want, use them instead of removing them and re adding them
|
||||
|
|
|
@ -29,11 +29,25 @@ import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
|||
|
||||
public class ServletSubRequestDetails extends ServletRequestDetails {
|
||||
|
||||
private Map<String, ArrayList<String>> myHeaders = new HashMap<>();
|
||||
private Map<String, List<String>> myHeaders = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theRequestDetails The parent request details
|
||||
*/
|
||||
public ServletSubRequestDetails(ServletRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
Map<String, List<String>> headers = theRequestDetails.getHeaders();
|
||||
for (Map.Entry<String, List<String>> next : headers.entrySet()) {
|
||||
myHeaders.put(next.getKey().toLowerCase(), next.getValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addHeader(String theName, String theValue) {
|
||||
String lowerCase = theName.toLowerCase();
|
||||
ArrayList<String> list = myHeaders.get(lowerCase);
|
||||
List<String> list = myHeaders.get(lowerCase);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
myHeaders.put(lowerCase, list);
|
||||
|
@ -43,7 +57,7 @@ public class ServletSubRequestDetails extends ServletRequestDetails {
|
|||
|
||||
@Override
|
||||
public String getHeader(String theName) {
|
||||
ArrayList<String> list = myHeaders.get(theName.toLowerCase());
|
||||
List<String> list = myHeaders.get(theName.toLowerCase());
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
@ -52,7 +66,7 @@ public class ServletSubRequestDetails extends ServletRequestDetails {
|
|||
|
||||
@Override
|
||||
public List<String> getHeaders(String theName) {
|
||||
ArrayList<String> list = myHeaders.get(theName.toLowerCase());
|
||||
List<String> list = myHeaders.get(theName.toLowerCase());
|
||||
if (list == null || list.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -391,7 +391,6 @@ public class ResourceReindexingSvcImpl implements IResourceReindexingSvc {
|
|||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("JpaQlInspection")
|
||||
private void markResourceAsIndexingFailed(final long theId) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
|
||||
|
|
|
@ -26,9 +26,9 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
|||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
@ -77,7 +77,7 @@ public class CacheWarmingSvcImpl implements ICacheWarmingSvc {
|
|||
private void refreshNow(WarmCacheEntry theCacheEntry) {
|
||||
String nextUrl = theCacheEntry.getUrl();
|
||||
|
||||
RuntimeResourceDefinition resourceDef = parseUrlResourceType(myCtx, nextUrl);
|
||||
RuntimeResourceDefinition resourceDef = UrlUtil.parseUrlResourceType(myCtx, nextUrl);
|
||||
IFhirResourceDao<?> callingDao = myDaoRegistry.getResourceDao(resourceDef.getName());
|
||||
String queryPart = parseWarmUrlParamPart(nextUrl);
|
||||
SearchParameterMap responseCriteriaUrl = myMatchUrlService.translateMatchUrl(queryPart, resourceDef);
|
||||
|
@ -93,20 +93,6 @@ public class CacheWarmingSvcImpl implements ICacheWarmingSvc {
|
|||
return theNextUrl.substring(paramIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: this method probably belongs in a utility class, not here
|
||||
*
|
||||
* @throws DataFormatException If the resource type is not known
|
||||
*/
|
||||
public static RuntimeResourceDefinition parseUrlResourceType(FhirContext theCtx, String theUrl) throws DataFormatException {
|
||||
int paramIndex = theUrl.indexOf('?');
|
||||
String resourceName = theUrl.substring(0, paramIndex);
|
||||
if (resourceName.contains("/")) {
|
||||
resourceName = resourceName.substring(resourceName.lastIndexOf('/') + 1);
|
||||
}
|
||||
return theCtx.getResourceDefinition(resourceName);
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
initCacheMap();
|
||||
|
@ -120,7 +106,7 @@ public class CacheWarmingSvcImpl implements ICacheWarmingSvc {
|
|||
|
||||
// Validate
|
||||
parseWarmUrlParamPart(next.getUrl());
|
||||
parseUrlResourceType(myCtx, next.getUrl());
|
||||
UrlUtil.parseUrlResourceType(myCtx, next.getUrl());
|
||||
|
||||
myCacheEntryToNextRefresh.put(next, 0L);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
package ca.uhn.fhir.jpa.subscription;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR JPA Server
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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.subscription.module.ResourceModifiedMessage;
|
||||
|
||||
public interface IResourceModifiedConsumer {
|
||||
void submitResourceModified(ResourceModifiedMessage theMsg);
|
||||
}
|
|
@ -26,17 +26,20 @@ import ca.uhn.fhir.jpa.config.BaseConfig;
|
|||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.search.warm.CacheWarmingSvcImpl;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionCanonicalizer;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionMatchingStrategy;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionStrategyEvaluator;
|
||||
import ca.uhn.fhir.model.dstu2.valueset.ResourceTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
||||
import ca.uhn.fhir.util.SubscriptionUtil;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.hl7.fhir.instance.model.Subscription;
|
||||
|
@ -68,7 +71,8 @@ import java.util.concurrent.TimeUnit;
|
|||
*/
|
||||
@Service
|
||||
@Lazy
|
||||
public class SubscriptionActivatingInterceptor extends ServerOperationInterceptorAdapter {
|
||||
@Interceptor(manualRegistration = true)
|
||||
public class SubscriptionActivatingInterceptor {
|
||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionActivatingInterceptor.class);
|
||||
|
||||
private static boolean ourWaitForSubscriptionActivationSynchronouslyForUnitTest;
|
||||
|
@ -92,6 +96,8 @@ public class SubscriptionActivatingInterceptor extends ServerOperationIntercepto
|
|||
private MatchUrlService myMatchUrlService;
|
||||
@Autowired
|
||||
private DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
private SubscriptionStrategyEvaluator mySubscriptionStrategyEvaluator;
|
||||
|
||||
public boolean activateOrRegisterSubscriptionIfRequired(final IBaseResource theSubscription) {
|
||||
// Grab the value for "Subscription.channel.type" so we can see if this
|
||||
|
@ -156,10 +162,10 @@ public class SubscriptionActivatingInterceptor extends ServerOperationIntercepto
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
private boolean activateSubscription(String theActiveStatus, final IBaseResource theSubscription, String theRequestedStatus) {
|
||||
IFhirResourceDao subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
IBaseResource subscription = subscriptionDao.read(theSubscription.getIdElement());
|
||||
subscription.setId(subscription.getIdElement().toVersionless());
|
||||
|
||||
ourLog.info("Activating subscription {} from status {} to {}", subscription.getIdElement().toUnqualified().getValue(), theRequestedStatus, theActiveStatus);
|
||||
try {
|
||||
|
@ -180,56 +186,71 @@ public class SubscriptionActivatingInterceptor extends ServerOperationIntercepto
|
|||
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
@Hook(Pointcut.OP_PRESTORAGE_RESOURCE_CREATED)
|
||||
public void addStrategyTagCreated(IBaseResource theResource) {
|
||||
if (isSubscription(theResource)) {
|
||||
validateCriteriaAndAddStrategy(theResource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceDeleted(RequestDetails theRequest, IBaseResource theResource) {
|
||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.DELETE);
|
||||
@Hook(Pointcut.OP_PRESTORAGE_RESOURCE_UPDATED)
|
||||
public void addStrategyTagUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
if (isSubscription(theNewResource)) {
|
||||
validateCriteriaAndAddStrategy(theNewResource);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
// TODO KHS add third type of strategy DISABLED if that subscription type is disabled on this server
|
||||
public void validateCriteriaAndAddStrategy(final IBaseResource theResource) {
|
||||
String criteria = mySubscriptionCanonicalizer.getCriteria(theResource);
|
||||
try {
|
||||
SubscriptionMatchingStrategy strategy = mySubscriptionStrategyEvaluator.determineStrategy(criteria);
|
||||
mySubscriptionCanonicalizer.setMatchingStrategyTag(myFhirContext, theResource, strategy);
|
||||
} catch (InvalidRequestException | DataFormatException e) {
|
||||
throw new UnprocessableEntityException("Invalid subscription criteria submitted: " + criteria + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED)
|
||||
public void resourceUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
||||
}
|
||||
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED)
|
||||
public void resourceCreated(IBaseResource theResource) {
|
||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
}
|
||||
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED)
|
||||
public void resourceDeleted(IBaseResource theResource) {
|
||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.DELETE);
|
||||
}
|
||||
|
||||
private void submitResourceModified(IBaseResource theNewResource, ResourceModifiedMessage.OperationTypeEnum theOperationType) {
|
||||
if (isSubscription(theNewResource)) {
|
||||
submitResourceModified(new ResourceModifiedMessage(myFhirContext, theNewResource, theOperationType));
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isSubscription(IBaseResource theNewResource) {
|
||||
RuntimeResourceDefinition resourceDefinition = myFhirContext.getResourceDefinition(theNewResource);
|
||||
return ResourceTypeEnum.SUBSCRIPTION.getCode().equals(resourceDefinition.getName());
|
||||
}
|
||||
|
||||
private void submitResourceModified(final ResourceModifiedMessage theMsg) {
|
||||
IIdType id = theMsg.getId(myFhirContext);
|
||||
if (!id.getResourceType().equals(ResourceTypeEnum.SUBSCRIPTION.getCode())) {
|
||||
return;
|
||||
}
|
||||
switch (theMsg.getOperationType()) {
|
||||
case DELETE:
|
||||
mySubscriptionRegistry.unregisterSubscription(id);
|
||||
mySubscriptionRegistry.unregisterSubscription(theMsg.getId(myFhirContext));
|
||||
break;
|
||||
case CREATE:
|
||||
case UPDATE:
|
||||
final IBaseResource subscription = theMsg.getNewPayload(myFhirContext);
|
||||
validateCriteria(subscription);
|
||||
activateAndRegisterSubscriptionIfRequiredInTransaction(subscription);
|
||||
activateAndRegisterSubscriptionIfRequiredInTransaction(theMsg.getNewPayload(myFhirContext));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void validateCriteria(final IBaseResource theResource) {
|
||||
CanonicalSubscription subscription = mySubscriptionCanonicalizer.canonicalize(theResource);
|
||||
String criteria = subscription.getCriteriaString();
|
||||
try {
|
||||
RuntimeResourceDefinition resourceDef = CacheWarmingSvcImpl.parseUrlResourceType(myFhirContext, criteria);
|
||||
myMatchUrlService.translateMatchUrl(criteria, resourceDef);
|
||||
} catch (InvalidRequestException e) {
|
||||
throw new UnprocessableEntityException("Invalid subscription criteria submitted: " + criteria + " " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void activateAndRegisterSubscriptionIfRequiredInTransaction(IBaseResource theSubscription) {
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myTransactionManager);
|
||||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
|
|
|
@ -21,6 +21,7 @@ package ca.uhn.fhir.jpa.subscription;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionLoader;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
|
@ -37,52 +38,44 @@ import java.util.Set;
|
|||
public class SubscriptionInterceptorLoader {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionInterceptorLoader.class);
|
||||
|
||||
@Autowired
|
||||
private SubscriptionMatcherInterceptor mySubscriptionMatcherInterceptor;
|
||||
@Autowired
|
||||
private SubscriptionActivatingInterceptor mySubscriptionActivatingInterceptor;
|
||||
|
||||
@Autowired
|
||||
DaoConfig myDaoConfig;
|
||||
@Autowired
|
||||
private SubscriptionRegistry mySubscriptionRegistry;
|
||||
@Autowired
|
||||
private ApplicationContext myAppicationContext;
|
||||
@Autowired
|
||||
private SubscriptionRegistry mySubscriptionRegistry;
|
||||
private IInterceptorRegistry myInterceptorRegistry;
|
||||
|
||||
public void registerInterceptors() {
|
||||
Set<Subscription.SubscriptionChannelType> supportedSubscriptionTypes = myDaoConfig.getSupportedSubscriptionTypes();
|
||||
|
||||
if (!supportedSubscriptionTypes.isEmpty()) {
|
||||
loadSubscriptions();
|
||||
|
||||
ourLog.info("Registering subscription activating interceptor");
|
||||
myDaoConfig.registerInterceptor(mySubscriptionActivatingInterceptor);
|
||||
myInterceptorRegistry.registerInterceptor(mySubscriptionActivatingInterceptor);
|
||||
}
|
||||
if (myDaoConfig.isSubscriptionMatchingEnabled()) {
|
||||
mySubscriptionMatcherInterceptor.start();
|
||||
ourLog.info("Registering subscription matcher interceptor");
|
||||
|
||||
if (mySubscriptionMatcherInterceptor == null) {
|
||||
mySubscriptionMatcherInterceptor = myAppicationContext.getBean(SubscriptionMatcherInterceptor.class);
|
||||
}
|
||||
|
||||
myDaoConfig.registerInterceptor(mySubscriptionMatcherInterceptor);
|
||||
|
||||
myInterceptorRegistry.registerInterceptor(mySubscriptionMatcherInterceptor);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadSubscriptions() {
|
||||
ourLog.info("Loading subscriptions into the SubscriptionRegistry...");
|
||||
// Load subscriptions into the SubscriptionRegistry
|
||||
// Activate scheduled subscription loads into the SubscriptionRegistry
|
||||
myAppicationContext.getBean(SubscriptionLoader.class);
|
||||
ourLog.info("...{} subscriptions loaded", mySubscriptionRegistry.size());
|
||||
|
||||
// Once subscriptions have been loaded, now
|
||||
if (mySubscriptionActivatingInterceptor == null) {
|
||||
mySubscriptionActivatingInterceptor = myAppicationContext.getBean(SubscriptionActivatingInterceptor.class);
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void unregisterInterceptorsForUnitTest() {
|
||||
myDaoConfig.unregisterInterceptor(mySubscriptionActivatingInterceptor);
|
||||
myDaoConfig.unregisterInterceptor(mySubscriptionMatcherInterceptor);
|
||||
void unregisterInterceptorsForUnitTest() {
|
||||
myInterceptorRegistry.unregisterInterceptor(mySubscriptionActivatingInterceptor);
|
||||
myInterceptorRegistry.unregisterInterceptor(mySubscriptionMatcherInterceptor);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,16 @@
|
|||
package ca.uhn.fhir.jpa.subscription;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.subscription.module.LinkedBlockingQueueSubscribableChannel;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionChannelFactory;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceModifiedJsonMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.SubscriptionMatchingSubscriber;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.interceptor.ServerOperationInterceptorAdapter;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -17,7 +19,6 @@ import org.springframework.context.annotation.Lazy;
|
|||
import org.springframework.messaging.SubscribableChannel;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
|
||||
/*-
|
||||
|
@ -42,9 +43,11 @@ import javax.annotation.PreDestroy;
|
|||
|
||||
@Component
|
||||
@Lazy
|
||||
public class SubscriptionMatcherInterceptor extends ServerOperationInterceptorAdapter {
|
||||
@Interceptor(manualRegistration = true)
|
||||
public class SubscriptionMatcherInterceptor implements IResourceModifiedConsumer {
|
||||
private Logger ourLog = LoggerFactory.getLogger(SubscriptionMatcherInterceptor.class);
|
||||
|
||||
private static final String SUBSCRIPTION_MATCHING_CHANNEL_NAME = "subscription-matching";
|
||||
static final String SUBSCRIPTION_STATUS = "Subscription.status";
|
||||
static final String SUBSCRIPTION_TYPE = "Subscription.channel.type";
|
||||
private SubscribableChannel myProcessingChannel;
|
||||
|
@ -63,32 +66,36 @@ public class SubscriptionMatcherInterceptor extends ServerOperationInterceptorAd
|
|||
super();
|
||||
}
|
||||
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
if (myProcessingChannel == null) {
|
||||
myProcessingChannel = mySubscriptionChannelFactory.newMatchingChannel("subscription-matching");
|
||||
myProcessingChannel = mySubscriptionChannelFactory.newMatchingChannel(SUBSCRIPTION_MATCHING_CHANNEL_NAME);
|
||||
}
|
||||
myProcessingChannel.subscribe(mySubscriptionMatchingSubscriber);
|
||||
ourLog.info("Subscription Matching Subscriber subscribed to Matching Channel {} with name {}", myProcessingChannel.getClass().getName(), SUBSCRIPTION_MATCHING_CHANNEL_NAME);
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@PreDestroy
|
||||
public void preDestroy() {
|
||||
|
||||
if (myProcessingChannel != null) {
|
||||
myProcessingChannel.unsubscribe(mySubscriptionMatchingSubscriber);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceCreated(RequestDetails theRequest, IBaseResource theResource) {
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED)
|
||||
public void resourceCreated(IBaseResource theResource) {
|
||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceDeleted(RequestDetails theRequest, IBaseResource theResource) {
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_DELETED)
|
||||
public void resourceDeleted(IBaseResource theResource) {
|
||||
submitResourceModified(theResource, ResourceModifiedMessage.OperationTypeEnum.DELETE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resourceUpdated(RequestDetails theRequest, IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED)
|
||||
public void resourceUpdated(IBaseResource theOldResource, IBaseResource theNewResource) {
|
||||
submitResourceModified(theNewResource, ResourceModifiedMessage.OperationTypeEnum.UPDATE);
|
||||
}
|
||||
|
||||
|
@ -97,8 +104,9 @@ public class SubscriptionMatcherInterceptor extends ServerOperationInterceptorAd
|
|||
submitResourceModified(msg);
|
||||
}
|
||||
|
||||
protected void sendToProcessingChannel(final ResourceModifiedMessage theMessage) {
|
||||
private void sendToProcessingChannel(final ResourceModifiedMessage theMessage) {
|
||||
ourLog.trace("Sending resource modified message to processing channel");
|
||||
Validate.notNull(myProcessingChannel, "A SubscriptionMatcherInterceptor has been registered without calling start() on it.");
|
||||
myProcessingChannel.send(new ResourceModifiedJsonMessage(theMessage));
|
||||
}
|
||||
|
||||
|
@ -109,12 +117,13 @@ public class SubscriptionMatcherInterceptor extends ServerOperationInterceptorAd
|
|||
/**
|
||||
* This is an internal API - Use with caution!
|
||||
*/
|
||||
@Override
|
||||
public void submitResourceModified(final ResourceModifiedMessage theMsg) {
|
||||
sendToProcessingChannel(theMsg);
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public LinkedBlockingQueueSubscribableChannel getProcessingChannelForUnitTest() {
|
||||
LinkedBlockingQueueSubscribableChannel getProcessingChannelForUnitTest() {
|
||||
return (LinkedBlockingQueueSubscribableChannel) myProcessingChannel;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
|||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.provider.SubscriptionTriggeringProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.search.warm.CacheWarmingSvcImpl;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
|
@ -42,6 +41,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.util.ParametersUtil;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.util.ValidateUtil;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
@ -55,15 +55,15 @@ import org.hl7.fhir.instance.model.api.IIdType;
|
|||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
|
@ -72,10 +72,10 @@ import static org.apache.commons.lang3.StringUtils.isBlank;
|
|||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
@Service
|
||||
public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc, ApplicationContextAware {
|
||||
public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SubscriptionTriggeringProvider.class);
|
||||
|
||||
public static final int DEFAULT_MAX_SUBMIT = 10000;
|
||||
private static final int DEFAULT_MAX_SUBMIT = 10000;
|
||||
|
||||
@Autowired
|
||||
private FhirContext myFhirContext;
|
||||
|
@ -88,11 +88,10 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
@Autowired
|
||||
private MatchUrlService myMatchUrlService;
|
||||
@Autowired
|
||||
private SubscriptionMatcherInterceptor mySubscriptionMatcherInterceptor;
|
||||
private IResourceModifiedConsumer myResourceModifiedConsumer;
|
||||
|
||||
private final List<SubscriptionTriggeringJobDetails> myActiveJobs = new ArrayList<>();
|
||||
private int myMaxSubmitPerPass = DEFAULT_MAX_SUBMIT;
|
||||
private ApplicationContext myAppCtx;
|
||||
private ExecutorService myExecutorService;
|
||||
|
||||
@Override
|
||||
|
@ -105,7 +104,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
if (theSubscriptionId != null) {
|
||||
IFhirResourceDao<?> subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
IIdType subscriptionId = theSubscriptionId;
|
||||
if (subscriptionId.hasResourceType() == false) {
|
||||
if (!subscriptionId.hasResourceType()) {
|
||||
subscriptionId = subscriptionId.withResourceType(ResourceTypeEnum.SUBSCRIPTION.getCode());
|
||||
}
|
||||
subscriptionDao.read(subscriptionId);
|
||||
|
@ -128,7 +127,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
|
||||
// Search URLs must be valid
|
||||
for (StringParam next : searchUrls) {
|
||||
if (next.getValue().contains("?") == false) {
|
||||
if (!next.getValue().contains("?")) {
|
||||
throw new InvalidRequestException("Search URL is not valid (must be in the form \"[resource type]?[optional params]\")");
|
||||
}
|
||||
}
|
||||
|
@ -163,7 +162,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
return;
|
||||
}
|
||||
|
||||
String activeJobIds = myActiveJobs.stream().map(t -> t.getJobId()).collect(Collectors.joining(", "));
|
||||
String activeJobIds = myActiveJobs.stream().map(SubscriptionTriggeringJobDetails::getJobId).collect(Collectors.joining(", "));
|
||||
ourLog.info("Starting pass: currently have {} active job IDs: {}", myActiveJobs.size(), activeJobIds);
|
||||
|
||||
SubscriptionTriggeringJobDetails activeJob = myActiveJobs.get(0);
|
||||
|
@ -210,7 +209,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
// If we don't have an active search started, and one needs to be.. start it
|
||||
if (isBlank(theJobDetails.getCurrentSearchUuid()) && theJobDetails.getRemainingSearchUrls().size() > 0 && totalSubmitted < myMaxSubmitPerPass) {
|
||||
String nextSearchUrl = theJobDetails.getRemainingSearchUrls().remove(0);
|
||||
RuntimeResourceDefinition resourceDef = CacheWarmingSvcImpl.parseUrlResourceType(myFhirContext, nextSearchUrl);
|
||||
RuntimeResourceDefinition resourceDef = UrlUtil.parseUrlResourceType(myFhirContext, nextSearchUrl);
|
||||
String queryPart = nextSearchUrl.substring(nextSearchUrl.indexOf('?'));
|
||||
String resourceType = resourceDef.getName();
|
||||
|
||||
|
@ -290,7 +289,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
|
||||
private Future<Void> submitResource(String theSubscriptionId, String theResourceIdToTrigger) {
|
||||
org.hl7.fhir.r4.model.IdType resourceId = new org.hl7.fhir.r4.model.IdType(theResourceIdToTrigger);
|
||||
IFhirResourceDao<? extends IBaseResource> dao = myDaoRegistry.getResourceDao(resourceId.getResourceType());
|
||||
IFhirResourceDao dao = myDaoRegistry.getResourceDao(resourceId.getResourceType());
|
||||
IBaseResource resourceToTrigger = dao.read(resourceId);
|
||||
|
||||
return submitResource(theSubscriptionId, resourceToTrigger);
|
||||
|
@ -306,7 +305,7 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
return myExecutorService.submit(() -> {
|
||||
for (int i = 0; ; i++) {
|
||||
try {
|
||||
mySubscriptionMatcherInterceptor.submitResourceModified(msg);
|
||||
myResourceModifiedConsumer.submitResourceModified(msg);
|
||||
break;
|
||||
} catch (Exception e) {
|
||||
if (i >= 3) {
|
||||
|
@ -329,11 +328,6 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
myAppCtx = applicationContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the maximum number of resources that will be submitted in a single pass
|
||||
*/
|
||||
|
@ -346,7 +340,6 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
myMaxSubmitPerPass = maxSubmitPerPass;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@PostConstruct
|
||||
public void start() {
|
||||
LinkedBlockingQueue<Runnable> executorQueue = new LinkedBlockingQueue<>(1000);
|
||||
|
@ -393,67 +386,67 @@ public class SubscriptionTriggeringSvcImpl implements ISubscriptionTriggeringSvc
|
|||
private String myCurrentSearchResourceType;
|
||||
private int myCurrentSearchLastUploadedIndex;
|
||||
|
||||
public Integer getCurrentSearchCount() {
|
||||
Integer getCurrentSearchCount() {
|
||||
return myCurrentSearchCount;
|
||||
}
|
||||
|
||||
public void setCurrentSearchCount(Integer theCurrentSearchCount) {
|
||||
void setCurrentSearchCount(Integer theCurrentSearchCount) {
|
||||
myCurrentSearchCount = theCurrentSearchCount;
|
||||
}
|
||||
|
||||
public String getCurrentSearchResourceType() {
|
||||
String getCurrentSearchResourceType() {
|
||||
return myCurrentSearchResourceType;
|
||||
}
|
||||
|
||||
public void setCurrentSearchResourceType(String theCurrentSearchResourceType) {
|
||||
void setCurrentSearchResourceType(String theCurrentSearchResourceType) {
|
||||
myCurrentSearchResourceType = theCurrentSearchResourceType;
|
||||
}
|
||||
|
||||
public String getJobId() {
|
||||
String getJobId() {
|
||||
return myJobId;
|
||||
}
|
||||
|
||||
public void setJobId(String theJobId) {
|
||||
void setJobId(String theJobId) {
|
||||
myJobId = theJobId;
|
||||
}
|
||||
|
||||
public String getSubscriptionId() {
|
||||
String getSubscriptionId() {
|
||||
return mySubscriptionId;
|
||||
}
|
||||
|
||||
public void setSubscriptionId(String theSubscriptionId) {
|
||||
void setSubscriptionId(String theSubscriptionId) {
|
||||
mySubscriptionId = theSubscriptionId;
|
||||
}
|
||||
|
||||
public List<String> getRemainingResourceIds() {
|
||||
List<String> getRemainingResourceIds() {
|
||||
return myRemainingResourceIds;
|
||||
}
|
||||
|
||||
public void setRemainingResourceIds(List<String> theRemainingResourceIds) {
|
||||
void setRemainingResourceIds(List<String> theRemainingResourceIds) {
|
||||
myRemainingResourceIds = theRemainingResourceIds;
|
||||
}
|
||||
|
||||
public List<String> getRemainingSearchUrls() {
|
||||
List<String> getRemainingSearchUrls() {
|
||||
return myRemainingSearchUrls;
|
||||
}
|
||||
|
||||
public void setRemainingSearchUrls(List<String> theRemainingSearchUrls) {
|
||||
void setRemainingSearchUrls(List<String> theRemainingSearchUrls) {
|
||||
myRemainingSearchUrls = theRemainingSearchUrls;
|
||||
}
|
||||
|
||||
public String getCurrentSearchUuid() {
|
||||
String getCurrentSearchUuid() {
|
||||
return myCurrentSearchUuid;
|
||||
}
|
||||
|
||||
public void setCurrentSearchUuid(String theCurrentSearchUuid) {
|
||||
void setCurrentSearchUuid(String theCurrentSearchUuid) {
|
||||
myCurrentSearchUuid = theCurrentSearchUuid;
|
||||
}
|
||||
|
||||
public int getCurrentSearchLastUploadedIndex() {
|
||||
int getCurrentSearchLastUploadedIndex() {
|
||||
return myCurrentSearchLastUploadedIndex;
|
||||
}
|
||||
|
||||
public void setCurrentSearchLastUploadedIndex(int theCurrentSearchLastUploadedIndex) {
|
||||
void setCurrentSearchLastUploadedIndex(int theCurrentSearchLastUploadedIndex) {
|
||||
myCurrentSearchLastUploadedIndex = theCurrentSearchLastUploadedIndex;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,7 @@ public class DaoSubscriptionProvider implements ISubscriptionProvider {
|
|||
@Override
|
||||
public IBundleProvider search(SearchParameterMap theMap) {
|
||||
IFhirResourceDao subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
RequestDetails req = new ServletSubRequestDetails();
|
||||
req.setSubRequest(true);
|
||||
|
||||
return subscriptionDao.search(theMap, req);
|
||||
return subscriptionDao.search(theMap);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -21,10 +21,11 @@ package ca.uhn.fhir.jpa.subscription.dbmatcher;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.ISubscriptionMatcher;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionMatchResult;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.InMemorySubscriptionMatcher;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionMatchResult;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
@ -43,16 +44,19 @@ public class CompositeInMemoryDaoSubscriptionMatcher implements ISubscriptionMat
|
|||
}
|
||||
|
||||
@Override
|
||||
public SubscriptionMatchResult match(String criteria, ResourceModifiedMessage msg) {
|
||||
public SubscriptionMatchResult match(CanonicalSubscription theSubscription, ResourceModifiedMessage theMsg) {
|
||||
SubscriptionMatchResult result;
|
||||
if (myDaoConfig.isEnableInMemorySubscriptionMatching()) {
|
||||
result = myInMemorySubscriptionMatcher.match(criteria, msg);
|
||||
if (!result.supported()) {
|
||||
ourLog.info("Criteria {} not supported by InMemoryMatcher: {}. Reverting to DatabaseMatcher", criteria, result.getUnsupportedReason());
|
||||
result = myDaoSubscriptionMatcher.match(criteria, msg);
|
||||
result = myInMemorySubscriptionMatcher.match(theSubscription, theMsg);
|
||||
if (result.supported()) {
|
||||
// TODO KHS test
|
||||
result.setInMemory(true);
|
||||
} else {
|
||||
ourLog.info("Criteria {} for Subscription {} not supported by InMemoryMatcher: {}. Reverting to DatabaseMatcher", theSubscription.getCriteriaString(), theSubscription.getIdElementString(), result.getUnsupportedReason());
|
||||
result = myDaoSubscriptionMatcher.match(theSubscription, theMsg);
|
||||
}
|
||||
} else {
|
||||
result = myDaoSubscriptionMatcher.match(criteria, msg);
|
||||
result = myDaoSubscriptionMatcher.match(theSubscription, theMsg);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -24,14 +24,13 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.jpa.dao.DaoRegistry;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
|
||||
import ca.uhn.fhir.jpa.searchparam.MatchUrlService;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.ISubscriptionMatcher;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionMatchResult;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.slf4j.Logger;
|
||||
|
@ -49,10 +48,11 @@ public class DaoSubscriptionMatcher implements ISubscriptionMatcher {
|
|||
MatchUrlService myMatchUrlService;
|
||||
|
||||
@Override
|
||||
public SubscriptionMatchResult match(String criteria, ResourceModifiedMessage msg) {
|
||||
IIdType id = msg.getId(myCtx);
|
||||
public SubscriptionMatchResult match(CanonicalSubscription theSubscription, ResourceModifiedMessage theMsg) {
|
||||
IIdType id = theMsg.getId(myCtx);
|
||||
String resourceType = id.getResourceType();
|
||||
String resourceId = id.getIdPart();
|
||||
String criteria = theSubscription.getCriteriaString();
|
||||
|
||||
// run the subscriptions query and look for matches, add the id as part of the criteria to avoid getting matches of previous resources rather than the recent resource
|
||||
criteria += "&_id=" + resourceType + "/" + resourceId;
|
||||
|
@ -61,23 +61,20 @@ public class DaoSubscriptionMatcher implements ISubscriptionMatcher {
|
|||
|
||||
ourLog.debug("Subscription check found {} results for query: {}", results.size(), criteria);
|
||||
|
||||
return new SubscriptionMatchResult(results.size() > 0, "DATABASE");
|
||||
return SubscriptionMatchResult.fromBoolean(results.size() > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Search based on a query criteria
|
||||
*/
|
||||
protected IBundleProvider performSearch(String theCriteria) {
|
||||
private IBundleProvider performSearch(String theCriteria) {
|
||||
IFhirResourceDao<?> subscriptionDao = myDaoRegistry.getSubscriptionDao();
|
||||
RuntimeResourceDefinition responseResourceDef = subscriptionDao.validateCriteriaAndReturnResourceDefinition(theCriteria);
|
||||
SearchParameterMap responseCriteriaUrl = myMatchUrlService.translateMatchUrl(theCriteria, responseResourceDef);
|
||||
|
||||
RequestDetails req = new ServletSubRequestDetails();
|
||||
req.setSubRequest(true);
|
||||
|
||||
IFhirResourceDao<? extends IBaseResource> responseDao = myDaoRegistry.getResourceDao(responseResourceDef.getImplementingClass());
|
||||
responseCriteriaUrl.setLoadSynchronousUpTo(1);
|
||||
|
||||
return responseDao.search(responseCriteriaUrl, req);
|
||||
return responseDao.search(responseCriteriaUrl);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,9 +25,9 @@ import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
|||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoCodeSystem;
|
||||
import ca.uhn.fhir.jpa.dao.data.*;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.util.ScrollableResultsIterator;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
@ -137,6 +137,8 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
private int myFetchSize = DEFAULT_FETCH_SIZE;
|
||||
private ApplicationContext myApplicationContext;
|
||||
private TransactionTemplate myTxTemplate;
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
/**
|
||||
* @param theAdd If true, add the code. If false, remove the code.
|
||||
|
@ -368,9 +370,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
}
|
||||
}
|
||||
|
||||
@Autowired
|
||||
private PlatformTransactionManager myTransactionManager;
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void deleteConceptMapAndChildren(ResourceTable theResourceTable) {
|
||||
|
@ -1190,6 +1189,22 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
termConceptMap.setResource(theResourceTable);
|
||||
termConceptMap.setUrl(theConceptMap.getUrl());
|
||||
|
||||
String source = theConceptMap.hasSourceUriType() ? theConceptMap.getSourceUriType().getValueAsString() : null;
|
||||
String target = theConceptMap.hasTargetUriType() ? theConceptMap.getTargetUriType().getValueAsString() : null;
|
||||
|
||||
/*
|
||||
* If this is a mapping between "resources" instead of purely between
|
||||
* "concepts" (this is a weird concept that is technically possible, at least as of
|
||||
* FHIR R4), don't try to store the mappings.
|
||||
*
|
||||
* See here for a description of what that is:
|
||||
* http://hl7.org/fhir/conceptmap.html#bnr
|
||||
*/
|
||||
if ("StructureDefinition".equals(new IdType(source).getResourceType()) ||
|
||||
"StructureDefinition".equals(new IdType(target).getResourceType())) {
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* For now we always delete old versions. At some point, it would be nice to allow configuration to keep old versions.
|
||||
*/
|
||||
|
@ -1202,11 +1217,9 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
Optional<TermConceptMap> optionalExistingTermConceptMapByUrl = myConceptMapDao.findTermConceptMapByUrl(conceptMapUrl);
|
||||
if (!optionalExistingTermConceptMapByUrl.isPresent()) {
|
||||
try {
|
||||
String source = theConceptMap.hasSourceUriType() ? theConceptMap.getSourceUriType().getValueAsString() : null;
|
||||
if (isNotBlank(source)) {
|
||||
termConceptMap.setSource(source);
|
||||
}
|
||||
String target = theConceptMap.hasTargetUriType() ? theConceptMap.getTargetUriType().getValueAsString() : null;
|
||||
if (isNotBlank(target)) {
|
||||
termConceptMap.setTarget(target);
|
||||
}
|
||||
|
@ -1244,12 +1257,12 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
|||
|
||||
if (element.hasTarget()) {
|
||||
TermConceptMapGroupElementTarget termConceptMapGroupElementTarget;
|
||||
for (ConceptMap.TargetElementComponent target : element.getTarget()) {
|
||||
for (ConceptMap.TargetElementComponent elementTarget : element.getTarget()) {
|
||||
termConceptMapGroupElementTarget = new TermConceptMapGroupElementTarget();
|
||||
termConceptMapGroupElementTarget.setConceptMapGroupElement(termConceptMapGroupElement);
|
||||
termConceptMapGroupElementTarget.setCode(target.getCode());
|
||||
termConceptMapGroupElementTarget.setDisplay(target.getDisplay());
|
||||
termConceptMapGroupElementTarget.setEquivalence(target.getEquivalence());
|
||||
termConceptMapGroupElementTarget.setCode(elementTarget.getCode());
|
||||
termConceptMapGroupElementTarget.setDisplay(elementTarget.getDisplay());
|
||||
termConceptMapGroupElementTarget.setEquivalence(elementTarget.getEquivalence());
|
||||
myConceptMapGroupElementTargetDao.save(termConceptMapGroupElementTarget);
|
||||
|
||||
if (codesSaved++ % 250 == 0) {
|
||||
|
|
|
@ -25,11 +25,15 @@ import com.google.common.collect.ImmutableSet;
|
|||
import com.google.common.reflect.ClassPath;
|
||||
import com.google.common.reflect.ClassPath.ClassInfo;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.InstantType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.AnnotatedElement;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -165,10 +169,21 @@ public class TestUtil {
|
|||
ourLog.info("Sleeping for {}ms", timeToSleep);
|
||||
Thread.sleep(timeToSleep);
|
||||
} catch (InterruptedException theE) {
|
||||
theE.printStackTrace();
|
||||
ourLog.error("Interrupted", theE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void clearAllStaticFieldsForUnitTest() {
|
||||
ca.uhn.fhir.util.TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
public static InstantType getTimestamp(IBaseResource resource) {
|
||||
return new InstantType(new Date(resource.getMeta().getLastUpdated().getTime()));
|
||||
}
|
||||
|
||||
public static void sleepOneClick() {
|
||||
sleepAtLeast(1);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,92 @@
|
|||
package ca.uhn.fhir.jpa.config;
|
||||
|
||||
import net.ttddyy.dsproxy.ExecutionInfo;
|
||||
import net.ttddyy.dsproxy.QueryInfo;
|
||||
import net.ttddyy.dsproxy.proxy.ParameterSetOperation;
|
||||
import net.ttddyy.dsproxy.support.ProxyDataSourceBuilder;
|
||||
import org.hibernate.engine.jdbc.internal.BasicFormatterImpl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class CaptureQueriesListener implements ProxyDataSourceBuilder.SingleQueryExecution {
|
||||
|
||||
private static final LinkedList<Query> LAST_N_QUERIES = new LinkedList<>();
|
||||
|
||||
@Override
|
||||
public void execute(ExecutionInfo execInfo, List<QueryInfo> queryInfoList) {
|
||||
synchronized (LAST_N_QUERIES) {
|
||||
for (QueryInfo next : queryInfoList) {
|
||||
String sql = next.getQuery();
|
||||
List<String> params;
|
||||
if (next.getParametersList().size() > 0 && next.getParametersList().get(0).size() > 0) {
|
||||
List<ParameterSetOperation> values = next
|
||||
.getParametersList()
|
||||
.get(0);
|
||||
params = values.stream()
|
||||
.map(t -> t.getArgs()[1])
|
||||
.map(t -> t != null ? t.toString() : "NULL")
|
||||
.collect(Collectors.toList());
|
||||
} else {
|
||||
params = new ArrayList<>();
|
||||
}
|
||||
LAST_N_QUERIES.add(0, new Query(sql, params));
|
||||
}
|
||||
while (LAST_N_QUERIES.size() > 100) {
|
||||
LAST_N_QUERIES.removeLast();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Query {
|
||||
private final String myThreadName = Thread.currentThread().getName();
|
||||
private final String mySql;
|
||||
private final List<String> myParams;
|
||||
|
||||
Query(String theSql, List<String> theParams) {
|
||||
mySql = theSql;
|
||||
myParams = Collections.unmodifiableList(theParams);
|
||||
}
|
||||
|
||||
public String getThreadName() {
|
||||
return myThreadName;
|
||||
}
|
||||
|
||||
public String getSql(boolean theInlineParams, boolean theFormat) {
|
||||
String retVal = mySql;
|
||||
if (theFormat) {
|
||||
retVal = new BasicFormatterImpl().format(retVal);
|
||||
}
|
||||
|
||||
if (theInlineParams) {
|
||||
List<String> nextParams = new ArrayList<>(myParams);
|
||||
while (retVal.contains("?") && nextParams.size() > 0) {
|
||||
int idx = retVal.indexOf("?");
|
||||
retVal = retVal.substring(0, idx) + nextParams.remove(0) + retVal.substring(idx + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return retVal;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
synchronized (LAST_N_QUERIES) {
|
||||
LAST_N_QUERIES.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Index 0 is newest!
|
||||
*/
|
||||
public static ArrayList<Query> getLastNQueries() {
|
||||
synchronized (LAST_N_QUERIES) {
|
||||
return new ArrayList<>(LAST_N_QUERIES);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -100,6 +100,7 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
|||
// .logSlowQueryBySlf4j(10, TimeUnit.SECONDS)
|
||||
// .countQuery(new ThreadQueryCountHolder())
|
||||
.beforeQuery(new BlockLargeNumbersOfParamsListener())
|
||||
.afterQuery(new CaptureQueriesListener())
|
||||
.countQuery(singleQueryCountHolder())
|
||||
.build();
|
||||
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.config.CaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorRegistry;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.provider.SystemProviderDstu2Test;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
|
@ -51,7 +54,9 @@ import java.sql.Connection;
|
|||
import java.sql.SQLException;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static ca.uhn.fhir.util.TestUtil.randomizeLocale;
|
||||
|
@ -84,10 +89,13 @@ public abstract class BaseJpaTest {
|
|||
protected IRequestOperationCallback myRequestOperationCallback = mock(IRequestOperationCallback.class);
|
||||
@Autowired
|
||||
protected DatabaseBackedPagingProvider myDatabaseBackedPagingProvider;
|
||||
@Autowired
|
||||
protected IInterceptorRegistry myInterceptorRegistry;
|
||||
|
||||
@After
|
||||
public void afterPerformCleanup() {
|
||||
BaseHapiFhirResourceDao.setDisableIncrementOnUpdateForUnitTest(false);
|
||||
CaptureQueriesListener.clear();
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -128,6 +136,12 @@ public abstract class BaseJpaTest {
|
|||
when(mySrd.getHeaders(eq(JpaConstants.HEADER_META_SNAPSHOT_MODE))).thenReturn(new ArrayList<>());
|
||||
}
|
||||
|
||||
protected CountDownLatch registerLatchHookInterceptor(int theCount, Pointcut theLatchPointcut) {
|
||||
CountDownLatch deliveryLatch = new CountDownLatch(theCount);
|
||||
myInterceptorRegistry.registerAnonymousHookForUnitTest(theLatchPointcut, Integer.MAX_VALUE, t -> deliveryLatch.countDown());
|
||||
return deliveryLatch;
|
||||
}
|
||||
|
||||
protected abstract FhirContext getContext();
|
||||
|
||||
protected abstract PlatformTransactionManager getTxManager();
|
||||
|
@ -431,6 +445,20 @@ public abstract class BaseJpaTest {
|
|||
}
|
||||
}
|
||||
|
||||
public static void waitForTrue(Supplier<Boolean> theList) {
|
||||
StopWatch sw = new StopWatch();
|
||||
while (!theList.get() && sw.getMillis() <= 16000) {
|
||||
try {
|
||||
Thread.sleep(50);
|
||||
} catch (InterruptedException theE) {
|
||||
throw new Error(theE);
|
||||
}
|
||||
}
|
||||
if (sw.getMillis() >= 16000) {
|
||||
fail("Waited " + sw.toString() + " and is still false");
|
||||
}
|
||||
}
|
||||
|
||||
public static void waitForSize(int theTarget, Callable<Number> theCallable) throws Exception {
|
||||
waitForSize(theTarget, 10000, theCallable);
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
|||
@Qualifier("myResourceCountsCache")
|
||||
protected ResourceCountCache myResourceCountsCache;
|
||||
@Autowired
|
||||
protected ISearchParamRegistry mySearchParamRegsitry;
|
||||
protected ISearchParamRegistry mySearchParamRegistry;
|
||||
@Autowired
|
||||
protected ApplicationContext myAppCtx;
|
||||
@Autowired
|
||||
|
@ -181,8 +181,6 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
|
|||
@Qualifier("myValueSetDaoDstu2")
|
||||
protected IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> myValueSetDao;
|
||||
@Autowired
|
||||
private ISearchParamRegistry mySearchParamRegistry;
|
||||
@Autowired
|
||||
protected SubscriptionLoader mySubscriptionLoader;
|
||||
|
||||
@Before
|
||||
|
|
|
@ -2,8 +2,8 @@ package ca.uhn.fhir.jpa.dao.dstu2;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
|
||||
|
@ -70,7 +70,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
threadIdSp.setXpathUsage(XPathUsageTypeEnum.NORMAL);
|
||||
threadIdSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(threadIdSp, mySrd);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Communication com = new Communication();
|
||||
com.setStatus(CommunicationStatusEnum.IN_PROGRESS);
|
||||
|
@ -163,7 +163,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
sp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Practitioner pract = new Practitioner();
|
||||
pract.setId("A");
|
||||
|
@ -194,7 +194,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
eyeColourSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -215,7 +215,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
attendingSp.addTarget(ResourceTypeEnum.PRACTITIONER);
|
||||
IIdType spId = mySearchParameterDao.create(attendingSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Practitioner p1 = new Practitioner();
|
||||
p1.getName().addFamily("P1");
|
||||
|
@ -265,7 +265,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
identifierSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
||||
mySearchParameterDao.create(identifierSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().addGiven("G");
|
||||
|
@ -307,7 +307,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
identifierSp.setStatus(ConformanceResourceStatusEnum.RETIRED);
|
||||
mySearchParameterDao.create(identifierSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().addGiven("G");
|
||||
|
@ -339,7 +339,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.addTarget(ResourceTypeEnum.ORGANIZATION);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().addFamily("P1");
|
||||
|
@ -382,7 +382,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.addTarget(ResourceTypeEnum.PATIENT);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().addFamily("P1");
|
||||
|
@ -435,7 +435,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().addFamily("P1");
|
||||
|
@ -489,7 +489,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
eyeColourSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -522,7 +522,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.addTarget(ResourceTypeEnum.ORGANIZATION);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily("P2");
|
||||
|
@ -558,7 +558,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.addTarget(ResourceTypeEnum.ORGANIZATION);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily("P2");
|
||||
|
@ -594,7 +594,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatusEnum.ARRIVED);
|
||||
|
@ -635,7 +635,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily("P2");
|
||||
|
@ -671,7 +671,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily("P2");
|
||||
|
@ -708,7 +708,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.addTarget(ResourceTypeEnum.APPOINTMENT);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatusEnum.ARRIVED);
|
||||
|
@ -747,7 +747,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatusEnum.ARRIVED);
|
||||
|
@ -789,7 +789,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.addTarget(ResourceTypeEnum.OBSERVATION);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatusEnum.ARRIVED);
|
||||
|
@ -830,7 +830,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().addFamily("P2");
|
||||
|
@ -867,7 +867,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
fooSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.addIdentifier().setSystem("FOO123").setValue("BAR678");
|
||||
|
@ -912,7 +912,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.addIdentifier().setSystem("http://AAA").setValue("BAR678");
|
||||
|
@ -957,7 +957,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
fooSp.setStatus(ConformanceResourceStatusEnum.ACTIVE);
|
||||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGenderEnum.MALE);
|
||||
|
@ -988,7 +988,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
// Delete the param
|
||||
mySearchParameterDao.delete(spId, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
|
@ -1016,7 +1016,7 @@ public class FhirResourceDaoDstu2SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
fooSp.setStatus(ConformanceResourceStatusEnum.DRAFT);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGenderEnum.MALE);
|
||||
|
|
|
@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
|||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.dao.data.ISearchParamPresentDao;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.model.api.*;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.*;
|
||||
|
@ -19,7 +20,6 @@ import ca.uhn.fhir.rest.api.SortSpec;
|
|||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
@ -374,6 +374,9 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
long betweenTime = System.currentTimeMillis();
|
||||
IIdType id2;
|
||||
{
|
||||
|
@ -820,8 +823,6 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
|
||||
@Test
|
||||
public void testSearchLastUpdatedParamWithComparator() throws InterruptedException {
|
||||
String methodName = "testSearchLastUpdatedParamWithComparator";
|
||||
|
||||
IIdType id0;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -829,18 +830,16 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
id0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
int sleep = 100;
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
Thread.sleep(sleep);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
DateTimeDt beforeAny = new DateTimeDt(new Date(), TemporalPrecisionEnum.MILLI);
|
||||
IIdType id1a;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
id1a = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
TestUtil.sleepOneClick();
|
||||
IIdType id1b;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -853,11 +852,12 @@ public class FhirResourceDaoDstu2SearchNoFtTest extends BaseJpaDstu2Test {
|
|||
InstantDt id1bpublished = ResourceMetadataKeyEnum.PUBLISHED.get(myPatientDao.read(id1b, mySrd));
|
||||
ourLog.info("Res 3: {}", id1bpublished.getValueAsString());
|
||||
|
||||
Thread.sleep(sleep);
|
||||
TestUtil.sleepOneClick();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
SearchParameterMap params;
|
||||
Date startDate = new Date(start);
|
||||
TestUtil.sleepOneClick();
|
||||
Date endDate = new Date(end);
|
||||
DateTimeDt startDateTime = new DateTimeDt(startDate, TemporalPrecisionEnum.MILLI);
|
||||
DateTimeDt endDateTime = new DateTimeDt(endDate, TemporalPrecisionEnum.MILLI);
|
||||
|
|
|
@ -56,7 +56,7 @@ import java.io.IOException;
|
|||
import java.io.InputStream;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.fail;
|
||||
import static org.mockito.Mockito.mock;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
|
@ -215,7 +215,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@Autowired
|
||||
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
||||
@Autowired
|
||||
protected ISearchParamRegistry mySearchParamRegsitry;
|
||||
protected ISearchParamRegistry mySearchParamRegistry;
|
||||
@Autowired
|
||||
protected IStaleSearchDeletingSvc myStaleSearchDeletingSvc;
|
||||
@Autowired
|
||||
|
@ -256,8 +256,6 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
protected ITermConceptMapGroupElementTargetDao myTermConceptMapGroupElementTargetDao;
|
||||
@Autowired
|
||||
private JpaValidationSupportChainDstu3 myJpaValidationSupportChainDstu3;
|
||||
@Autowired
|
||||
protected ISearchParamRegistry mySearchParamRegistry;
|
||||
|
||||
@After()
|
||||
public void afterCleanupDao() {
|
||||
|
@ -306,7 +304,7 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
@Before
|
||||
@Transactional()
|
||||
public void beforePurgeDatabase() {
|
||||
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegsitry);
|
||||
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry);
|
||||
}
|
||||
|
||||
@Before
|
||||
|
|
|
@ -139,7 +139,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
sp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
org.hl7.fhir.dstu3.model.Practitioner pract = new org.hl7.fhir.dstu3.model.Practitioner();
|
||||
pract.setId("A");
|
||||
|
@ -169,7 +169,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
eyeColourSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -191,7 +191,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
attendingSp.getTarget().add(new CodeType("Practitioner"));
|
||||
IIdType spId = mySearchParameterDao.create(attendingSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Practitioner p1 = new Practitioner();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -231,7 +231,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
threadIdSp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
threadIdSp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(threadIdSp, mySrd);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Communication com = new Communication();
|
||||
com.setStatus(Communication.CommunicationStatus.INPROGRESS);
|
||||
|
@ -277,7 +277,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
sp.addTarget("Condition");
|
||||
sp.addTarget("Observation");
|
||||
mySearchParameterDao.create(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Condition condition = new Condition();
|
||||
condition.getCode().setText("A condition");
|
||||
|
@ -313,7 +313,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setExpression("MedicationRequest.reasonCode | ProcedureRequest.reasonCode");
|
||||
mySearchParameterDao.create(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
mr.addReasonCode().addCoding().setSystem("foo").setCode("bar");
|
||||
|
@ -343,7 +343,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -387,7 +387,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.getTarget().add(new CodeType("Patient"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -441,7 +441,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -496,7 +496,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
eyeColourSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -530,7 +530,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -568,7 +568,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -605,7 +605,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -647,7 +647,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -684,7 +684,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -722,7 +722,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.getTarget().add(new CodeType("Appointment"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -764,7 +764,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -807,7 +807,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.getTarget().add(new CodeType("Observation"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -849,7 +849,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
siblingSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -886,7 +886,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
displaySp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(displaySp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
MedicationStatement ms1 = new MedicationStatement();
|
||||
ms1.setMedication(new CodeableConcept());
|
||||
|
@ -919,7 +919,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(sp));
|
||||
mySearchParameterDao.create(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Specimen specimen = new Specimen();
|
||||
specimen.setId("#FOO");
|
||||
|
@ -962,7 +962,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
@ -993,7 +993,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
// Delete the param
|
||||
mySearchParameterDao.delete(spId, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
|
||||
|
@ -1021,7 +1021,7 @@ public class FhirResourceDaoDstu3SearchCustomSearchParamTest extends BaseJpaDstu
|
|||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.DRAFT);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
|
|
@ -13,6 +13,7 @@ import javax.servlet.http.HttpServletRequest;
|
|||
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
|
@ -40,7 +41,6 @@ import ca.uhn.fhir.rest.api.SortSpec;
|
|||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||
|
@ -667,6 +667,9 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
long betweenTime = System.currentTimeMillis();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
IIdType id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -1020,7 +1023,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
patient.addName().setFamily("testSearchLanguageParam").addGiven("Joe");
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
Date betweenTime = new Date();
|
||||
|
||||
IIdType id2;
|
||||
|
@ -1196,10 +1199,9 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
id0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
int sleep = 100;
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
long start = System.currentTimeMillis();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(sleep);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
IIdType id1a;
|
||||
{
|
||||
|
@ -1218,7 +1220,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
ourLog.info("Res 2: {}", myPatientDao.read(id1a, mySrd).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
ourLog.info("Res 3: {}", myPatientDao.read(id1b, mySrd).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(sleep);
|
||||
TestUtil.sleepOneClick();
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
SearchParameterMap map;
|
||||
|
@ -1615,18 +1617,18 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
obs01.setSubject(new Reference(patientId01));
|
||||
IIdType obsId01 = myObservationDao.create(obs01, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
Date between = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Observation obs02 = new Observation();
|
||||
obs02.setEffective(new DateTimeType(new Date()));
|
||||
obs02.setSubject(new Reference(locId01));
|
||||
IIdType obsId02 = myObservationDao.create(obs02, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
Date after = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
ourLog.info("P1[{}] L1[{}] Obs1[{}] Obs2[{}]", new Object[] { patientId01, locId01, obsId01, obsId02 });
|
||||
|
||||
|
@ -1853,15 +1855,15 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("Joe");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
TestUtil.sleepOneClick();
|
||||
Date between = new Date();
|
||||
Thread.sleep(10);
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("002");
|
||||
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
TestUtil.sleepOneClick();
|
||||
Date after = new Date();
|
||||
|
||||
SearchParameterMap params;
|
||||
|
@ -2871,6 +2873,8 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
tag1id = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Date betweenDate = new Date();
|
||||
|
||||
IIdType tag2id;
|
||||
|
@ -3193,7 +3197,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
p01.addName().setFamily("B").addGiven("A");
|
||||
String id1 = myPatientDao.create(p01).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Thread.sleep(10);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
// Numeric ID
|
||||
Patient p02 = new Patient();
|
||||
|
@ -3203,7 +3207,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
p02.addName().setFamily("Z").addGiven("Z");
|
||||
String id2 = myPatientDao.create(p02).getId().toUnqualifiedVersionless().getValue();
|
||||
|
||||
Thread.sleep(10);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
// Forced ID
|
||||
Patient pAB = new Patient();
|
||||
|
@ -3213,7 +3217,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
pAB.addName().setFamily("A").addGiven("B");
|
||||
myPatientDao.update(pAB);
|
||||
|
||||
Thread.sleep(10);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
// Forced ID
|
||||
Patient pAA = new Patient();
|
||||
|
|
|
@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
|||
import ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4SearchPageExpiryTest;
|
||||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
|
@ -29,7 +30,6 @@ import org.springframework.transaction.support.TransactionTemplate;
|
|||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
@ -105,8 +105,7 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
assertEquals(searchUuid1, searchUuid2);
|
||||
|
||||
sleepAtLeast(501);
|
||||
|
||||
TestUtil.sleepAtLeast(501);
|
||||
// We're now past 500ms so we shouldn't reuse the search
|
||||
|
||||
final String searchUuid3;
|
||||
|
@ -277,7 +276,7 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
assertEquals(searchUuid1, searchUuid2);
|
||||
|
||||
sleepAtLeast(501);
|
||||
TestUtil.sleepAtLeast(501);
|
||||
|
||||
// We're now past 500ms so we shouldn't reuse the search
|
||||
|
||||
|
@ -363,7 +362,7 @@ public class FhirResourceDaoDstu3SearchPageExpiryTest extends BaseJpaDstu3Test {
|
|||
}
|
||||
});
|
||||
if (search == null) {
|
||||
sleepAtLeast(100);
|
||||
TestUtil.sleepAtLeast(100);
|
||||
}
|
||||
}
|
||||
assertNotNull("Search " + bundleProvider.getUuid() + " not found on disk after 10 seconds", search);
|
||||
|
|
|
@ -2867,21 +2867,21 @@ public class FhirResourceDaoDstu3Test extends BaseJpaDstu3Test {
|
|||
p.addName().setFamily(methodName);
|
||||
IIdType id1 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system2").setValue(methodName);
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType id2 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system3").setValue(methodName);
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType id3 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system4").setValue(methodName);
|
||||
|
|
|
@ -2,11 +2,10 @@ package ca.uhn.fhir.jpa.dao.dstu3;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.SearchBuilder;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedCompositeStringUnique;
|
||||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
|
@ -82,7 +81,7 @@ public class FhirResourceDaoDstu3UniqueSearchParamTest extends BaseJpaDstu3Test
|
|||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueIndexCoverageBeneficiary() {
|
||||
|
@ -121,7 +120,7 @@ public class FhirResourceDaoDstu3UniqueSearchParamTest extends BaseJpaDstu3Test
|
|||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueNameAndManagingOrganizationSps() {
|
||||
|
@ -159,13 +158,13 @@ public class FhirResourceDaoDstu3UniqueSearchParamTest extends BaseJpaDstu3Test
|
|||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectUniqueSearchParams() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
List<JpaRuntimeSearchParam> params = mySearchParamRegsitry.getActiveUniqueSearchParams("Patient");
|
||||
List<JpaRuntimeSearchParam> params = mySearchParamRegistry.getActiveUniqueSearchParams("Patient");
|
||||
|
||||
assertEquals(1, params.size());
|
||||
assertEquals(params.get(0).isUnique(), true);
|
||||
|
|
|
@ -306,7 +306,7 @@ public class FhirResourceDaoDstu3UpdateTest extends BaseJpaDstu3Test {
|
|||
|
||||
assertEquals("1", outcome.getId().getVersionIdPart());
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
Date now = new Date();
|
||||
Patient retrieved = myPatientDao.read(outcome.getId(), mySrd);
|
||||
InstantType updated = retrieved.getMeta().getLastUpdatedElement().copy();
|
||||
|
|
|
@ -4,6 +4,7 @@ import static org.hamcrest.Matchers.containsString;
|
|||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||
|
@ -11,7 +12,6 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||
|
@ -25,8 +25,6 @@ import org.junit.Test;
|
|||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
|
||||
public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3ValidateTest.class);
|
||||
|
||||
|
@ -64,7 +62,7 @@ public class FhirResourceDaoDstu3ValidateTest extends BaseJpaDstu3Test {
|
|||
MethodOutcome results = myQuestionnaireResponseDao.validate(qr, null, null, null, null, null, null);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(results.getOperationOutcome()));
|
||||
|
||||
sleepAtLeast(2500);
|
||||
TestUtil.sleepAtLeast(2500);
|
||||
try {
|
||||
myQuestionnaireResponseDao.validate(qr, null, null, null, null, null, null);
|
||||
fail();
|
||||
|
|
|
@ -8,13 +8,14 @@ import ca.uhn.fhir.jpa.dao.dstu2.FhirResourceDaoDstu2SearchNoFtTest;
|
|||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorRegistry;
|
||||
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||
import ca.uhn.fhir.jpa.search.DatabaseBackedPagingProvider;
|
||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||
import ca.uhn.fhir.jpa.search.IStaleSearchDeletingSvc;
|
||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||
import ca.uhn.fhir.jpa.search.warm.ICacheWarmingSvc;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.BaseSearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionRegistry;
|
||||
import ca.uhn.fhir.jpa.term.BaseHapiTerminologySvcImpl;
|
||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||
|
@ -150,6 +151,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
|||
protected IFhirResourceDao<RiskAssessment> myRiskAssessmentDao;
|
||||
protected IServerInterceptor myInterceptor;
|
||||
@Autowired
|
||||
protected IInterceptorRegistry myInterceptorRegistry;
|
||||
@Autowired
|
||||
@Qualifier("myLocationDaoR4")
|
||||
protected IFhirResourceDao<Location> myLocationDao;
|
||||
@Autowired
|
||||
|
@ -226,7 +229,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
|||
@Qualifier("mySearchParameterDaoR4")
|
||||
protected IFhirResourceDao<SearchParameter> mySearchParameterDao;
|
||||
@Autowired
|
||||
protected ISearchParamRegistry mySearchParamRegsitry;
|
||||
protected BaseSearchParamRegistry mySearchParamRegistry;
|
||||
@Autowired
|
||||
protected IStaleSearchDeletingSvc myStaleSearchDeletingSvc;
|
||||
@Autowired
|
||||
|
@ -285,6 +288,8 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
|||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setSuppressUpdatesWithNoChange(new DaoConfig().isSuppressUpdatesWithNoChange());
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
|
||||
myInterceptorRegistry.clearAnonymousHookForUnitTest();
|
||||
}
|
||||
|
||||
@After
|
||||
|
@ -326,7 +331,7 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
|||
@Transactional()
|
||||
public void beforePurgeDatabase() throws InterruptedException {
|
||||
final EntityManager entityManager = this.myEntityManager;
|
||||
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegsitry);
|
||||
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry);
|
||||
}
|
||||
|
||||
@Before
|
||||
|
|
|
@ -2,8 +2,8 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamToken;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
|
@ -163,7 +163,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
sp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
org.hl7.fhir.r4.model.Practitioner pract = new org.hl7.fhir.r4.model.Practitioner();
|
||||
pract.setId("A");
|
||||
|
@ -193,7 +193,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
eyeColourSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -215,7 +215,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
attendingSp.getTarget().add(new CodeType("Practitioner"));
|
||||
IIdType spId = mySearchParameterDao.create(attendingSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Practitioner p1 = new Practitioner();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -265,7 +265,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
identifierSp.setStatus(Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(identifierSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().addGiven("G");
|
||||
|
@ -305,7 +305,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
identifierSp.setStatus(Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(identifierSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().addGiven("G");
|
||||
|
@ -342,7 +342,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
sp.addTarget("Condition");
|
||||
sp.addTarget("Observation");
|
||||
mySearchParameterDao.create(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Condition condition = new Condition();
|
||||
condition.getCode().setText("A condition");
|
||||
|
@ -378,7 +378,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setExpression("MedicationRequest.reasonCode | ServiceRequest.reasonCode");
|
||||
mySearchParameterDao.create(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
mr.addReasonCode().addCoding().setSystem("foo").setCode("bar");
|
||||
|
@ -425,7 +425,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -469,7 +469,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.getTarget().add(new CodeType("Patient"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -523,7 +523,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -577,7 +577,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
eyeColourSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(eyeColourSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -611,7 +611,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -649,7 +649,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.getTarget().add(new CodeType("Organization"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -686,7 +686,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -739,7 +739,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theArg0) {
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -783,7 +783,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -821,7 +821,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.getTarget().add(new CodeType("Appointment"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -863,7 +863,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -906,7 +906,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.getTarget().add(new CodeType("Observation"));
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Appointment apt = new Appointment();
|
||||
apt.setStatus(AppointmentStatus.ARRIVED);
|
||||
|
@ -948,7 +948,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
siblingSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(siblingSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily("P2");
|
||||
|
@ -986,7 +986,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.addIdentifier().setSystem("FOO123").setValue("BAR678");
|
||||
|
@ -1030,7 +1030,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.addIdentifier().setSystem("http://AAA").setValue("BAR678");
|
||||
|
@ -1074,7 +1074,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
sp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Specimen specimen = new Specimen();
|
||||
specimen.setId("#FOO");
|
||||
|
@ -1117,7 +1117,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
IIdType spId = mySearchParameterDao.create(fooSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
@ -1148,7 +1148,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
// Delete the param
|
||||
mySearchParameterDao.delete(spId, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
|
||||
// Try with custom gender SP
|
||||
|
@ -1175,7 +1175,7 @@ public class FhirResourceDaoR4SearchCustomSearchParamTest extends BaseJpaR4Test
|
|||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.DRAFT);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.config.CaptureQueriesListener;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
|
@ -12,7 +14,7 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -39,6 +41,7 @@ import java.io.IOException;
|
|||
import java.math.BigDecimal;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
|
@ -53,6 +56,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
myDaoConfig.setReuseCachedSearchResultsForMillis(new DaoConfig().getReuseCachedSearchResultsForMillis());
|
||||
myDaoConfig.setFetchSizeDefaultMaximum(new DaoConfig().getFetchSizeDefaultMaximum());
|
||||
myDaoConfig.setAllowContainsSearches(new DaoConfig().isAllowContainsSearches());
|
||||
myDaoConfig.setSearchPreFetchThresholds(new DaoConfig().getSearchPreFetchThresholds());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -151,16 +155,16 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
List<String> ids;
|
||||
|
||||
Date beforeAll = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName("O1");
|
||||
org.setId("O1");
|
||||
myOrganizationDao.update(org);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Date beforePatient = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("P1");
|
||||
|
@ -168,7 +172,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
p.setManagingOrganization(new Reference("Organization/O1"));
|
||||
myPatientDao.update(p);
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
Date afterAll = new Date();
|
||||
|
||||
// Search with between date (should still return Organization even though
|
||||
|
@ -216,7 +220,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
myOrganizationDao.update(org);
|
||||
|
||||
Date beforeAll = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("P1");
|
||||
|
@ -224,17 +228,17 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
p.setManagingOrganization(new Reference("Organization/O1"));
|
||||
myPatientDao.update(p);
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Date beforeOrg = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
org = new Organization();
|
||||
org.setActive(true);
|
||||
org.setId("O1");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
Date afterAll = new Date();
|
||||
|
||||
// Everything should come back
|
||||
|
@ -889,7 +893,11 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
long betweenTime = System.currentTimeMillis();
|
||||
|
||||
IIdType id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -1136,6 +1144,40 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #1174
|
||||
*/
|
||||
@Test
|
||||
public void testSearchDateInSavedSearch() {
|
||||
for (int i = 1; i <= 9; i++) {
|
||||
Patient p1 = new Patient();
|
||||
p1.getBirthDateElement().setValueAsString("1980-01-0" + i);
|
||||
String id1 = myPatientDao.create(p1).getId().toUnqualifiedVersionless().getValue();
|
||||
}
|
||||
|
||||
myDaoConfig.setSearchPreFetchThresholds(Lists.newArrayList(3, 6, 10));
|
||||
|
||||
{
|
||||
// Don't load synchronous
|
||||
SearchParameterMap map = new SearchParameterMap();
|
||||
map.setLastUpdated(new DateRangeParam().setUpperBound(new DateParam(ParamPrefixEnum.LESSTHAN, "2022-01-01")));
|
||||
IBundleProvider found = myPatientDao.search(map);
|
||||
Set<String> dates = new HashSet<>();
|
||||
for (int i = 0; i < 9; i++) {
|
||||
Patient nextResource = (Patient) found.getResources(i, i + 1).get(0);
|
||||
dates.add(nextResource.getBirthDateElement().getValueAsString());
|
||||
}
|
||||
|
||||
assertThat(dates, hasItems(
|
||||
"1980-01-01",
|
||||
"1980-01-09"
|
||||
));
|
||||
|
||||
assertFalse(map.isLoadSynchronous());
|
||||
assertNull(map.getLoadSynchronousUpTo());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* #222
|
||||
*/
|
||||
|
@ -1264,8 +1306,12 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Date betweenTime = new Date();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
IIdType id2;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -1439,10 +1485,11 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
id0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
int sleep = 100;
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
Thread.sleep(sleep);
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
IIdType id1a;
|
||||
{
|
||||
|
@ -1450,6 +1497,9 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
id1a = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
IIdType id1b;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -1461,7 +1511,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
ourLog.info("Res 2: {}", myPatientDao.read(id1a, mySrd).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
ourLog.info("Res 3: {}", myPatientDao.read(id1b, mySrd).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
|
||||
Thread.sleep(sleep);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
SearchParameterMap map;
|
||||
|
@ -1487,7 +1538,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
map = new SearchParameterMap();
|
||||
map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN, startDateTime.getValue()),
|
||||
new DateParam(ParamPrefixEnum.LESSTHAN, myPatientDao.read(id1b, mySrd).getMeta().getLastUpdatedElement().getValue())));
|
||||
new DateParam(ParamPrefixEnum.LESSTHAN, TestUtil.getTimestamp(myPatientDao.read(id1b, mySrd)))));
|
||||
ourLog.info("Searching: {}", map.getLastUpdated());
|
||||
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a));
|
||||
}
|
||||
|
@ -1857,15 +1908,15 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
obs01.setSubject(new Reference(patientId01));
|
||||
IIdType obsId01 = myObservationDao.create(obs01, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
Date between = new Date();
|
||||
Thread.sleep(10);
|
||||
|
||||
Observation obs02 = new Observation();
|
||||
obs02.setEffective(new DateTimeType(new Date()));
|
||||
obs02.setSubject(new Reference(locId01));
|
||||
IIdType obsId02 = myObservationDao.create(obs02, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(10);
|
||||
TestUtil.sleepOneClick();
|
||||
Date after = new Date();
|
||||
|
||||
ourLog.info("P1[{}] L1[{}] Obs1[{}] Obs2[{}]", patientId01, locId01, obsId01, obsId02);
|
||||
|
@ -1988,15 +2039,16 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("Joe");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
TestUtil.sleepOneClick();
|
||||
Date between = new Date();
|
||||
Thread.sleep(10);
|
||||
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("002");
|
||||
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
Thread.sleep(10);
|
||||
TestUtil.sleepOneClick();
|
||||
Date after = new Date();
|
||||
|
||||
SearchParameterMap params;
|
||||
|
@ -2146,6 +2198,51 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchLinkToken() {
|
||||
// /fhirapi/MedicationRequest?category=community&identifier=urn:oid:2.16.840.1.113883.3.7418.12.3%7C&intent=order&medication.code:text=calcitriol,hectorol,Zemplar,rocaltrol,vectical,vitamin%20D,doxercalciferol,paricalcitol&status=active,completed
|
||||
|
||||
Medication m = new Medication();
|
||||
m.getCode().setText("valueb");
|
||||
myMedicationDao.create(m);
|
||||
|
||||
MedicationRequest mr = new MedicationRequest();
|
||||
mr.addCategory().addCoding().setCode("community");
|
||||
mr.addIdentifier().setSystem("urn:oid:2.16.840.1.113883.3.7418.12.3").setValue("1");
|
||||
mr.setIntent(MedicationRequest.MedicationRequestIntent.ORDER);
|
||||
mr.setMedication(new Reference(m.getId()));
|
||||
myMedicationRequestDao.create(mr);
|
||||
|
||||
SearchParameterMap sp = new SearchParameterMap();
|
||||
sp.setLoadSynchronous(true);
|
||||
sp.add("category", new TokenParam("community"));
|
||||
sp.add("identifier", new TokenParam("urn:oid:2.16.840.1.113883.3.7418.12.3", "1"));
|
||||
sp.add("intent", new TokenParam("order"));
|
||||
ReferenceParam param1 = new ReferenceParam("valuea").setChain("code:text");
|
||||
ReferenceParam param2 = new ReferenceParam("valueb").setChain("code:text");
|
||||
ReferenceParam param3 = new ReferenceParam("valuec").setChain("code:text");
|
||||
sp.add("medication", new ReferenceOrListParam().addOr(param1).addOr(param2).addOr(param3));
|
||||
|
||||
IBundleProvider retrieved = myMedicationRequestDao.search(sp);
|
||||
assertEquals(1, retrieved.size().intValue());
|
||||
|
||||
List<String> queries = CaptureQueriesListener
|
||||
.getLastNQueries()
|
||||
.stream()
|
||||
.filter(t -> t.getThreadName().equals("main"))
|
||||
.filter(t -> t.getSql(false, false).toLowerCase().contains("select"))
|
||||
.filter(t -> t.getSql(false, false).toLowerCase().contains("token"))
|
||||
.map(t -> t.getSql(true, true))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ourLog.info("Queries:\n {}", queries.stream().findFirst());
|
||||
|
||||
String searchQuery = queries.get(0);
|
||||
assertEquals(searchQuery, 3, StringUtils.countMatches(searchQuery.toUpperCase(), "HFJ_SPIDX_TOKEN"));
|
||||
assertEquals(searchQuery, 5, StringUtils.countMatches(searchQuery.toUpperCase(), "LEFT OUTER JOIN"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testSearchTokenParam() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -2966,6 +3063,8 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
|||
tag1id = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Date betweenDate = new Date();
|
||||
|
||||
IIdType tag2id;
|
||||
|
|
|
@ -4,6 +4,7 @@ import ca.uhn.fhir.jpa.dao.DaoConfig;
|
|||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap.EverythingModeEnum;
|
||||
import ca.uhn.fhir.jpa.model.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
|
@ -12,7 +13,6 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
|
@ -153,16 +153,16 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
List<String> ids;
|
||||
|
||||
Date beforeAll = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setName("O1");
|
||||
org.setId("O1");
|
||||
myOrganizationDao.update(org);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Date beforePatient = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("P1");
|
||||
|
@ -170,7 +170,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
p.setManagingOrganization(new Reference("Organization/O1"));
|
||||
myPatientDao.update(p);
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
Date afterAll = new Date();
|
||||
|
||||
// Search with between date (should still return Organization even though
|
||||
|
@ -218,7 +218,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
myOrganizationDao.update(org);
|
||||
|
||||
Date beforeAll = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setId("P1");
|
||||
|
@ -226,17 +226,17 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
p.setManagingOrganization(new Reference("Organization/O1"));
|
||||
myPatientDao.update(p);
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
Date beforeOrg = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
|
||||
org = new Organization();
|
||||
org.setActive(true);
|
||||
org.setId("O1");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(100);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick();
|
||||
Date afterAll = new Date();
|
||||
|
||||
// Everything should come back
|
||||
|
@ -891,6 +891,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
TestUtil.sleepOneClick();
|
||||
long betweenTime = System.currentTimeMillis();
|
||||
IIdType id2;
|
||||
{
|
||||
|
@ -1266,6 +1267,8 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
id1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Date betweenTime = new Date();
|
||||
|
||||
IIdType id2;
|
||||
|
@ -1349,8 +1352,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
public void testSearchLastUpdatedParam() throws InterruptedException {
|
||||
String methodName = "testSearchLastUpdatedParam";
|
||||
|
||||
int sleep = 100;
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(sleep);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
DateTimeType beforeAny = new DateTimeType(new Date(), TemporalPrecisionEnum.MILLI);
|
||||
IIdType id1a;
|
||||
|
@ -1368,9 +1370,9 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
id1b = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1100);
|
||||
TestUtil.sleepAtLeast(1100);
|
||||
DateTimeType beforeR2 = new DateTimeType(new Date(), TemporalPrecisionEnum.MILLI);
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(1100);
|
||||
TestUtil.sleepAtLeast(1100);
|
||||
|
||||
IIdType id2;
|
||||
{
|
||||
|
@ -1441,10 +1443,11 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
id0 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
int sleep = 100;
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
long start = System.currentTimeMillis();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(sleep);
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
IIdType id1a;
|
||||
{
|
||||
|
@ -1452,6 +1455,9 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
id1a = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
IIdType id1b;
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
|
@ -1463,11 +1469,13 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
ourLog.info("Res 2: {}", myPatientDao.read(id1a, mySrd).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
ourLog.info("Res 3: {}", myPatientDao.read(id1b, mySrd).getMeta().getLastUpdatedElement().getValueAsString());
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(sleep);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
long end = System.currentTimeMillis();
|
||||
|
||||
SearchParameterMap map;
|
||||
Date startDate = new Date(start);
|
||||
TestUtil.sleepOneClick();
|
||||
Date endDate = new Date(end);
|
||||
DateTimeType startDateTime = new DateTimeType(startDate, TemporalPrecisionEnum.MILLI);
|
||||
DateTimeType endDateTime = new DateTimeType(endDate, TemporalPrecisionEnum.MILLI);
|
||||
|
@ -1489,7 +1497,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
|
||||
map = new SearchParameterMap();
|
||||
map.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN, startDateTime.getValue()),
|
||||
new DateParam(ParamPrefixEnum.LESSTHAN, myPatientDao.read(id1b, mySrd).getMeta().getLastUpdatedElement().getValue())));
|
||||
new DateParam(ParamPrefixEnum.LESSTHAN, TestUtil.getTimestamp(myPatientDao.read(id1b, mySrd)))));
|
||||
ourLog.info("Searching: {}", map.getLastUpdated());
|
||||
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), containsInAnyOrder(id1a));
|
||||
}
|
||||
|
@ -1860,14 +1868,14 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
IIdType obsId01 = myObservationDao.create(obs01, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
Date between = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(10);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Observation obs02 = new Observation();
|
||||
obs02.setEffective(new DateTimeType(new Date()));
|
||||
obs02.setSubject(new Reference(locId01));
|
||||
IIdType obsId02 = myObservationDao.create(obs02, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(10);
|
||||
TestUtil.sleepOneClick();
|
||||
Date after = new Date();
|
||||
|
||||
ourLog.info("P1[{}] L1[{}] Obs1[{}] Obs2[{}]", patientId01, locId01, obsId01, obsId02);
|
||||
|
@ -1990,15 +1998,16 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("Joe");
|
||||
pid1 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
TestUtil.sleepOneClick();
|
||||
Date between = new Date();
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(10);
|
||||
TestUtil.sleepOneClick();
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("002");
|
||||
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("John");
|
||||
pid2 = myPatientDao.create(patient, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast(10);
|
||||
TestUtil.sleepOneClick();
|
||||
Date after = new Date();
|
||||
|
||||
SearchParameterMap params;
|
||||
|
@ -2945,6 +2954,8 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
|||
tag1id = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Date betweenDate = new Date();
|
||||
|
||||
IIdType tag2id;
|
||||
|
|
|
@ -6,6 +6,7 @@ import ca.uhn.fhir.jpa.dao.data.ISearchDao;
|
|||
import ca.uhn.fhir.jpa.entity.Search;
|
||||
import ca.uhn.fhir.jpa.entity.SearchStatusEnum;
|
||||
import ca.uhn.fhir.jpa.search.StaleSearchDeletingSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
|
@ -29,7 +30,6 @@ import javax.annotation.Nullable;
|
|||
import java.util.Date;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
@ -100,7 +100,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
}
|
||||
assertEquals(searchUuid1, searchUuid2);
|
||||
|
||||
sleepAtLeast(501);
|
||||
TestUtil.sleepAtLeast(501);
|
||||
|
||||
// We're now past 500ms so we shouldn't reuse the search
|
||||
|
||||
|
@ -274,7 +274,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
}
|
||||
assertEquals(searchUuid1, searchUuid2);
|
||||
|
||||
sleepAtLeast(501);
|
||||
TestUtil.sleepAtLeast(501);
|
||||
|
||||
// We're now past 500ms so we shouldn't reuse the search
|
||||
|
||||
|
@ -360,7 +360,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
}
|
||||
});
|
||||
if (search == null) {
|
||||
sleepAtLeast(100);
|
||||
TestUtil.sleepAtLeast(100);
|
||||
}
|
||||
}
|
||||
assertNotNull("Search " + bundleProvider.getUuid() + " not found on disk after 10 seconds", search);
|
||||
|
@ -407,7 +407,7 @@ public class FhirResourceDaoR4SearchPageExpiryTest extends BaseJpaR4Test {
|
|||
for (int i = 0; i < 20 && search == null; i++) {
|
||||
search = theSearchEntityDao.findByUuid(theUuid);
|
||||
if (search == null || search.getStatus() == SearchStatusEnum.LOADING) {
|
||||
sleepAtLeast(100);
|
||||
TestUtil.sleepAtLeast(100);
|
||||
}
|
||||
}
|
||||
assertNotNull(search);
|
||||
|
|
|
@ -10,6 +10,7 @@ import ca.uhn.fhir.jpa.model.entity.*;
|
|||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||
|
@ -20,7 +21,6 @@ import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
|||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.google.common.collect.Lists;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -3159,16 +3159,22 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
p.addName().setFamily(methodName);
|
||||
IIdType id1 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system2").setValue(methodName);
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType id2 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system3").setValue(methodName);
|
||||
p.addName().setFamily(methodName);
|
||||
IIdType id3 = myPatientDao.create(p, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
p = new Patient();
|
||||
p.addIdentifier().setSystem("urn:system4").setValue(methodName);
|
||||
p.addName().setFamily(methodName);
|
||||
|
|
|
@ -8,7 +8,6 @@ import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
|||
import ca.uhn.fhir.jpa.searchparam.SearchParamConstants;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.util.JpaConstants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.TokenParam;
|
||||
|
@ -97,7 +96,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
SearchBuilder.resetLastHandlerMechanismForUnitTest();
|
||||
}
|
||||
|
@ -139,7 +138,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
|
||||
|
@ -168,7 +167,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
|
||||
|
@ -197,7 +196,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
|
||||
|
@ -226,7 +225,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
.setUrl(SearchParamConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueNameAndManagingOrganizationSps() {
|
||||
|
@ -264,7 +263,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueObservationSubjectDateCode() {
|
||||
|
@ -316,13 +315,13 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectUniqueSearchParams() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
List<JpaRuntimeSearchParam> params = mySearchParamRegsitry.getActiveUniqueSearchParams("Patient");
|
||||
List<JpaRuntimeSearchParam> params = mySearchParamRegistry.getActiveUniqueSearchParams("Patient");
|
||||
|
||||
assertEquals(1, params.size());
|
||||
assertTrue(params.get(0).isUnique());
|
||||
|
@ -474,7 +473,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
|
||||
myResourceIndexedCompositeStringUniqueDao.deleteAll();
|
||||
|
||||
assertEquals(1, mySearchParamRegsitry.getActiveUniqueSearchParams("Observation").size());
|
||||
assertEquals(1, mySearchParamRegistry.getActiveUniqueSearchParams("Observation").size());
|
||||
|
||||
myResourceReindexingSvc.markAllResourcesForReindexing();
|
||||
myResourceReindexingSvc.forceReindexingPass();
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.jpa.dao.r4;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
|
@ -12,7 +13,6 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
|
@ -313,12 +313,15 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
|||
|
||||
assertEquals("1", outcome.getId().getVersionIdPart());
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
Patient retrieved = myPatientDao.read(outcome.getId(), mySrd);
|
||||
InstantType updated = retrieved.getMeta().getLastUpdatedElement().copy();
|
||||
InstantType updated = TestUtil.getTimestamp(retrieved);
|
||||
assertTrue(updated.before(now));
|
||||
|
||||
Thread.sleep(1000);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
reset(myInterceptor);
|
||||
retrieved.getIdentifier().get(0).setValue("002");
|
||||
|
@ -335,17 +338,18 @@ public class FhirResourceDaoR4UpdateTest extends BaseJpaR4Test {
|
|||
assertEquals("Patient", details.getResourceType());
|
||||
assertEquals(Patient.class, details.getResource().getClass());
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
Date now2 = new Date();
|
||||
|
||||
Patient retrieved2 = myPatientDao.read(outcome.getId().toVersionless(), mySrd);
|
||||
|
||||
assertEquals("2", retrieved2.getIdElement().getVersionIdPart());
|
||||
assertEquals("002", retrieved2.getIdentifier().get(0).getValue());
|
||||
InstantType updated2 = retrieved2.getMeta().getLastUpdatedElement();
|
||||
InstantType updated2 = TestUtil.getTimestamp(retrieved2);
|
||||
assertTrue(updated2.after(now));
|
||||
assertTrue(updated2.before(now2));
|
||||
|
||||
Thread.sleep(2000);
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
/*
|
||||
* Get history
|
||||
|
|
|
@ -7,7 +7,6 @@ import ca.uhn.fhir.jpa.model.entity.*;
|
|||
import ca.uhn.fhir.jpa.searchparam.JpaRuntimeSearchParam;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.PathAndRef;
|
||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamProvider;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||
|
@ -71,11 +70,6 @@ public class SearchParamExtractorR4Test {
|
|||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshCacheIfNecessary() {
|
||||
// nothing
|
||||
}
|
||||
|
||||
@Override
|
||||
public void requestRefresh() {
|
||||
// nothing
|
||||
|
@ -90,11 +84,6 @@ public class SearchParamExtractorR4Test {
|
|||
public Collection<RuntimeSearchParam> getSearchParamsByResourceType(RuntimeResourceDefinition theResourceDef) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSearchParamProviderForUnitTest(ISearchParamProvider theSearchParamProvider) {
|
||||
// nothing
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -211,9 +211,11 @@ public class SystemProviderDstu2Test extends BaseJpaDstu2Test {
|
|||
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
|
||||
myObservationDao.update(obs, mySrd);
|
||||
|
||||
// Try to wait for the indexing to complete
|
||||
waitForSize(2, ()-> fetchSuggestionCount(ptId));
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/$suggest-keywords?context=Patient/" + ptId.getIdPart() + "/$everything&searchParam=_content&text=zxc&_pretty=true&_format=xml");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
try {
|
||||
try (CloseableHttpResponse http = ourHttpClient.execute(get)) {
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(output);
|
||||
|
@ -225,8 +227,16 @@ public class SystemProviderDstu2Test extends BaseJpaDstu2Test {
|
|||
assertEquals("score", parameters.getParameter().get(0).getPart().get(1).getName());
|
||||
assertEquals(new DecimalDt("1.0"), parameters.getParameter().get(0).getPart().get(1).getValue());
|
||||
|
||||
} finally {
|
||||
http.close();
|
||||
}
|
||||
}
|
||||
|
||||
private Number fetchSuggestionCount(IIdType thePtId) throws IOException {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/$suggest-keywords?context=Patient/" + thePtId.getIdPart() + "/$everything&searchParam=_content&text=zxc&_pretty=true&_format=xml");
|
||||
try (CloseableHttpResponse http = ourHttpClient.execute(get)) {
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
Parameters parameters = ourCtx.newXmlParser().parseResource(Parameters.class, output);
|
||||
return parameters.getParameter().size();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,37 +1,43 @@
|
|||
package ca.uhn.fhir.jpa.provider.dstu3;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceReindexJobEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.*;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.gclient.ReferenceClientParam;
|
||||
import ca.uhn.fhir.rest.gclient.TokenClientParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestComponent;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||
import org.hl7.fhir.dstu3.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.dstu3.model.SearchParameter.XPathUsageType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProviderDstu3Test {
|
||||
|
||||
|
@ -56,7 +62,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
|
|||
super.beforeResetConfig();
|
||||
|
||||
myModelConfig.setDefaultSearchParamsCanBeOverridden(new ModelConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private Map<String, CapabilityStatementRestResourceSearchParamComponent> extractSearchParams(CapabilityStatement conformance, String resType) {
|
||||
|
@ -142,7 +148,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
|
|||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -198,7 +204,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
|
|||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
conformance = ourClient
|
||||
.fetchConformance()
|
||||
|
@ -259,7 +265,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
|
|||
attendingSp.getTarget().add(new CodeType("Practitioner"));
|
||||
IIdType spId = mySearchParameterDao.create(attendingSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Practitioner p1 = new Practitioner();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -309,7 +315,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
|
|||
.resource(eyeColourSp)
|
||||
.execute();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -351,7 +357,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
|
|||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
@ -395,7 +401,7 @@ public class ResourceProviderCustomSearchParamDstu3Test extends BaseResourceProv
|
|||
fooSp.setStatus(org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
|
|
@ -4,6 +4,8 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||
|
@ -28,6 +30,7 @@ import java.util.ArrayList;
|
|||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.in;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
|
@ -148,6 +151,58 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReadInTransaction() {
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
IIdType id = ourClient.update().resource(patient).conditionalByUrl("Patient?identifier=http://uhn.ca/mrns|100").execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
ourRestServer.registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||
@Override
|
||||
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||
String authHeader = theRequestDetails.getHeader("Authorization");
|
||||
if (!"Bearer AAA".equals(authHeader)) {
|
||||
throw new AuthenticationException("Invalid auth header: " + authHeader);
|
||||
}
|
||||
return new RuleBuilder()
|
||||
.allow().transaction().withAnyOperation().andApplyNormalRules().andThen()
|
||||
.allow().read().resourcesOfType(Patient.class).withAnyId()
|
||||
.build();
|
||||
}
|
||||
});
|
||||
|
||||
SimpleRequestHeaderInterceptor interceptor = new SimpleRequestHeaderInterceptor("Authorization", "Bearer AAA");
|
||||
try {
|
||||
ourClient.registerInterceptor(interceptor);
|
||||
|
||||
Bundle bundle;
|
||||
Bundle responseBundle;
|
||||
|
||||
// Read
|
||||
bundle = new Bundle();
|
||||
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||
bundle.addEntry().getRequest().setMethod(Bundle.HTTPVerb.GET).setUrl(id.getValue());
|
||||
responseBundle = ourClient.transaction().withBundle(bundle).execute();
|
||||
patient = (Patient) responseBundle.getEntry().get(0).getResource();
|
||||
assertEquals("Tester", patient.getNameFirstRep().getFamily());
|
||||
|
||||
// Search
|
||||
bundle = new Bundle();
|
||||
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||
bundle.addEntry().getRequest().setMethod(Bundle.HTTPVerb.GET).setUrl("Patient?");
|
||||
responseBundle = ourClient.transaction().withBundle(bundle).execute();
|
||||
responseBundle = (Bundle) responseBundle.getEntry().get(0).getResource();
|
||||
patient = (Patient) responseBundle.getEntry().get(0).getResource();
|
||||
assertEquals("Tester", patient.getNameFirstRep().getFamily());
|
||||
|
||||
} finally {
|
||||
ourClient.unregisterInterceptor(interceptor);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* See #751
|
||||
*/
|
||||
|
|
|
@ -59,14 +59,14 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
protected static RestfulServer ourRestServer;
|
||||
protected static String ourServerBase;
|
||||
protected static SearchParamRegistryR4 ourSearchParamRegistry;
|
||||
protected static DatabaseBackedPagingProvider ourPagingProvider;
|
||||
private static DatabaseBackedPagingProvider ourPagingProvider;
|
||||
protected static ISearchDao mySearchEntityDao;
|
||||
protected static ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||
protected static GenericWebApplicationContext ourWebApplicationContext;
|
||||
protected static SubscriptionMatcherInterceptor ourSubscriptionMatcherInterceptor;
|
||||
private static GenericWebApplicationContext ourWebApplicationContext;
|
||||
private static SubscriptionMatcherInterceptor ourSubscriptionMatcherInterceptor;
|
||||
private static Server ourServer;
|
||||
protected IGenericClient ourClient;
|
||||
protected ResourceCountCache ourResourceCountsCache;
|
||||
ResourceCountCache ourResourceCountsCache;
|
||||
private TerminologyUploaderProviderR4 myTerminologyUploaderProvider;
|
||||
private Object ourGraphQLProvider;
|
||||
private boolean ourRestHookSubscriptionInterceptorRequested;
|
||||
|
@ -162,6 +162,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
mySearchEntityDao = wac.getBean(ISearchDao.class);
|
||||
ourSearchParamRegistry = wac.getBean(SearchParamRegistryR4.class);
|
||||
ourSubscriptionMatcherInterceptor = wac.getBean(SubscriptionMatcherInterceptor.class);
|
||||
ourSubscriptionMatcherInterceptor.start();
|
||||
|
||||
myFhirCtx.getRestfulClientFactory().setSocketTimeout(5000000);
|
||||
|
||||
|
@ -204,7 +205,7 @@ public abstract class BaseResourceProviderR4Test extends BaseJpaR4Test {
|
|||
fail("Failed to init subscriptions");
|
||||
}
|
||||
try {
|
||||
mySubscriptionLoader.initSubscriptions();
|
||||
mySubscriptionLoader.syncSubscriptions();
|
||||
break;
|
||||
} catch (ResourceVersionConflictException e) {
|
||||
Thread.sleep(250);
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
public class HookInterceptorR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HookInterceptorR4Test.class);
|
||||
|
||||
@Test
|
||||
public void testOP_PRESTORAGE_RESOURCE_CREATED_ModifyResource() {
|
||||
myInterceptorRegistry.registerAnonymousHookForUnitTest(Pointcut.OP_PRESTORAGE_RESOURCE_CREATED, t->{
|
||||
Patient contents = (Patient) t.get(IBaseResource.class, 0);
|
||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||
});
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getNameFirstRep().setFamily("OLDFAMILY");
|
||||
MethodOutcome outcome = ourClient.create().resource(p).execute();
|
||||
|
||||
// Response reflects change, stored resource also does
|
||||
Patient responsePatient = (Patient) outcome.getResource();
|
||||
assertEquals("NEWFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
responsePatient = ourClient.read().resource(Patient.class).withId(outcome.getId()).execute();
|
||||
assertEquals("NEWFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOP_PRECOMMIT_RESOURCE_CREATED_ModifyResource() {
|
||||
myInterceptorRegistry.registerAnonymousHookForUnitTest(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED, t->{
|
||||
Patient contents = (Patient) t.get(IBaseResource.class, 0);
|
||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||
});
|
||||
|
||||
Patient p = new Patient();
|
||||
p.getNameFirstRep().setFamily("OLDFAMILY");
|
||||
MethodOutcome outcome = ourClient.create().resource(p).execute();
|
||||
|
||||
// Response reflects change, stored resource does not
|
||||
Patient responsePatient = (Patient) outcome.getResource();
|
||||
assertEquals("NEWFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
responsePatient = ourClient.read().resource(Patient.class).withId(outcome.getId()).execute();
|
||||
assertEquals("OLDFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOP_PRESTORAGE_RESOURCE_UPDATED_ModifyResource() {
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
IIdType id = ourClient.create().resource(p).execute().getId();
|
||||
|
||||
myInterceptorRegistry.registerAnonymousHookForUnitTest(Pointcut.OP_PRESTORAGE_RESOURCE_UPDATED, t->{
|
||||
Patient contents = (Patient) t.get(IBaseResource.class, 1);
|
||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||
});
|
||||
|
||||
p = new Patient();
|
||||
p.setId(id);
|
||||
p.getNameFirstRep().setFamily("OLDFAMILY");
|
||||
MethodOutcome outcome = ourClient.update().resource(p).execute();
|
||||
|
||||
// Response reflects change, stored resource also does
|
||||
Patient responsePatient = (Patient) outcome.getResource();
|
||||
assertEquals("NEWFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
responsePatient = ourClient.read().resource(Patient.class).withId(outcome.getId()).execute();
|
||||
assertEquals("NEWFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOP_PRECOMMIT_RESOURCE_UPDATED_ModifyResource() {
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
IIdType id = ourClient.create().resource(p).execute().getId();
|
||||
|
||||
myInterceptorRegistry.registerAnonymousHookForUnitTest(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, t->{
|
||||
Patient contents = (Patient) t.get(IBaseResource.class, 1);
|
||||
contents.getNameFirstRep().setFamily("NEWFAMILY");
|
||||
});
|
||||
|
||||
p = new Patient();
|
||||
p.setId(id);
|
||||
p.getNameFirstRep().setFamily("OLDFAMILY");
|
||||
MethodOutcome outcome = ourClient.update().resource(p).execute();
|
||||
|
||||
// Response reflects change, stored resource does not
|
||||
Patient responsePatient = (Patient) outcome.getResource();
|
||||
assertEquals("NEWFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
responsePatient = ourClient.read().resource(Patient.class).withId(outcome.getId()).execute();
|
||||
assertEquals("OLDFAMILY", responsePatient.getNameFirstRep().getFamily());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,37 +1,43 @@
|
|||
package ca.uhn.fhir.jpa.provider.r4;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceReindexJobEntity;
|
||||
import ca.uhn.fhir.jpa.model.entity.ModelConfig;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.*;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.SearchParameter.XPathUsageType;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.*;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.gclient.ReferenceClientParam;
|
||||
import ca.uhn.fhir.rest.gclient.TokenClientParam;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestComponent;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceComponent;
|
||||
import org.hl7.fhir.r4.model.CapabilityStatement.CapabilityStatementRestResourceSearchParamComponent;
|
||||
import org.hl7.fhir.r4.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
import org.hl7.fhir.r4.model.SearchParameter.XPathUsageType;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
|
||||
import org.springframework.transaction.support.TransactionTemplate;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
|
@ -56,7 +62,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
|
|||
super.beforeResetConfig();
|
||||
|
||||
myModelConfig.setDefaultSearchParamsCanBeOverridden(new ModelConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
|
||||
private Map<String, CapabilityStatementRestResourceSearchParamComponent> extractSearchParams(CapabilityStatement conformance, String resType) {
|
||||
|
@ -142,7 +148,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
|
|||
txTemplate.execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -198,7 +204,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
|
|||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.RETIRED);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
conformance = ourClient
|
||||
.fetchConformance()
|
||||
|
@ -260,7 +266,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
|
|||
attendingSp.getTarget().add(new CodeType("Practitioner"));
|
||||
IIdType spId = mySearchParameterDao.create(attendingSp, mySrd).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Practitioner p1 = new Practitioner();
|
||||
p1.addName().setFamily("P1");
|
||||
|
@ -310,7 +316,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
|
|||
.resource(eyeColourSp)
|
||||
.execute();
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient p1 = new Patient();
|
||||
p1.setActive(true);
|
||||
|
@ -352,7 +358,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
|
|||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
@ -396,7 +402,7 @@ public class ResourceProviderCustomSearchParamR4Test extends BaseResourceProvide
|
|||
fooSp.setStatus(org.hl7.fhir.r4.model.Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(fooSp, mySrd);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
|
||||
Patient pat = new Patient();
|
||||
pat.setGender(AdministrativeGender.MALE);
|
||||
|
|
|
@ -366,6 +366,7 @@ public class ResourceProviderInterceptorR4Test extends BaseResourceProviderR4Tes
|
|||
|
||||
}
|
||||
|
||||
|
||||
private void transaction(Bundle theBundle) throws IOException {
|
||||
String resource = myFhirCtx.newXmlParser().encodeResourceToString(theBundle);
|
||||
HttpPost post = new HttpPost(ourServerBase + "/");
|
||||
|
|
|
@ -2,12 +2,12 @@ package ca.uhn.fhir.jpa.provider.r4;
|
|||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.search.SearchCoordinatorSvcImpl;
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.parser.StrictErrorHandler;
|
||||
import ca.uhn.fhir.rest.api.CacheControlDirective;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CapturingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.r4.model.Bundle;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.After;
|
||||
|
@ -160,12 +160,18 @@ public class ResourceProviderR4CacheTest extends BaseResourceProviderR4Test {
|
|||
|
||||
Date beforeFirst = new Date();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Bundle results1 = ourClient.search().forResource("Patient").where(Patient.FAMILY.matches().value("FAM")).returnBundle(Bundle.class).execute();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
assertEquals(1, results1.getEntry().size());
|
||||
assertEquals(1, mySearchEntityDao.count());
|
||||
assertThat(myCapturingInterceptor.getLastResponse().getHeaders(Constants.HEADER_X_CACHE), empty());
|
||||
assertThat(results1.getMeta().getLastUpdated(), greaterThan(beforeFirst));
|
||||
assertThat(results1.getMeta().getLastUpdated(), lessThan(new Date()));
|
||||
Date results1Date = TestUtil.getTimestamp(results1).getValue();
|
||||
assertThat(results1Date, greaterThan(beforeFirst));
|
||||
assertThat(results1Date, lessThan(new Date()));
|
||||
assertThat(results1.getId(), not(blankOrNullString()));
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
|
|
|
@ -37,6 +37,7 @@ import java.util.Set;
|
|||
import java.util.TreeSet;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import ca.uhn.fhir.jpa.util.TestUtil;
|
||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -116,13 +117,13 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.util.StopWatch;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
@SuppressWarnings("Duplicates")
|
||||
public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ResourceProviderR4Test.class);
|
||||
public static final int LARGE_NUMBER = 77;
|
||||
private SearchCoordinatorSvcImpl mySearchCoordinatorSvcRaw;
|
||||
private CapturingInterceptor myCapturingInterceptor = new CapturingInterceptor();
|
||||
|
||||
|
@ -198,6 +199,34 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchFetchPageBeyondEnd() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
Organization o = new Organization();
|
||||
o.setId("O" + i);
|
||||
o.setName("O" + i);
|
||||
IIdType oid = ourClient.update().resource(o).execute().getId().toUnqualifiedVersionless();
|
||||
}
|
||||
|
||||
Bundle output = ourClient
|
||||
.search()
|
||||
.forResource("Organization")
|
||||
.count(3)
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
String nextPageUrl = output.getLink("next").getUrl();
|
||||
String url = nextPageUrl.replace("_getpagesoffset=3", "_getpagesoffset=999");
|
||||
ourLog.info("Going to request URL: {}", url);
|
||||
|
||||
output = ourClient
|
||||
.loadPage()
|
||||
.byUrl(url)
|
||||
.andReturnBundle(Bundle.class)
|
||||
.execute();
|
||||
assertEquals(0, output.getEntry().size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteConditional() {
|
||||
|
@ -945,6 +974,19 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
@Ignore
|
||||
public void testQuery() throws IOException {
|
||||
ourLog.info("** Performing Search");
|
||||
HttpGet read = new HttpGet(ourServerBase + "/MedicationRequest?category=community&identifier=urn:oid:2.16.840.1.113883.3.7418.12.3%7C&intent=order&medication.code:text=calcitriol,hectorol,Zemplar,rocaltrol,vectical,vitamin%20D,doxercalciferol,paricalcitol&status=active,completed");
|
||||
try (CloseableHttpResponse response = ourHttpClient.execute(read)) {
|
||||
ourLog.info(response.toString());
|
||||
}
|
||||
ourLog.info("** DONE Performing Search");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDeleteResourceConditional1() throws IOException {
|
||||
String methodName = "testDeleteResourceConditional1";
|
||||
|
@ -1714,7 +1756,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
p.setActive(true);
|
||||
IIdType id = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
for (int i = 1; i < 77; i++) {
|
||||
for (int i = 1; i < LARGE_NUMBER; i++) {
|
||||
Observation obs = new Observation();
|
||||
obs.setId("A" + StringUtils.leftPad(Integer.toString(i), 2, '0'));
|
||||
obs.setSubject(new Reference(id));
|
||||
|
@ -1752,8 +1794,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
}
|
||||
|
||||
assertThat(ids, hasItem(id.getIdPart()));
|
||||
assertEquals(77, ids.size());
|
||||
for (int i = 1; i < 77; i++) {
|
||||
assertEquals(LARGE_NUMBER, ids.size());
|
||||
for (int i = 1; i < LARGE_NUMBER; i++) {
|
||||
assertThat(ids.size() + " ids: " + ids, ids, hasItem("A" + StringUtils.leftPad(Integer.toString(i), 2, '0')));
|
||||
}
|
||||
}
|
||||
|
@ -3646,6 +3688,8 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
|||
Search search1 = newTxTemplate().execute(theStatus -> mySearchEntityDao.findByUuid(uuid1));
|
||||
Date lastReturned1 = search1.getSearchLastReturned();
|
||||
|
||||
TestUtil.sleepOneClick();
|
||||
|
||||
Bundle result2 = ourClient
|
||||
.search()
|
||||
.forResource("Organization")
|
||||
|
|
|
@ -279,6 +279,9 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
|
||||
myObservationDao.update(obs, mySrd);
|
||||
|
||||
// Try to wait for the indexing to complete
|
||||
waitForSize(2, ()-> fetchSuggestionCount(ptId));
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/$suggest-keywords?context=Patient/" + ptId.getIdPart() + "/$everything&searchParam=_content&text=zxc&_pretty=true&_format=xml");
|
||||
CloseableHttpResponse http = ourHttpClient.execute(get);
|
||||
try {
|
||||
|
@ -298,6 +301,16 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
private Number fetchSuggestionCount(IIdType thePtId) throws IOException {
|
||||
HttpGet get = new HttpGet(ourServerBase + "/$suggest-keywords?context=Patient/" + thePtId.getIdPart() + "/$everything&searchParam=_content&text=zxc&_pretty=true&_format=xml");
|
||||
try (CloseableHttpResponse http = ourHttpClient.execute(get)) {
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
Parameters parameters = ourCtx.newXmlParser().parseResource(Parameters.class, output);
|
||||
return parameters.getParameter().size();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuggestKeywordsInvalid() throws Exception {
|
||||
Patient patient = new Patient();
|
||||
|
|
|
@ -89,17 +89,23 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
|||
ourHeaders.clear();
|
||||
|
||||
// Delete all Subscriptions
|
||||
if (ourClient != null) {
|
||||
Bundle allSubscriptions = ourClient.search().forResource(Subscription.class).returnBundle(Bundle.class).execute();
|
||||
for (IBaseResource next : BundleUtil.toListOfResources(myFhirCtx, allSubscriptions)) {
|
||||
ourClient.delete().resource(next).execute();
|
||||
}
|
||||
waitForActivatedSubscriptionCount(0);
|
||||
}
|
||||
|
||||
LinkedBlockingQueueSubscribableChannel processingChannel = mySubscriptionMatcherInterceptor.getProcessingChannelForUnitTest();
|
||||
if (processingChannel != null) {
|
||||
processingChannel.clearInterceptorsForUnitTest();
|
||||
}
|
||||
myCountingInterceptor = new CountingInterceptor();
|
||||
if (processingChannel != null) {
|
||||
processingChannel.addInterceptorForUnitTest(myCountingInterceptor);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected Subscription createSubscription(String theCriteria, String thePayload) {
|
||||
|
@ -147,9 +153,8 @@ public abstract class BaseSubscriptionsR4Test extends BaseResourceProviderR4Test
|
|||
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(observation).execute();
|
||||
|
||||
observation.setId(methodOutcome.getId());
|
||||
IIdType id = myObservationDao.create(observation).getId();
|
||||
observation.setId(id);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.subscription;
|
||||
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamProvider;
|
||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||
import ca.uhn.fhir.jpa.subscription.module.standalone.FhirClientSearchParamProvider;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import org.hl7.fhir.r4.model.Coding;
|
||||
|
@ -17,8 +16,6 @@ import static org.junit.Assert.assertEquals;
|
|||
|
||||
|
||||
public class FhirClientSearchParamProviderTest extends BaseSubscriptionsR4Test {
|
||||
@Autowired
|
||||
ISearchParamRegistry mySearchParamRegistry;
|
||||
@Autowired
|
||||
ISearchParamProvider origSearchParamProvider;
|
||||
|
||||
|
@ -44,7 +41,7 @@ public class FhirClientSearchParamProviderTest extends BaseSubscriptionsR4Test {
|
|||
sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
createSubscription(criteria, "application/json");
|
||||
waitForActivatedSubscriptionCount(1);
|
||||
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
package ca.uhn.fhir.jpa.subscription;
|
||||
|
||||
import javax.servlet.http.HttpServlet;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
|
||||
/**
|
||||
* Receives subscription notification without payloads.
|
||||
*/
|
||||
public class NotificationServlet extends HttpServlet {
|
||||
private static final long serialVersionUID = 5957950857980374719L;
|
||||
|
||||
private final AtomicLong receivedNotificationCount = new AtomicLong();
|
||||
|
||||
private final List<String> receivedAuthorizationHeaders = Collections.synchronizedList(new ArrayList<>());
|
||||
|
||||
@Override
|
||||
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
|
||||
receivedNotificationCount.incrementAndGet();
|
||||
receivedAuthorizationHeaders.add(req.getHeader("Authorization"));
|
||||
}
|
||||
|
||||
public long getReceivedNotificationCount() {
|
||||
return receivedNotificationCount.get();
|
||||
}
|
||||
|
||||
public List<String> getReceivedAuthorizationHeaders() {
|
||||
return receivedAuthorizationHeaders;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
receivedNotificationCount.set(0);
|
||||
receivedAuthorizationHeaders.clear();
|
||||
}
|
||||
}
|
|
@ -4,9 +4,9 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.jpa.config.TestR4Config;
|
||||
import ca.uhn.fhir.jpa.model.entity.ResourceIndexedSearchParamString;
|
||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage;
|
||||
import ca.uhn.fhir.model.api.TemporalPrecisionEnum;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
@ -35,28 +35,41 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
@Autowired
|
||||
InMemorySubscriptionMatcher myInMemorySubscriptionMatcher;
|
||||
@Autowired
|
||||
SubscriptionStrategyEvaluator mySubscriptionStrategyEvaluator;
|
||||
@Autowired
|
||||
FhirContext myContext;
|
||||
|
||||
private SubscriptionMatchResult match(IBaseResource resource, SearchParameterMap params) {
|
||||
String criteria = params.toNormalizedQueryString(myContext);
|
||||
ourLog.info("Criteria: <{}>", criteria);
|
||||
return myInMemorySubscriptionMatcher.match(criteria, resource);
|
||||
}
|
||||
|
||||
private void assertUnsupported(IBaseResource resource, SearchParameterMap params) {
|
||||
assertFalse(match(resource, params).supported());
|
||||
}
|
||||
|
||||
private void assertMatched(IBaseResource resource, SearchParameterMap params) {
|
||||
private void assertMatched(Resource resource, SearchParameterMap params) {
|
||||
SubscriptionMatchResult result = match(resource, params);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertTrue(result.matched());
|
||||
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY, mySubscriptionStrategyEvaluator.determineStrategy(getCriteria(resource, params)));
|
||||
}
|
||||
|
||||
private void assertNotMatched(IBaseResource resource, SearchParameterMap params) {
|
||||
private void assertNotMatched(Resource resource, SearchParameterMap params) {
|
||||
SubscriptionMatchResult result = match(resource, params);
|
||||
assertTrue(result.getUnsupportedReason(), result.supported());
|
||||
assertFalse(result.matched());
|
||||
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY, mySubscriptionStrategyEvaluator.determineStrategy(getCriteria(resource, params)));
|
||||
}
|
||||
|
||||
private SubscriptionMatchResult match(Resource theResource, SearchParameterMap theParams) {
|
||||
return match(getCriteria(theResource, theParams), theResource);
|
||||
}
|
||||
|
||||
private String getCriteria(Resource theResource, SearchParameterMap theParams) {
|
||||
return theResource.getResourceType().name() + theParams.toNormalizedQueryString(myContext);
|
||||
}
|
||||
|
||||
private SubscriptionMatchResult match(String criteria, Resource theResource) {
|
||||
ourLog.info("Criteria: <{}>", criteria);
|
||||
return myInMemorySubscriptionMatcher.match(criteria, theResource);
|
||||
}
|
||||
|
||||
private void assertUnsupported(Resource resource, SearchParameterMap theParams) {
|
||||
SubscriptionMatchResult result = match(resource, theParams);
|
||||
assertFalse(result.supported());
|
||||
assertEquals(SubscriptionMatchingStrategy.DATABASE, mySubscriptionStrategyEvaluator.determineStrategy(getCriteria(resource, theParams)));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -92,7 +105,6 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("_has", new HasParam("Observation", "subject", "identifier", "urn:system|FOO"));
|
||||
String criteria = params.toNormalizedQueryString(myContext);
|
||||
assertUnsupported(patient, params);
|
||||
}
|
||||
|
||||
|
@ -129,7 +141,7 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
|
||||
TokenParam v0 = new TokenParam("foo", "testSearchCompositeParamN01");
|
||||
StringParam v1 = new StringParam("testSearchCompositeParamS01");
|
||||
CompositeParam<TokenParam, StringParam> val = new CompositeParam<TokenParam, StringParam>(v0, v1);
|
||||
CompositeParam<TokenParam, StringParam> val = new CompositeParam<>(v0, v1);
|
||||
SearchParameterMap params = new SearchParameterMap().setLoadSynchronous(true).add(Observation.SP_CODE_VALUE_STRING, val);
|
||||
assertUnsupported(o1, params);
|
||||
}
|
||||
|
@ -169,11 +181,11 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testIdNotSupported() {
|
||||
public void testIdSupported() {
|
||||
Observation o1 = new Observation();
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add("_id", new StringParam("testSearchForUnknownAlphanumericId"));
|
||||
assertUnsupported(o1, params);
|
||||
assertNotMatched(o1, params);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -189,7 +201,7 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSearchLastUpdatedParamUnsupported() throws InterruptedException {
|
||||
public void testSearchLastUpdatedParamUnsupported() {
|
||||
String methodName = "testSearchLastUpdatedParam";
|
||||
DateTimeType today = new DateTimeType(new Date(), TemporalPrecisionEnum.DAY);
|
||||
Patient patient = new Patient();
|
||||
|
@ -293,12 +305,12 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
@Test
|
||||
public void testSearchQuantityWrongParam() {
|
||||
Condition c1 = new Condition();
|
||||
c1.setAbatement(new Range().setLow((SimpleQuantity) new SimpleQuantity().setValue(1L)).setHigh((SimpleQuantity) new SimpleQuantity().setValue(1L)));
|
||||
c1.setAbatement(new Range().setLow(new SimpleQuantity().setValue(1L)).setHigh(new SimpleQuantity().setValue(1L)));
|
||||
SearchParameterMap params = new SearchParameterMap().setLoadSynchronous(true).add(Condition.SP_ABATEMENT_AGE, new QuantityParam("1"));
|
||||
assertMatched(c1, params);
|
||||
|
||||
Condition c2 = new Condition();
|
||||
c2.setOnset(new Range().setLow((SimpleQuantity) new SimpleQuantity().setValue(1L)).setHigh((SimpleQuantity) new SimpleQuantity().setValue(1L)));
|
||||
c2.setOnset(new Range().setLow(new SimpleQuantity().setValue(1L)).setHigh(new SimpleQuantity().setValue(1L)));
|
||||
|
||||
params = new SearchParameterMap().add(Condition.SP_ONSET_AGE, new QuantityParam("1"));
|
||||
assertMatched(c2, params);
|
||||
|
@ -380,13 +392,16 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
params.add(Patient.SP_FAMILY, new StringParam("testSearchNameParam01Fam"));
|
||||
try {
|
||||
String criteria = params.toNormalizedQueryString(myContext);
|
||||
CanonicalSubscription subscription = new CanonicalSubscription();
|
||||
subscription.setCriteriaString(criteria);
|
||||
subscription.setIdElement(new IdType("Subscription", 123L));
|
||||
ResourceModifiedMessage msg = new ResourceModifiedMessage(myContext, patient, ResourceModifiedMessage.OperationTypeEnum.CREATE);
|
||||
msg.setSubscriptionId("Subscription/123");
|
||||
msg.setId(new IdType("Patient/ABC"));
|
||||
SubscriptionMatchResult result = myInMemorySubscriptionMatcher.match(criteria, msg);
|
||||
SubscriptionMatchResult result = myInMemorySubscriptionMatcher.match(subscription, msg);
|
||||
fail();
|
||||
} catch (InternalErrorException e){
|
||||
assertEquals("Failure processing resource ID[Patient/ABC] for subscription ID[Subscription/123]: Invalid resource reference found at path[Patient.managingOrganization] - Does not contain resource type - urn:uuid:13720262-b392-465f-913e-54fb198ff954", e.getMessage());
|
||||
} catch (AssertionError e){
|
||||
assertEquals("Reference at managingOrganization is invalid: urn:uuid:13720262-b392-465f-913e-54fb198ff954", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -410,7 +425,7 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testSearchStringParam() throws Exception {
|
||||
public void testSearchStringParam() {
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester_testSearchStringParam").addGiven("Joe");
|
||||
|
@ -565,13 +580,11 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
|
||||
@Test
|
||||
public void testSearchTokenWithNotModifierUnsupported() {
|
||||
String male, female;
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("urn:system").setValue("001");
|
||||
patient.addName().setFamily("Tester").addGiven("Joe");
|
||||
patient.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
|
||||
List<String> patients;
|
||||
SearchParameterMap params;
|
||||
|
||||
params = new SearchParameterMap();
|
||||
|
@ -636,7 +649,6 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
o2.setValue(q2);
|
||||
|
||||
SearchParameterMap map;
|
||||
IBundleProvider found;
|
||||
QuantityParam param;
|
||||
|
||||
map = new SearchParameterMap();
|
||||
|
@ -678,9 +690,7 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("ABCDEFGHIJK");
|
||||
|
||||
List<String> ids;
|
||||
SearchParameterMap map;
|
||||
IBundleProvider results;
|
||||
|
||||
// Contains = true
|
||||
map = new SearchParameterMap();
|
||||
|
@ -871,7 +881,7 @@ public class InMemorySubscriptionMatcherTestR4 {
|
|||
map.add(Observation.SP_DATE, new DateParam("2011-01-02"));
|
||||
|
||||
for (Observation obs : nlist) {
|
||||
// assertNotMatched(obs, map);
|
||||
assertNotMatched(obs, map);
|
||||
}
|
||||
for (Observation obs : ylist) {
|
||||
ourLog.info("Obs {} has time {}", obs.getId(), obs.getEffectiveDateTimeType().getValue().toString());
|
||||
|
|
|
@ -57,7 +57,7 @@ public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourc
|
|||
@Before
|
||||
public void beforeSetSubscriptionActivatingInterceptor() {
|
||||
SubscriptionActivatingInterceptor.setWaitForSubscriptionActivationSynchronouslyForUnitTest(true);
|
||||
mySubscriptionLoader.initSubscriptions();
|
||||
mySubscriptionLoader.syncSubscriptions();
|
||||
}
|
||||
|
||||
|
||||
|
@ -109,7 +109,7 @@ public class RestHookActivatesPreExistingSubscriptionsR4Test extends BaseResourc
|
|||
createSubscription(criteria2, payload, ourListenerServerBase);
|
||||
|
||||
mySubscriptionTestUtil.registerRestHookInterceptor();
|
||||
mySubscriptionLoader.initSubscriptions();
|
||||
mySubscriptionLoader.syncSubscriptions();
|
||||
|
||||
sendObservation(code, "SNOMED-CT");
|
||||
|
||||
|
|
|
@ -113,10 +113,8 @@ public class RestHookTestDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
|
||||
observation.setStatus(ObservationStatusEnum.FINAL);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(observation).execute();
|
||||
|
||||
String observationId = methodOutcome.getId().getIdPart();
|
||||
observation.setId(observationId);
|
||||
IIdType id = myObservationDao.create(observation).getId();
|
||||
observation.setId(id);
|
||||
|
||||
return observation;
|
||||
}
|
||||
|
|
|
@ -4,7 +4,10 @@ package ca.uhn.fhir.jpa.subscription.resthook;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.provider.dstu3.BaseResourceProviderDstu3Test;
|
||||
import ca.uhn.fhir.jpa.subscription.NotificationServlet;
|
||||
import ca.uhn.fhir.jpa.subscription.SubscriptionTestUtil;
|
||||
import ca.uhn.fhir.jpa.subscription.module.cache.SubscriptionConstants;
|
||||
import ca.uhn.fhir.jpa.subscription.module.matcher.SubscriptionMatchingStrategy;
|
||||
import ca.uhn.fhir.rest.annotation.Create;
|
||||
import ca.uhn.fhir.rest.annotation.ResourceParam;
|
||||
import ca.uhn.fhir.rest.annotation.Update;
|
||||
|
@ -49,6 +52,8 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
|
||||
@Autowired
|
||||
private SubscriptionTestUtil mySubscriptionTestUtil;
|
||||
private static NotificationServlet ourNotificationServlet;
|
||||
private static String ourNotificationListenerServer;
|
||||
|
||||
@After
|
||||
public void afterUnregisterRestHookListener() {
|
||||
|
@ -79,9 +84,15 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
ourCreatedObservations.clear();
|
||||
ourUpdatedObservations.clear();
|
||||
ourContentTypes.clear();
|
||||
ourNotificationServlet.reset();
|
||||
}
|
||||
|
||||
private Subscription createSubscription(String theCriteria, String thePayload, String theEndpoint) throws InterruptedException {
|
||||
private Subscription createSubscription(String criteria, String payload, String endpoint) throws InterruptedException {
|
||||
return createSubscription(criteria, payload, endpoint, null);
|
||||
}
|
||||
|
||||
private Subscription createSubscription(String theCriteria, String thePayload, String theEndpoint,
|
||||
List<StringType> headers) throws InterruptedException {
|
||||
Subscription subscription = new Subscription();
|
||||
subscription.setReason("Monitor new neonatal function (note, age will be determined by the monitor)");
|
||||
subscription.setStatus(Subscription.SubscriptionStatus.REQUESTED);
|
||||
|
@ -91,15 +102,17 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
channel.setType(Subscription.SubscriptionChannelType.RESTHOOK);
|
||||
channel.setPayload(thePayload);
|
||||
channel.setEndpoint(theEndpoint);
|
||||
if (headers != null) {
|
||||
channel.setHeader(headers);
|
||||
}
|
||||
subscription.setChannel(channel);
|
||||
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(subscription).execute();
|
||||
subscription.setId(methodOutcome.getId().getIdPart());
|
||||
mySubscriptionIds.add(methodOutcome.getId());
|
||||
|
||||
waitForQueueToDrain();
|
||||
|
||||
return subscription;
|
||||
return (Subscription)methodOutcome.getResource();
|
||||
}
|
||||
|
||||
private Observation sendObservation(String code, String system) {
|
||||
|
@ -120,6 +133,55 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
return observation;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscription() throws Exception {
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
String criteria2 = "Observation?code=SNOMED-CT|" + code + "111&_format=xml";
|
||||
|
||||
createSubscription(criteria1, null, ourNotificationListenerServer,
|
||||
Collections.singletonList(new StringType("Authorization: abc-def")));
|
||||
createSubscription(criteria2, null, ourNotificationListenerServer);
|
||||
|
||||
sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification with authorization header
|
||||
waitForSize(1, ourNotificationServlet.getReceivedAuthorizationHeaders());
|
||||
Assert.assertEquals(1, ourNotificationServlet.getReceivedNotificationCount());
|
||||
Assert.assertEquals("abc-def", ourNotificationServlet.getReceivedAuthorizationHeaders().get(0));
|
||||
ourNotificationServlet.reset();
|
||||
|
||||
sendObservation(code, "SNOMED-CT");
|
||||
|
||||
// Should see 1 subscription notification with authorization header
|
||||
waitForSize(1, ourNotificationServlet.getReceivedAuthorizationHeaders());
|
||||
Assert.assertEquals(1, ourNotificationServlet.getReceivedNotificationCount());
|
||||
Assert.assertEquals("abc-def", ourNotificationServlet.getReceivedAuthorizationHeaders().get(0));
|
||||
ourNotificationServlet.reset();
|
||||
|
||||
Observation observationTemp3 = sendObservation(code, "SNOMED-CT");
|
||||
|
||||
/// Should see 1 subscription notification with authorization header
|
||||
waitForSize(1, ourNotificationServlet.getReceivedAuthorizationHeaders());
|
||||
Assert.assertEquals(1, ourNotificationServlet.getReceivedNotificationCount());
|
||||
Assert.assertEquals("abc-def", ourNotificationServlet.getReceivedAuthorizationHeaders().get(0));
|
||||
ourNotificationServlet.reset();
|
||||
|
||||
Observation observation3 = ourClient.read(Observation.class, observationTemp3.getId());
|
||||
CodeableConcept codeableConcept = new CodeableConcept();
|
||||
observation3.setCode(codeableConcept);
|
||||
Coding coding = codeableConcept.addCoding();
|
||||
coding.setCode(code + "111");
|
||||
coding.setSystem("SNOMED-CT");
|
||||
ourClient.update().resource(observation3).withId(observation3.getIdElement()).execute();
|
||||
|
||||
// Should see 2 subscription notifications with and without authorization header
|
||||
waitForSize(1, ourNotificationServlet.getReceivedAuthorizationHeaders());
|
||||
Assert.assertEquals(1, ourNotificationServlet.getReceivedNotificationCount());
|
||||
Assert.assertNull(ourNotificationServlet.getReceivedAuthorizationHeaders().get(0));
|
||||
ourNotificationServlet.reset();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRestHookSubscriptionApplicationFhirJson() throws Exception {
|
||||
String payload = "application/fhir+json";
|
||||
|
@ -291,7 +353,7 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
waitForSize(0, ourCreatedObservations);
|
||||
waitForSize(5, ourUpdatedObservations);
|
||||
|
||||
Assert.assertFalse(subscription1.getId().equals(subscription2.getId()));
|
||||
Assert.assertNotEquals(subscription1.getId(), subscription2.getId());
|
||||
Assert.assertFalse(observation1.getId().isEmpty());
|
||||
Assert.assertFalse(observation2.getId().isEmpty());
|
||||
}
|
||||
|
@ -353,16 +415,70 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
mySubscriptionTestUtil.waitForQueueToDrain();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionActivatesInMemoryTag() throws Exception {
|
||||
String payload = "application/fhir+xml";
|
||||
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?code=SNOMED-CT|" + code + "&_format=xml";
|
||||
|
||||
Subscription subscriptionOrig = createSubscription(criteria1, payload, ourListenerServerBase);
|
||||
IdType subscriptionId = subscriptionOrig.getIdElement();
|
||||
|
||||
assertEquals(Subscription.SubscriptionStatus.REQUESTED, subscriptionOrig.getStatus());
|
||||
List<Coding> tags = subscriptionOrig.getMeta().getTag();
|
||||
assertEquals(1, tags.size());
|
||||
Coding tag = tags.get(0);
|
||||
assertEquals(SubscriptionConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.getCode());
|
||||
assertEquals("In-memory", tag.getDisplay());
|
||||
|
||||
Subscription subscriptionActivated = ourClient.read().resource(Subscription.class).withId(subscriptionId.toUnqualifiedVersionless()).execute();
|
||||
assertEquals(Subscription.SubscriptionStatus.ACTIVE, subscriptionActivated.getStatus());
|
||||
tags = subscriptionActivated.getMeta().getTag();
|
||||
assertEquals(1, tags.size());
|
||||
tag = tags.get(0);
|
||||
assertEquals(SubscriptionConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||
assertEquals(SubscriptionMatchingStrategy.IN_MEMORY.toString(), tag.getCode());
|
||||
assertEquals("In-memory", tag.getDisplay());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSubscriptionActivatesDatabaseTag() throws Exception {
|
||||
String payload = "application/fhir+xml";
|
||||
|
||||
Subscription subscriptionOrig = createSubscription("Observation?code=17861-6&context.type=IHD", payload, ourListenerServerBase);
|
||||
IdType subscriptionId = subscriptionOrig.getIdElement();
|
||||
|
||||
List<Coding> tags = subscriptionOrig.getMeta().getTag();
|
||||
assertEquals(1, tags.size());
|
||||
Coding tag = tags.get(0);
|
||||
assertEquals(SubscriptionConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.getCode());
|
||||
assertEquals("Database", tag.getDisplay());
|
||||
|
||||
Subscription subscription = ourClient.read().resource(Subscription.class).withId(subscriptionId.toUnqualifiedVersionless()).execute();
|
||||
assertEquals(Subscription.SubscriptionStatus.ACTIVE, subscription.getStatus());
|
||||
tags = subscription.getMeta().getTag();
|
||||
assertEquals(1, tags.size());
|
||||
tag = tags.get(0);
|
||||
assertEquals(SubscriptionConstants.EXT_SUBSCRIPTION_MATCHING_STRATEGY, tag.getSystem());
|
||||
assertEquals(SubscriptionMatchingStrategy.DATABASE.toString(), tag.getCode());
|
||||
assertEquals("Database", tag.getDisplay());
|
||||
}
|
||||
|
||||
@BeforeClass
|
||||
public static void startListenerServer() throws Exception {
|
||||
ourListenerPort = PortUtil.findFreePort();
|
||||
ourListenerRestServer = new RestfulServer(FhirContext.forDstu3());
|
||||
ourListenerServerBase = "http://localhost:" + ourListenerPort + "/fhir/context";
|
||||
ourNotificationListenerServer = "http://localhost:" + ourListenerPort + "/fhir/subscription";
|
||||
|
||||
ObservationListener obsListener = new ObservationListener();
|
||||
ourListenerRestServer.setResourceProviders(obsListener);
|
||||
|
||||
ourListenerServer = new Server(ourListenerPort);
|
||||
ourNotificationServlet = new NotificationServlet();
|
||||
|
||||
ServletContextHandler proxyHandler = new ServletContextHandler();
|
||||
proxyHandler.setContextPath("/");
|
||||
|
@ -370,6 +486,9 @@ public class RestHookTestDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
ServletHolder servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(ourListenerRestServer);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/context/*");
|
||||
servletHolder = new ServletHolder();
|
||||
servletHolder.setServlet(ourNotificationServlet);
|
||||
proxyHandler.addServlet(servletHolder, "/fhir/subscription");
|
||||
|
||||
ourListenerServer.setHandler(proxyHandler);
|
||||
ourListenerServer.start();
|
||||
|
|
|
@ -23,6 +23,7 @@ import java.util.concurrent.TimeUnit;
|
|||
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.hamcrest.Matchers.matchesPattern;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
|
@ -112,6 +113,39 @@ public class RestHookTestR4Test extends BaseSubscriptionsR4Test {
|
|||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testPlaceholderReferencesInTransactionAreResolvedCorrectly() throws Exception {
|
||||
|
||||
String payload = "application/fhir+json";
|
||||
String code = "1000000050";
|
||||
String criteria1 = "Observation?";
|
||||
createSubscription(criteria1, payload);
|
||||
waitForActivatedSubscriptionCount(1);
|
||||
|
||||
// Create a transaction that should match
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.setId(IdType.newRandomUuid());
|
||||
patient.getIdentifierFirstRep().setSystem("foo").setValue("AAA");
|
||||
bundle.addEntry().setResource(patient).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Patient");
|
||||
|
||||
Observation observation = new Observation();
|
||||
observation.getIdentifierFirstRep().setSystem("foo").setValue("1");
|
||||
observation.getCode().addCoding().setCode(code).setSystem("SNOMED-CT");
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
observation.getSubject().setReference(patient.getId());
|
||||
bundle.addEntry().setResource(observation).getRequest().setMethod(Bundle.HTTPVerb.POST).setUrl("Observation");
|
||||
|
||||
// Send the transaction
|
||||
mySystemDao.transaction(null, bundle);
|
||||
|
||||
waitForSize(1, ourUpdatedObservations);
|
||||
|
||||
assertThat(ourUpdatedObservations.get(0).getSubject().getReference(), matchesPattern("Patient/[0-9]+"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdatesHaveCorrectMetadataUsingTransactions() throws Exception {
|
||||
String payload = "application/fhir+json";
|
||||
|
@ -206,7 +240,7 @@ public class RestHookTestR4Test extends BaseSubscriptionsR4Test {
|
|||
|
||||
waitForActivatedSubscriptionCount(1);
|
||||
for (int i = 0; i < 5; i++) {
|
||||
int changes = this.mySubscriptionLoader.doInitSubscriptionsForUnitTest();
|
||||
int changes = this.mySubscriptionLoader.doSyncSubscriptionsForUnitTest();
|
||||
assertEquals(0, changes);
|
||||
}
|
||||
}
|
||||
|
@ -874,7 +908,7 @@ public class RestHookTestR4Test extends BaseSubscriptionsR4Test {
|
|||
sp.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
sp.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
mySearchParameterDao.create(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
mySearchParamRegistry.forceRefresh();
|
||||
createSubscription(criteria, "application/json");
|
||||
waitForActivatedSubscriptionCount(1);
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigDstu2Test extends B
|
|||
ourCreatedObservations.clear();
|
||||
ourUpdatedObservations.clear();
|
||||
|
||||
mySubscriptionLoader.initSubscriptions();
|
||||
mySubscriptionLoader.syncSubscriptions();
|
||||
}
|
||||
|
||||
private void waitForQueueToDrain() throws InterruptedException {
|
||||
|
|
|
@ -0,0 +1,186 @@
|
|||
package ca.uhn.fhir.jpa.subscription.resthook;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.config.StoppableSubscriptionDeliveringRestHookSubscriber;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.IInterceptorRegistry;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.jpa.subscription.BaseSubscriptionsR4Test;
|
||||
import ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription;
|
||||
import ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import org.hl7.fhir.r4.model.IdType;
|
||||
import org.hl7.fhir.r4.model.Observation;
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.hamcrest.Matchers.hasItem;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* Test the rest-hook subscriptions
|
||||
*/
|
||||
@ContextConfiguration(classes = {RestHookWithInterceptorR4Test.MyTestCtxConfig.class})
|
||||
public class RestHookWithInterceptorR4Test extends BaseSubscriptionsR4Test {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(RestHookWithInterceptorR4Test.class);
|
||||
private static boolean ourNextModifyResourceId;
|
||||
private static boolean ourNextBeforeRestHookDeliveryReturn;
|
||||
private static boolean ourHitBeforeRestHookDelivery;
|
||||
private static boolean ourNextAfterRestHookDeliveryReturn;
|
||||
private static boolean ourHitAfterRestHookDelivery;
|
||||
private static boolean ourNextAddHeader;
|
||||
private static FhirContext ourCtx = FhirContext.forR4();
|
||||
|
||||
@Autowired
|
||||
StoppableSubscriptionDeliveringRestHookSubscriber myStoppableSubscriptionDeliveringRestHookSubscriber;
|
||||
|
||||
@After
|
||||
public void cleanupStoppableSubscriptionDeliveringRestHookSubscriber() {
|
||||
myStoppableSubscriptionDeliveringRestHookSubscriber.setCountDownLatch(null);
|
||||
myStoppableSubscriptionDeliveringRestHookSubscriber.unPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void before() throws Exception {
|
||||
super.before();
|
||||
ourNextModifyResourceId = false;
|
||||
ourNextAddHeader = false;
|
||||
ourNextBeforeRestHookDeliveryReturn = true;
|
||||
ourNextAfterRestHookDeliveryReturn = true;
|
||||
ourHitBeforeRestHookDelivery = false;
|
||||
ourHitAfterRestHookDelivery = false;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeRestHookDelivery_ModifyResourceId() throws Exception {
|
||||
ourNextModifyResourceId = true;
|
||||
|
||||
// Create a subscription
|
||||
CountDownLatch registerLatch = registerLatchHookInterceptor(1, Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED);
|
||||
createSubscription("Observation?status=final", "application/fhir+json");
|
||||
registerLatch.await(10, TimeUnit.SECONDS);
|
||||
|
||||
// Creating a matching resource
|
||||
CountDownLatch deliveryLatch = registerLatchHookInterceptor(1, Pointcut.SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY);
|
||||
sendObservation();
|
||||
deliveryLatch.await(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(0, ourCreatedObservations.size());
|
||||
assertEquals(1, ourUpdatedObservations.size());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
||||
assertEquals("Observation/A", ourUpdatedObservations.get(0).getId());
|
||||
assertTrue(ourHitBeforeRestHookDelivery);
|
||||
assertTrue(ourHitAfterRestHookDelivery);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBeforeRestHookDelivery_AddHeader() throws Exception {
|
||||
ourNextAddHeader = true;
|
||||
|
||||
// Create a subscription
|
||||
CountDownLatch registerLatch = registerLatchHookInterceptor(1, Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED);
|
||||
createSubscription("Observation?status=final", "application/fhir+json");
|
||||
registerLatch.await(10, TimeUnit.SECONDS);
|
||||
|
||||
// Creating a matching resource
|
||||
CountDownLatch deliveryLatch = registerLatchHookInterceptor(1, Pointcut.SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY);
|
||||
sendObservation();
|
||||
deliveryLatch.await(10, TimeUnit.SECONDS);
|
||||
|
||||
assertEquals(0, ourCreatedObservations.size());
|
||||
assertEquals(1, ourUpdatedObservations.size());
|
||||
assertEquals(Constants.CT_FHIR_JSON_NEW, ourContentTypes.get(0));
|
||||
assertTrue(ourHitBeforeRestHookDelivery);
|
||||
assertTrue(ourHitAfterRestHookDelivery);
|
||||
assertThat(ourHeaders, hasItem("X-Foo: Bar"));
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testBeforeRestHookDelivery_AbortDelivery() throws Exception {
|
||||
ourNextBeforeRestHookDeliveryReturn = false;
|
||||
|
||||
// Create a subscription
|
||||
CountDownLatch registerLatch = registerLatchHookInterceptor(1, Pointcut.SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED);
|
||||
createSubscription("Observation?status=final", "application/fhir+json");
|
||||
registerLatch.await(10, TimeUnit.SECONDS);
|
||||
|
||||
sendObservation();
|
||||
|
||||
Thread.sleep(1000);
|
||||
assertEquals(0, ourUpdatedObservations.size());
|
||||
}
|
||||
|
||||
protected Observation sendObservation() {
|
||||
Observation observation = new Observation();
|
||||
observation.setStatus(Observation.ObservationStatus.FINAL);
|
||||
MethodOutcome methodOutcome = ourClient.create().resource(observation).execute();
|
||||
observation.setId(methodOutcome.getId());
|
||||
return observation;
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class MyTestCtxConfig {
|
||||
|
||||
@Autowired
|
||||
private IInterceptorRegistry myInterceptorRegistry;
|
||||
|
||||
@Bean
|
||||
public MyTestInterceptor interceptor() {
|
||||
MyTestInterceptor retVal = new MyTestInterceptor();
|
||||
myInterceptorRegistry.registerInterceptor(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Interceptor class
|
||||
*/
|
||||
@Interceptor
|
||||
public static class MyTestInterceptor {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public MyTestInterceptor() {
|
||||
ourLog.info("Creating interceptor");
|
||||
}
|
||||
|
||||
@Hook(Pointcut.SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY)
|
||||
public boolean beforeRestHookDelivery(ResourceDeliveryMessage theDeliveryMessage, CanonicalSubscription theSubscription) {
|
||||
if (ourNextModifyResourceId) {
|
||||
theDeliveryMessage.getPayload(ourCtx).setId(new IdType("Observation/A"));
|
||||
}
|
||||
if (ourNextAddHeader) {
|
||||
theSubscription.addHeader("X-Foo: Bar");
|
||||
}
|
||||
|
||||
ourHitBeforeRestHookDelivery = true;
|
||||
return ourNextBeforeRestHookDeliveryReturn;
|
||||
}
|
||||
|
||||
@Hook(Pointcut.SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY)
|
||||
public boolean afterRestHookDelivery(ResourceDeliveryMessage theDeliveryMessage, CanonicalSubscription theSubscription) {
|
||||
ourHitAfterRestHookDelivery = true;
|
||||
return ourNextAfterRestHookDeliveryReturn;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||
import ca.uhn.fhir.jpa.dao.r4.BaseJpaR4Test;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptMap;
|
||||
import ca.uhn.fhir.jpa.entity.TermConceptMapGroup;
|
||||
|
@ -8,12 +9,11 @@ import ca.uhn.fhir.jpa.entity.TermConceptMapGroupElementTarget;
|
|||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.model.CanonicalType;
|
||||
import org.hl7.fhir.r4.model.ConceptMap;
|
||||
import org.hl7.fhir.r4.model.Enumerations.ConceptMapEquivalence;
|
||||
import org.hl7.fhir.r4.model.UriType;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.*;
|
||||
import org.junit.rules.ExpectedException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
@ -32,11 +32,26 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
public final ExpectedException expectedException = ExpectedException.none();
|
||||
private IIdType myConceptMapId;
|
||||
|
||||
private void persistConceptMap() {
|
||||
@Before
|
||||
public void before() {
|
||||
myDaoConfig.setAllowExternalReferences(true);
|
||||
}
|
||||
|
||||
@After
|
||||
public void after() {
|
||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||
}
|
||||
|
||||
private void createAndPersistConceptMap() {
|
||||
ConceptMap conceptMap = createConceptMap();
|
||||
persistConceptMap(conceptMap);
|
||||
}
|
||||
|
||||
private void persistConceptMap(ConceptMap theConceptMap) {
|
||||
new TransactionTemplate(myTxManager).execute(new TransactionCallbackWithoutResult() {
|
||||
@Override
|
||||
protected void doInTransactionWithoutResult(TransactionStatus theStatus) {
|
||||
myConceptMapId = myConceptMapDao.create(createConceptMap(), mySrd).getId().toUnqualifiedVersionless();
|
||||
myConceptMapId = myConceptMapDao.create(theConceptMap, mySrd).getId().toUnqualifiedVersionless();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -63,6 +78,17 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testCreateConceptMapWithVirtualSourceSystem() {
|
||||
ConceptMap conceptMap = createConceptMap();
|
||||
conceptMap.getGroup().forEach(t->t.setSource(null));
|
||||
conceptMap.setSource(new CanonicalType("http://hl7.org/fhir/uv/livd/StructureDefinition/loinc-livd"));
|
||||
|
||||
persistConceptMap(conceptMap);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateConceptMapWithMissingTargetSystems() {
|
||||
|
||||
|
@ -113,17 +139,17 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testDuplicateConceptMapUrls() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
|
||||
expectedException.expect(UnprocessableEntityException.class);
|
||||
expectedException.expectMessage("Can not create multiple ConceptMap resources with ConceptMap.url \"http://example.com/my_concept_map\", already have one with resource ID: ConceptMap/" + myConceptMapId.getIdPart());
|
||||
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoreTermConceptMapAndChildren() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -301,7 +327,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateByCodeSystemsAndSourceCodeOneToMany() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -355,7 +381,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateByCodeSystemsAndSourceCodeOneToOne() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -429,7 +455,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateByCodeSystemsAndSourceCodeUnmapped() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -482,7 +508,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithCodeOnly() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -550,7 +576,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithSourceAndTargetSystem2() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -598,7 +624,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithSourceAndTargetSystem3() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -658,7 +684,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithSourceSystem() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -728,7 +754,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithSourceSystemAndVersion1() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -776,7 +802,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithSourceSystemAndVersion3() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -836,7 +862,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithSourceValueSet() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -906,7 +932,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateUsingPredicatesWithTargetValueSet() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -976,7 +1002,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverse() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1025,7 +1051,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseByCodeSystemsAndSourceCodeUnmapped() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1048,7 +1074,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseUsingPredicatesWithCodeOnly() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1104,7 +1130,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem1() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1153,7 +1179,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseUsingPredicatesWithSourceAndTargetSystem4() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1202,7 +1228,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseUsingPredicatesWithSourceSystem() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1260,7 +1286,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseUsingPredicatesWithSourceSystemAndVersion() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1320,7 +1346,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseUsingPredicatesWithSourceValueSet() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
@ -1378,7 +1404,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testTranslateWithReverseUsingPredicatesWithTargetValueSet() {
|
||||
persistConceptMap();
|
||||
createAndPersistConceptMap();
|
||||
ConceptMap conceptMap = myConceptMapDao.read(myConceptMapId);
|
||||
|
||||
ourLog.info("ConceptMap:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(conceptMap));
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.slf4j.LoggerFactory;
|
|||
|
||||
import java.sql.SQLException;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
|
@ -78,7 +79,13 @@ public class AddIdGeneratorTask extends BaseTask<AddIdGeneratorTask> {
|
|||
}
|
||||
|
||||
if (isNotBlank(sql)) {
|
||||
if (JdbcUtils.getSequenceNames(getConnectionProperties()).contains(myGeneratorName)) {
|
||||
Set<String> sequenceNames =
|
||||
JdbcUtils.getSequenceNames(getConnectionProperties())
|
||||
.stream()
|
||||
.map(String::toLowerCase)
|
||||
.collect(Collectors.toSet());
|
||||
ourLog.debug("Currently have sequences: {}", sequenceNames);
|
||||
if (sequenceNames.contains(myGeneratorName.toLowerCase())) {
|
||||
ourLog.info("Sequence {} already exists - No action performed", myGeneratorName);
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ public class AddTableRawSqlTask extends BaseTableTask<AddTableRawSqlTask> {
|
|||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(AddTableRawSqlTask.class);
|
||||
private Map<DriverTypeEnum, List<String>> myDriverToSqls = new HashMap<>();
|
||||
private List<String> myDriverNeutralSqls = new ArrayList<>();
|
||||
|
||||
public void addSql(DriverTypeEnum theDriverType, @Language("SQL") String theSql) {
|
||||
Validate.notNull(theDriverType);
|
||||
|
@ -52,7 +53,9 @@ public class AddTableRawSqlTask extends BaseTableTask<AddTableRawSqlTask> {
|
|||
return;
|
||||
}
|
||||
|
||||
List<String> sqlStatements = myDriverToSqls.get(getDriverType());
|
||||
List<String> sqlStatements = myDriverToSqls.computeIfAbsent(getDriverType(), t -> new ArrayList<>());
|
||||
sqlStatements.addAll(myDriverNeutralSqls);
|
||||
|
||||
ourLog.info("Going to create table {} using {} SQL statements", getTableName(), sqlStatements.size());
|
||||
getConnectionProperties().getTxTemplate().execute(t -> {
|
||||
|
||||
|
@ -65,4 +68,9 @@ public class AddTableRawSqlTask extends BaseTableTask<AddTableRawSqlTask> {
|
|||
});
|
||||
|
||||
}
|
||||
|
||||
public void addSql(String theSql) {
|
||||
Validate.notBlank("theSql must not be null", theSql);
|
||||
myDriverNeutralSqls.add(theSql);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -329,6 +329,10 @@ public class BaseMigrationTasks<T extends Enum> {
|
|||
myTask.addSql(theDriverTypeEnum, theSql);
|
||||
return this;
|
||||
}
|
||||
|
||||
public void addSql(@Language("SQL") String theSql) {
|
||||
myTask.addSql(theSql);
|
||||
}
|
||||
}
|
||||
|
||||
public class BuilderAddTableByColumns implements IAcceptsTasks {
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
package ca.uhn.fhir.jpa.migrate.taskdef;
|
||||
|
||||
import ca.uhn.fhir.jpa.migrate.tasks.api.BaseMigrationTasks;
|
||||
import ca.uhn.fhir.jpa.model.entity.SearchParamPresent;
|
||||
import ca.uhn.fhir.util.VersionEnum;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.List;
|
||||
|
@ -66,4 +68,35 @@ public class ArbitrarySqlTaskTest extends BaseTest {
|
|||
getMigrator().migrate();
|
||||
|
||||
}
|
||||
|
||||
private static class TestUpdateTasks extends BaseMigrationTasks<VersionEnum> {
|
||||
|
||||
public TestUpdateTasks() {
|
||||
Builder v = forVersion(VersionEnum.V3_5_0);
|
||||
v
|
||||
.addTableRawSql("A")
|
||||
.addSql("delete from TEST_UPDATE_TASK where RES_TYPE = 'Patient'");
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUpdateTask() {
|
||||
executeSql("create table TEST_UPDATE_TASK (PID bigint not null, RES_TYPE varchar(255), PARAM_NAME varchar(255))");
|
||||
executeSql("insert into TEST_UPDATE_TASK (PID, RES_TYPE, PARAM_NAME) values (1, 'Patient', 'identifier')");
|
||||
|
||||
List<Map<String, Object>> rows = executeQuery("select * from TEST_UPDATE_TASK");
|
||||
assertEquals(1, rows.size());
|
||||
|
||||
TestUpdateTasks migrator = new TestUpdateTasks();
|
||||
getMigrator().addTasks(migrator.getTasks(VersionEnum.V3_3_0, VersionEnum.V3_6_0));
|
||||
getMigrator().migrate();
|
||||
|
||||
rows = executeQuery("select * from TEST_UPDATE_TASK");
|
||||
assertEquals(0, rows.size());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -72,12 +72,53 @@
|
|||
<groupId>org.hibernate</groupId>
|
||||
<artifactId>hibernate-search-orm</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>xml-apis</artifactId>
|
||||
<groupId>xml-apis</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jscience</groupId>
|
||||
<artifactId>jscience</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.apache.commons</groupId>
|
||||
<artifactId>commons-collections4</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Java -->
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- test dependencies -->
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
<build>
|
||||
|
|
|
@ -40,7 +40,7 @@ public class ModelConfig {
|
|||
* <li><code>"http://hl7.org/fhir/StructureDefinition/*"</code></li>
|
||||
* </ul>
|
||||
*/
|
||||
public static final Set<String> DEFAULT_LOGICAL_BASE_URLS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(
|
||||
public static final Set<String> DEFAULT_LOGICAL_BASE_URLS = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(
|
||||
"http://hl7.org/fhir/ValueSet/*",
|
||||
"http://hl7.org/fhir/CodeSystem/*",
|
||||
"http://hl7.org/fhir/valueset-*",
|
||||
|
@ -57,6 +57,7 @@ public class ModelConfig {
|
|||
private boolean myDefaultSearchParamsCanBeOverridden = false;
|
||||
private Set<Subscription.SubscriptionChannelType> mySupportedSubscriptionTypes = new HashSet<>();
|
||||
private String myEmailFromAddress = "noreply@unknown.com";
|
||||
private boolean mySubscriptionMatchingEnabled = true;
|
||||
|
||||
/**
|
||||
* If set to {@code true} the default search params (i.e. the search parameters that are
|
||||
|
@ -225,7 +226,7 @@ public class ModelConfig {
|
|||
}
|
||||
}
|
||||
|
||||
HashSet<String> treatBaseUrlsAsLocal = new HashSet<String>();
|
||||
HashSet<String> treatBaseUrlsAsLocal = new HashSet<>();
|
||||
for (String next : ObjectUtils.defaultIfNull(theTreatBaseUrlsAsLocal, new HashSet<String>())) {
|
||||
while (next.endsWith("/")) {
|
||||
next = next.substring(0, next.length() - 1);
|
||||
|
@ -320,6 +321,27 @@ public class ModelConfig {
|
|||
return Collections.unmodifiableSet(mySupportedSubscriptionTypes);
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is true) the server will match incoming resources against active subscriptions
|
||||
* and send them to the subscription channel. If set to <code>false</code> no matching or sending occurs.
|
||||
* @since 3.7.0
|
||||
*/
|
||||
|
||||
public boolean isSubscriptionMatchingEnabled() {
|
||||
return mySubscriptionMatchingEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is true) the server will match incoming resources against active subscriptions
|
||||
* and send them to the subscription channel. If set to <code>false</code> no matching or sending occurs.
|
||||
* @since 3.7.0
|
||||
*/
|
||||
|
||||
|
||||
public void setSubscriptionMatchingEnabled(boolean theSubscriptionMatchingEnabled) {
|
||||
mySubscriptionMatchingEnabled = theSubscriptionMatchingEnabled;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
public void clearSupportedSubscriptionTypesForUnitTest() {
|
||||
mySupportedSubscriptionTypes.clear();
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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 java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This annotation should be placed on
|
||||
* {@link Interceptor Subscription Interceptor}
|
||||
* bean methods.
|
||||
* <p>
|
||||
* Methods with this annotation are invoked immediately before a REST HOOK
|
||||
* subscription delivery
|
||||
* </p>
|
||||
*
|
||||
* @see Interceptor
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Hook {
|
||||
|
||||
/**
|
||||
* Provides the specific point where this method should be invoked
|
||||
*/
|
||||
Pointcut[] value();
|
||||
|
||||
}
|
|
@ -0,0 +1,82 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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 com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import com.google.common.collect.Multimaps;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class HookParams {
|
||||
|
||||
private ListMultimap<Class<?>, Object> myParams = ArrayListMultimap.create();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public HookParams() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public HookParams(Object... theParams) {
|
||||
for (Object next : theParams) {
|
||||
add(next);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> void add(T theNext) {
|
||||
Class<T> nextClass = (Class<T>) theNext.getClass();
|
||||
add(nextClass, theNext);
|
||||
}
|
||||
|
||||
public <T> HookParams add(Class<T> theType, T theParam) {
|
||||
myParams.put(theType, theParam);
|
||||
return this;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T get(Class<T> theParamType, int theIndex) {
|
||||
List<T> objects = (List<T>) myParams.get(theParamType);
|
||||
T retVal = null;
|
||||
if (objects.size() > theIndex) {
|
||||
retVal = objects.get(theIndex);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an unmodifiable multimap of the params, where the
|
||||
* key is the param type and the value is the actual instance
|
||||
*/
|
||||
public ListMultimap<Class<?>, Object> getParamsForType() {
|
||||
return Multimaps.unmodifiableListMultimap(myParams);
|
||||
}
|
||||
|
||||
public Collection<Object> values() {
|
||||
return Collections.unmodifiableCollection(myParams.values());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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 com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
/**
|
||||
* This is currently only here for unit tests!
|
||||
*
|
||||
* DO NOT USE IN NON-TEST CODE. Maybe this will change in the future?
|
||||
*/
|
||||
@FunctionalInterface
|
||||
@VisibleForTesting
|
||||
public interface IAnonymousLambdaHook {
|
||||
|
||||
void invoke(HookParams theArgs);
|
||||
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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%
|
||||
*/
|
||||
|
||||
public interface IInterceptorBroadcaster {
|
||||
|
||||
/**
|
||||
* Invoke the interceptor methods
|
||||
*/
|
||||
boolean callHooks(Pointcut thePointcut, HookParams theParams);
|
||||
|
||||
/**
|
||||
* Invoke the interceptor methods
|
||||
*/
|
||||
boolean callHooks(Pointcut thePointcut, Object... theParams);
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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 com.google.common.annotations.VisibleForTesting;
|
||||
|
||||
public interface IInterceptorRegistry {
|
||||
|
||||
int DEFAULT_ORDER = 0;
|
||||
|
||||
/**
|
||||
* Register an interceptor. This method has no effect if the given interceptor is already registered.
|
||||
*
|
||||
* @param theInterceptor The interceptor to register
|
||||
* @return Returns <code>true</code> if at least one valid hook method was found on this interceptor
|
||||
*/
|
||||
boolean registerInterceptor(Object theInterceptor);
|
||||
|
||||
/**
|
||||
* Unregister an interceptor. This method has no effect if the given interceptor is not already registered.
|
||||
*
|
||||
* @param theInterceptor The interceptor to unregister
|
||||
*/
|
||||
void unregisterInterceptor(Object theInterceptor);
|
||||
|
||||
/**
|
||||
* @deprecated to be removed
|
||||
*/
|
||||
@Deprecated
|
||||
boolean registerGlobalInterceptor(Object theInterceptor);
|
||||
|
||||
/**
|
||||
* @deprecated to be removed
|
||||
*/
|
||||
@Deprecated
|
||||
void unregisterGlobalInterceptor(Object theInterceptor);
|
||||
|
||||
|
||||
@VisibleForTesting
|
||||
void registerAnonymousHookForUnitTest(Pointcut thePointcut, IAnonymousLambdaHook theHook);
|
||||
|
||||
@VisibleForTesting
|
||||
void registerAnonymousHookForUnitTest(Pointcut thePointcut, int theOrder, IAnonymousLambdaHook theHook);
|
||||
|
||||
@VisibleForTesting
|
||||
void clearAnonymousHookForUnitTest();
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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 java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* This annotation declares a bean as a subscription interceptor
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.TYPE)
|
||||
public @interface Interceptor {
|
||||
|
||||
/**
|
||||
* @return Declares that an interceptor should be manually registered with the registry,
|
||||
* and should not auto-register using Spring autowiring.
|
||||
*/
|
||||
boolean manualRegistration() default false;
|
||||
|
||||
}
|
|
@ -0,0 +1,179 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.api;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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 java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Value for {@link Hook#value()}
|
||||
*/
|
||||
public enum Pointcut {
|
||||
|
||||
/**
|
||||
* Invoked immediately after the delivery of a REST HOOK subscription.
|
||||
* <p>
|
||||
* When this hook is called, all processing is complete so this hook should not
|
||||
* make any changes to the parameters.
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription</li>
|
||||
* <li>ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage</li>
|
||||
* </ul>
|
||||
*/
|
||||
SUBSCRIPTION_AFTER_REST_HOOK_DELIVERY("ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription", "ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage"),
|
||||
|
||||
/**
|
||||
* Invoked immediately before the delivery of a REST HOOK subscription.
|
||||
* <p>
|
||||
* Hooks may make changes to the delivery payload, or make changes to the
|
||||
* canonical subscription such as adding headers, modifying the channel
|
||||
* endpoint, etc.
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription</li>
|
||||
* <li>ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage</li>
|
||||
* </ul>
|
||||
*/
|
||||
SUBSCRIPTION_BEFORE_REST_HOOK_DELIVERY("ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription", "ca.uhn.fhir.jpa.subscription.module.subscriber.ResourceDeliveryMessage"),
|
||||
|
||||
/**
|
||||
* Invoked whenever a persisted resource (a resource that has just been stored in the
|
||||
* database via a create/update/patch/etc.) has been checked for whether any subscriptions
|
||||
* were triggered as a result of the operation
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage</li>
|
||||
* </ul>
|
||||
*/
|
||||
SUBSCRIPTION_AFTER_PERSISTED_RESOURCE_CHECKED("ca.uhn.fhir.jpa.subscription.module.ResourceModifiedMessage"),
|
||||
|
||||
|
||||
/**
|
||||
* Invoked immediately after an active subscription is "registered". In HAPI FHIR, when
|
||||
* a subscription
|
||||
* <p>
|
||||
* Hooks may make changes to the canonicalized subscription and this will have an effect
|
||||
* on processing across this server. Note however that timing issues may occur, since the
|
||||
* subscription is already technically live by the time this hook is called.
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription</li>
|
||||
* </ul>
|
||||
*/
|
||||
SUBSCRIPTION_AFTER_ACTIVE_SUBSCRIPTION_REGISTERED("ca.uhn.fhir.jpa.subscription.module.CanonicalSubscription"),
|
||||
|
||||
/**
|
||||
* Invoked before a resource will be created, immediately before the resource
|
||||
* is persisted to the database.
|
||||
* <p>
|
||||
* Hooks will have access to the contents of the resource being created
|
||||
* and may choose to make modifications to it. These changes will be
|
||||
* reflected in permanent storage.
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource</li>
|
||||
* </ul>
|
||||
*/
|
||||
OP_PRESTORAGE_RESOURCE_CREATED("org.hl7.fhir.instance.model.api.IBaseResource"),
|
||||
|
||||
/**
|
||||
* Invoked before a resource will be created, immediately before the transaction
|
||||
* is committed (after all validation and other business rules have successfully
|
||||
* completed, and any other database activity is complete.
|
||||
* <p>
|
||||
* Hooks will have access to the contents of the resource being created
|
||||
* but should generally not make any
|
||||
* changes as storage has already occurred. Changes will not be reflected
|
||||
* in storage, but may be reflected in the HTTP response.
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource</li>
|
||||
* </ul>
|
||||
*/
|
||||
OP_PRECOMMIT_RESOURCE_CREATED("org.hl7.fhir.instance.model.api.IBaseResource"),
|
||||
|
||||
/**
|
||||
* Invoked before a resource will be created
|
||||
* <p>
|
||||
* Hooks will have access to the contents of the resource being deleted
|
||||
* but should not make any changes as storage has already occurred
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource</li>
|
||||
* </ul>
|
||||
*/
|
||||
OP_PRECOMMIT_RESOURCE_DELETED("org.hl7.fhir.instance.model.api.IBaseResource"),
|
||||
|
||||
/**
|
||||
* Invoked before a resource will be updated, immediately before the transaction
|
||||
* is committed (after all validation and other business rules have successfully
|
||||
* completed, and any other database activity is complete.
|
||||
* <p>
|
||||
* Hooks will have access to the contents of the resource being updated
|
||||
* (both the previous and new contents) but should generally not make any
|
||||
* changes as storage has already occurred. Changes will not be reflected
|
||||
* in storage, but may be reflected in the HTTP response.
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource (previous contents)</li>
|
||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource (new contents)</li>
|
||||
* </ul>
|
||||
*/
|
||||
OP_PRECOMMIT_RESOURCE_UPDATED("org.hl7.fhir.instance.model.api.IBaseResource", "org.hl7.fhir.instance.model.api.IBaseResource"),
|
||||
|
||||
/**
|
||||
* Invoked before a resource will be updated, immediately before the resource
|
||||
* is persisted to the database.
|
||||
* <p>
|
||||
* Hooks will have access to the contents of the resource being updated
|
||||
* (both the previous and new contents) and may choose to make modifications
|
||||
* to the new contents of the resource. These changes will be reflected in
|
||||
* permanent storage.
|
||||
* </p>
|
||||
* Hooks may accept the following parameters:
|
||||
* <ul>
|
||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource (previous contents)</li>
|
||||
* <li>org.hl7.fhir.instance.model.api.IBaseResource (new contents)</li>
|
||||
* </ul>
|
||||
*/
|
||||
OP_PRESTORAGE_RESOURCE_UPDATED("org.hl7.fhir.instance.model.api.IBaseResource", "org.hl7.fhir.instance.model.api.IBaseResource"),
|
||||
|
||||
;
|
||||
|
||||
private final List<String> myParameterTypes;
|
||||
|
||||
Pointcut(String... theParameterTypes) {
|
||||
myParameterTypes = Collections.unmodifiableList(Arrays.asList(theParameterTypes));
|
||||
}
|
||||
|
||||
public List<String> getParameterTypes() {
|
||||
return myParameterTypes;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,372 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.executor;
|
||||
|
||||
/*-
|
||||
* #%L
|
||||
* HAPI FHIR Model
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2019 University Health Network
|
||||
* %%
|
||||
* 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.interceptor.api.*;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ArrayListMultimap;
|
||||
import com.google.common.collect.ListMultimap;
|
||||
import org.apache.commons.collections4.ListUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Nonnull;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Component
|
||||
public class InterceptorService implements IInterceptorRegistry, IInterceptorBroadcaster {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(InterceptorService.class);
|
||||
private final List<Object> myInterceptors = new ArrayList<>();
|
||||
private final ListMultimap<Pointcut, BaseInvoker> myInvokers = ArrayListMultimap.create();
|
||||
private final ListMultimap<Pointcut, BaseInvoker> myAnonymousInvokers = ArrayListMultimap.create();
|
||||
private final Object myRegistryMutex = new Object();
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public InterceptorService() {
|
||||
super();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<Object> getGlobalInterceptorsForUnitTest() {
|
||||
return myInterceptors;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@VisibleForTesting
|
||||
public void registerAnonymousHookForUnitTest(Pointcut thePointcut, IAnonymousLambdaHook theHook) {
|
||||
registerAnonymousHookForUnitTest(thePointcut, DEFAULT_ORDER, theHook);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerAnonymousHookForUnitTest(Pointcut thePointcut, int theOrder, IAnonymousLambdaHook theHook) {
|
||||
Validate.notNull(thePointcut);
|
||||
Validate.notNull(theHook);
|
||||
|
||||
myAnonymousInvokers.put(thePointcut, new AnonymousLambdaInvoker(theHook, theOrder));
|
||||
}
|
||||
|
||||
@Override
|
||||
@VisibleForTesting
|
||||
public void clearAnonymousHookForUnitTest() {
|
||||
myAnonymousInvokers.clear();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerInterceptor(Object theInterceptor) {
|
||||
synchronized (myRegistryMutex) {
|
||||
|
||||
if (isInterceptorAlreadyRegistered(theInterceptor)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Class<?> interceptorClass = theInterceptor.getClass();
|
||||
int typeOrder = determineOrder(interceptorClass);
|
||||
|
||||
if (!scanInterceptorForHookMethodsAndAddThem(theInterceptor, typeOrder)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
myInterceptors.add(theInterceptor);
|
||||
|
||||
// Make sure we're always sorted according to the order declared in
|
||||
// @Order
|
||||
sortByOrderAnnotation(myInterceptors);
|
||||
for (Pointcut nextPointcut : myInvokers.keys()) {
|
||||
List<BaseInvoker> nextInvokerList = myInvokers.get(nextPointcut);
|
||||
nextInvokerList.sort(Comparator.naturalOrder());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean scanInterceptorForHookMethodsAndAddThem(Object theInterceptor, int theTypeOrder) {
|
||||
boolean retVal = false;
|
||||
for (Method nextMethod : theInterceptor.getClass().getDeclaredMethods()) {
|
||||
Hook hook = AnnotationUtils.findAnnotation(nextMethod, Hook.class);
|
||||
|
||||
if (hook != null) {
|
||||
|
||||
int methodOrder = theTypeOrder;
|
||||
Order methodOrderAnnotation = AnnotationUtils.findAnnotation(nextMethod, Order.class);
|
||||
if (methodOrderAnnotation != null) {
|
||||
methodOrder = methodOrderAnnotation.value();
|
||||
}
|
||||
|
||||
HookInvoker invoker = new HookInvoker(hook, theInterceptor, nextMethod, methodOrder);
|
||||
for (Pointcut nextPointcut : hook.value()) {
|
||||
myInvokers.put(nextPointcut, invoker);
|
||||
}
|
||||
|
||||
retVal = true;
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private int determineOrder(Class<?> theInterceptorClass) {
|
||||
int typeOrder = DEFAULT_ORDER;
|
||||
Order typeOrderAnnotation = AnnotationUtils.findAnnotation(theInterceptorClass, Order.class);
|
||||
if (typeOrderAnnotation != null) {
|
||||
typeOrder = typeOrderAnnotation.value();
|
||||
}
|
||||
return typeOrder;
|
||||
}
|
||||
|
||||
private boolean isInterceptorAlreadyRegistered(Object theInterceptor) {
|
||||
for (Object next : myInterceptors) {
|
||||
if (next == theInterceptor) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterInterceptor(Object theInterceptor) {
|
||||
synchronized (myRegistryMutex) {
|
||||
myInterceptors.removeIf(t -> t == theInterceptor);
|
||||
myInvokers.entries().removeIf(t -> t.getValue().getInterceptor() == theInterceptor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean registerGlobalInterceptor(Object theInterceptor) {
|
||||
return registerInterceptor(theInterceptor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterGlobalInterceptor(Object theInterceptor) {
|
||||
unregisterInterceptor(theInterceptor);
|
||||
}
|
||||
|
||||
private void sortByOrderAnnotation(List<Object> theObjects) {
|
||||
IdentityHashMap<Object, Integer> interceptorToOrder = new IdentityHashMap<>();
|
||||
for (Object next : theObjects) {
|
||||
Order orderAnnotation = next.getClass().getAnnotation(Order.class);
|
||||
int order = orderAnnotation != null ? orderAnnotation.value() : 0;
|
||||
interceptorToOrder.put(next, order);
|
||||
}
|
||||
|
||||
theObjects.sort((a, b) -> {
|
||||
Integer orderA = interceptorToOrder.get(a);
|
||||
Integer orderB = interceptorToOrder.get(b);
|
||||
return orderA - orderB;
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callHooks(Pointcut thePointcut, Object... theParams) {
|
||||
return callHooks(thePointcut, new HookParams(theParams));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean callHooks(Pointcut thePointcut, HookParams theParams) {
|
||||
assert haveAppropriateParams(thePointcut, theParams);
|
||||
|
||||
List<BaseInvoker> invokers = getInvokersForPointcut(thePointcut);
|
||||
|
||||
/*
|
||||
* Call each hook in order
|
||||
*/
|
||||
for (BaseInvoker nextInvoker : invokers) {
|
||||
boolean shouldContinue = nextInvoker.invoke(theParams);
|
||||
if (!shouldContinue) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
List<Object> getInterceptorsWithInvokersForPointcut(Pointcut thePointcut) {
|
||||
return getInvokersForPointcut(thePointcut)
|
||||
.stream()
|
||||
.map(BaseInvoker::getInterceptor)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an ordered list of invokers for the given pointcut. Note that
|
||||
* a new and stable list is returned to.. do whatever you want with it.
|
||||
*/
|
||||
private List<BaseInvoker> getInvokersForPointcut(Pointcut thePointcut) {
|
||||
List<BaseInvoker> invokers;
|
||||
boolean haveAnonymousInvokers;
|
||||
synchronized (myRegistryMutex) {
|
||||
List<BaseInvoker> globalInvokers = myInvokers.get(thePointcut);
|
||||
List<BaseInvoker> anonymousInvokers = myAnonymousInvokers.get(thePointcut);
|
||||
invokers = ListUtils.union(anonymousInvokers, globalInvokers);
|
||||
haveAnonymousInvokers = anonymousInvokers.isEmpty() == false;
|
||||
}
|
||||
|
||||
if (haveAnonymousInvokers) {
|
||||
invokers.sort(Comparator.naturalOrder());
|
||||
}
|
||||
return invokers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Only call this when assertions are enabled, it's expensive
|
||||
*/
|
||||
boolean haveAppropriateParams(Pointcut thePointcut, HookParams theParams) {
|
||||
Validate.isTrue(theParams.getParamsForType().values().size() == thePointcut.getParameterTypes().size(), "Wrong number of params for pointcut %s - Wanted %s but found %s", thePointcut.name(), toErrorString(thePointcut.getParameterTypes()), theParams.getParamsForType().values().stream().map(t -> t.getClass().getSimpleName()).sorted().collect(Collectors.toList()));
|
||||
|
||||
List<String> wantedTypes = new ArrayList<>(thePointcut.getParameterTypes());
|
||||
|
||||
ListMultimap<Class<?>, Object> givenTypes = theParams.getParamsForType();
|
||||
for (Class<?> nextTypeClass : givenTypes.keySet()) {
|
||||
String nextTypeName = nextTypeClass.getName();
|
||||
for (Object nextParamValue : givenTypes.get(nextTypeClass)) {
|
||||
Validate.isTrue(nextTypeClass.isAssignableFrom(nextParamValue.getClass()), "Invalid params for pointcut %s - %s is not of type %s", thePointcut.name(), nextParamValue.getClass(), nextTypeClass);
|
||||
Validate.isTrue(wantedTypes.remove(nextTypeName), "Invalid params for pointcut %s - Wanted %s but missing %s", thePointcut.name(), toErrorString(thePointcut.getParameterTypes()), nextTypeName);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private abstract class BaseInvoker implements Comparable<BaseInvoker> {
|
||||
|
||||
private final int myOrder;
|
||||
private final Object myInterceptor;
|
||||
|
||||
BaseInvoker(Object theInterceptor, int theOrder) {
|
||||
myInterceptor = theInterceptor;
|
||||
myOrder = theOrder;
|
||||
}
|
||||
|
||||
public Object getInterceptor() {
|
||||
return myInterceptor;
|
||||
}
|
||||
|
||||
abstract boolean invoke(HookParams theParams);
|
||||
|
||||
@Override
|
||||
public int compareTo(BaseInvoker o) {
|
||||
return myOrder - o.myOrder;
|
||||
}
|
||||
}
|
||||
|
||||
private class AnonymousLambdaInvoker extends BaseInvoker {
|
||||
private final IAnonymousLambdaHook myHook;
|
||||
|
||||
public AnonymousLambdaInvoker(IAnonymousLambdaHook theHook, int theOrder) {
|
||||
super(theHook, theOrder);
|
||||
myHook = theHook;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean invoke(HookParams theParams) {
|
||||
myHook.invoke(theParams);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private class HookInvoker extends BaseInvoker {
|
||||
|
||||
private final boolean myReturnsBoolean;
|
||||
private final Method myMethod;
|
||||
private final Class<?>[] myParameterTypes;
|
||||
private final int[] myParameterIndexes;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
private HookInvoker(Hook theHook, @Nonnull Object theInterceptor, @Nonnull Method theHookMethod, int theOrder) {
|
||||
super(theInterceptor, theOrder);
|
||||
myParameterTypes = theHookMethod.getParameterTypes();
|
||||
myMethod = theHookMethod;
|
||||
|
||||
Class<?> returnType = theHookMethod.getReturnType();
|
||||
if (returnType.equals(boolean.class)) {
|
||||
myReturnsBoolean = true;
|
||||
} else {
|
||||
Validate.isTrue(void.class.equals(returnType), "Method does not return boolean or void: %s", theHookMethod);
|
||||
myReturnsBoolean = false;
|
||||
}
|
||||
|
||||
myParameterIndexes = new int[myParameterTypes.length];
|
||||
Map<Class<?>, AtomicInteger> typeToCount = new HashMap<>();
|
||||
for (int i = 0; i < myParameterTypes.length; i++) {
|
||||
AtomicInteger counter = typeToCount.computeIfAbsent(myParameterTypes[i], t -> new AtomicInteger(0));
|
||||
myParameterIndexes[i] = counter.getAndIncrement();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Returns true/false if the hook method returns a boolean, returns true otherwise
|
||||
*/
|
||||
@Override
|
||||
boolean invoke(HookParams theParams) {
|
||||
|
||||
Object[] args = new Object[myParameterTypes.length];
|
||||
for (int i = 0; i < myParameterTypes.length; i++) {
|
||||
Class<?> nextParamType = myParameterTypes[i];
|
||||
int nextParamIndex = myParameterIndexes[i];
|
||||
Object nextParamValue = theParams.get(nextParamType, nextParamIndex);
|
||||
args[i] = nextParamValue;
|
||||
}
|
||||
|
||||
// Invoke the method
|
||||
try {
|
||||
Object returnValue = myMethod.invoke(getInterceptor(), args);
|
||||
if (myReturnsBoolean) {
|
||||
return (boolean) returnValue;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
} catch (InvocationTargetException e) {
|
||||
Throwable targetException = e.getTargetException();
|
||||
if (targetException instanceof RuntimeException) {
|
||||
throw ((RuntimeException) targetException);
|
||||
} else {
|
||||
throw new InternalErrorException(targetException);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static String toErrorString(List<String> theParameterTypes) {
|
||||
return theParameterTypes
|
||||
.stream()
|
||||
.sorted()
|
||||
.collect(Collectors.joining(","));
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,268 @@
|
|||
package ca.uhn.fhir.jpa.model.interceptor.executor;
|
||||
|
||||
import ca.uhn.fhir.jpa.model.interceptor.api.*;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.Patient;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.ComponentScan;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.hamcrest.Matchers.contains;
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(classes = {InterceptorServiceTest.InterceptorRegistryTestCtxConfig.class})
|
||||
public class InterceptorServiceTest {
|
||||
|
||||
private static boolean ourNext_beforeRestHookDelivery_Return1;
|
||||
private static List<String> ourInvocations = new ArrayList<>();
|
||||
private static IBaseResource ourLastResourceOne;
|
||||
private static IBaseResource ourLastResourceTwoA;
|
||||
private static IBaseResource ourLastResourceTwoB;
|
||||
|
||||
@Autowired
|
||||
private InterceptorService myInterceptorRegistry;
|
||||
|
||||
@Autowired
|
||||
private MyTestInterceptorOne myInterceptorOne;
|
||||
@Autowired
|
||||
private MyTestInterceptorTwo myInterceptorTwo;
|
||||
@Autowired
|
||||
private MyTestInterceptorManual myInterceptorManual;
|
||||
|
||||
@Test
|
||||
public void testGlobalInterceptorsAreFound() {
|
||||
List<Object> globalInterceptors = myInterceptorRegistry.getGlobalInterceptorsForUnitTest();
|
||||
assertEquals(2, globalInterceptors.size());
|
||||
assertTrue(globalInterceptors.get(0).getClass().toString(), globalInterceptors.get(0) instanceof MyTestInterceptorOne);
|
||||
assertTrue(globalInterceptors.get(1).getClass().toString(), globalInterceptors.get(1) instanceof MyTestInterceptorTwo);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testManuallyRegisterGlobalInterceptor() {
|
||||
|
||||
// Register the manual interceptor (has @Order right in the middle)
|
||||
myInterceptorRegistry.registerInterceptor(myInterceptorManual);
|
||||
List<Object> globalInterceptors = myInterceptorRegistry.getGlobalInterceptorsForUnitTest();
|
||||
assertEquals(3, globalInterceptors.size());
|
||||
assertTrue(globalInterceptors.get(0).getClass().toString(), globalInterceptors.get(0) instanceof MyTestInterceptorOne);
|
||||
assertTrue(globalInterceptors.get(1).getClass().toString(), globalInterceptors.get(1) instanceof MyTestInterceptorManual);
|
||||
assertTrue(globalInterceptors.get(2).getClass().toString(), globalInterceptors.get(2) instanceof MyTestInterceptorTwo);
|
||||
|
||||
// Try to register again (should have no effect
|
||||
myInterceptorRegistry.registerInterceptor(myInterceptorManual);
|
||||
globalInterceptors = myInterceptorRegistry.getGlobalInterceptorsForUnitTest();
|
||||
assertEquals(3, globalInterceptors.size());
|
||||
assertTrue(globalInterceptors.get(0).getClass().toString(), globalInterceptors.get(0) instanceof MyTestInterceptorOne);
|
||||
assertTrue(globalInterceptors.get(1).getClass().toString(), globalInterceptors.get(1) instanceof MyTestInterceptorManual);
|
||||
assertTrue(globalInterceptors.get(2).getClass().toString(), globalInterceptors.get(2) instanceof MyTestInterceptorTwo);
|
||||
|
||||
// Make sure we have the right invokers in the right order
|
||||
List<Object> invokers = myInterceptorRegistry.getInterceptorsWithInvokersForPointcut(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED);
|
||||
assertSame(myInterceptorOne, invokers.get(0));
|
||||
assertSame(myInterceptorManual, invokers.get(1));
|
||||
assertSame(myInterceptorTwo, invokers.get(2));
|
||||
|
||||
// Finally, unregister it
|
||||
myInterceptorRegistry.unregisterInterceptor(myInterceptorManual);
|
||||
globalInterceptors = myInterceptorRegistry.getGlobalInterceptorsForUnitTest();
|
||||
assertEquals(2, globalInterceptors.size());
|
||||
assertTrue(globalInterceptors.get(0).getClass().toString(), globalInterceptors.get(0) instanceof MyTestInterceptorOne);
|
||||
assertTrue(globalInterceptors.get(1).getClass().toString(), globalInterceptors.get(1) instanceof MyTestInterceptorTwo);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeGlobalInterceptorMethods() {
|
||||
Patient patient = new Patient();
|
||||
HookParams params = new HookParams()
|
||||
.add(IBaseResource.class, patient);
|
||||
boolean outcome = myInterceptorRegistry.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED, params);
|
||||
assertTrue(outcome);
|
||||
|
||||
assertThat(ourInvocations, contains("MyTestInterceptorOne.beforeRestHookDelivery", "MyTestInterceptorTwo.beforeRestHookDelivery"));
|
||||
assertSame(patient, ourLastResourceTwoA);
|
||||
assertNull(ourLastResourceTwoB);
|
||||
assertSame(patient, ourLastResourceOne);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInvokeGlobalInterceptorMethods_MethodAbortsProcessing() {
|
||||
ourNext_beforeRestHookDelivery_Return1 = false;
|
||||
|
||||
Patient patient = new Patient();
|
||||
HookParams params = new HookParams()
|
||||
.add(IBaseResource.class, patient);
|
||||
boolean outcome = myInterceptorRegistry.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED, params);
|
||||
assertFalse(outcome);
|
||||
|
||||
assertThat(ourInvocations, contains("MyTestInterceptorOne.beforeRestHookDelivery"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCallHooksInvokedWithWrongParameters() {
|
||||
Integer msg = 123;
|
||||
CanonicalSubscription subs = new CanonicalSubscription();
|
||||
HookParams params = new HookParams(msg, subs);
|
||||
try {
|
||||
myInterceptorRegistry.callHooks(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED, params);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Wrong number of params for pointcut OP_PRECOMMIT_RESOURCE_CREATED - Wanted org.hl7.fhir.instance.model.api.IBaseResource but found [CanonicalSubscription, Integer]", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateParamTypes() {
|
||||
HookParams params = new HookParams();
|
||||
params.add(IBaseResource.class, new Patient());
|
||||
params.add(IBaseResource.class, new Patient());
|
||||
boolean validated = myInterceptorRegistry.haveAppropriateParams(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, params);
|
||||
assertTrue(validated);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateParamTypesMissingParam() {
|
||||
HookParams params = new HookParams();
|
||||
params.add(IBaseResource.class, new Patient());
|
||||
try {
|
||||
myInterceptorRegistry.haveAppropriateParams(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, params);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Wrong number of params for pointcut OP_PRECOMMIT_RESOURCE_UPDATED - Wanted org.hl7.fhir.instance.model.api.IBaseResource,org.hl7.fhir.instance.model.api.IBaseResource but found [Patient]", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testValidateParamTypesExtraParam() {
|
||||
HookParams params = new HookParams();
|
||||
params.add(IBaseResource.class, new Patient());
|
||||
params.add(IBaseResource.class, new Patient());
|
||||
params.add(IBaseResource.class, new Patient());
|
||||
try {
|
||||
myInterceptorRegistry.haveAppropriateParams(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, params);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Wrong number of params for pointcut OP_PRECOMMIT_RESOURCE_UPDATED - Wanted org.hl7.fhir.instance.model.api.IBaseResource,org.hl7.fhir.instance.model.api.IBaseResource but found [Patient, Patient, Patient]", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void testValidateParamTypesWrongParam() {
|
||||
HookParams params = new HookParams();
|
||||
Class clazz = IBaseResource.class;
|
||||
params.add(clazz, "AAA");
|
||||
params.add(clazz, "BBB");
|
||||
try {
|
||||
myInterceptorRegistry.haveAppropriateParams(Pointcut.OP_PRECOMMIT_RESOURCE_UPDATED, params);
|
||||
fail();
|
||||
} catch (IllegalArgumentException e) {
|
||||
assertEquals("Invalid params for pointcut OP_PRECOMMIT_RESOURCE_UPDATED - class java.lang.String is not of type interface org.hl7.fhir.instance.model.api.IBaseResource", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
ourNext_beforeRestHookDelivery_Return1 = true;
|
||||
ourLastResourceOne = null;
|
||||
ourLastResourceTwoA = null;
|
||||
ourLastResourceTwoB = null;
|
||||
ourInvocations.clear();
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@ComponentScan(basePackages = "ca.uhn.fhir.jpa.model")
|
||||
static class InterceptorRegistryTestCtxConfig {
|
||||
|
||||
@Autowired
|
||||
private IInterceptorRegistry myInterceptorRegistry;
|
||||
|
||||
/**
|
||||
* Note: Orders are deliberately reversed to make sure we get the orders right
|
||||
* using the @Order annotation
|
||||
*/
|
||||
@Bean
|
||||
public MyTestInterceptorTwo interceptor1() {
|
||||
MyTestInterceptorTwo retVal = new MyTestInterceptorTwo();
|
||||
myInterceptorRegistry.registerInterceptor(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* Note: Orders are deliberately reversed to make sure we get the orders right
|
||||
* using the @Order annotation
|
||||
*/
|
||||
@Bean
|
||||
public MyTestInterceptorOne interceptor2() {
|
||||
MyTestInterceptorOne retVal = new MyTestInterceptorOne();
|
||||
myInterceptorRegistry.registerInterceptor(retVal);
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyTestInterceptorManual interceptorManual() {
|
||||
return new MyTestInterceptorManual();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Interceptor
|
||||
@Order(100)
|
||||
public static class MyTestInterceptorOne {
|
||||
|
||||
public MyTestInterceptorOne() {
|
||||
super();
|
||||
}
|
||||
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED)
|
||||
public boolean beforeRestHookDelivery(IBaseResource theResource) {
|
||||
ourLastResourceOne = theResource;
|
||||
ourInvocations.add("MyTestInterceptorOne.beforeRestHookDelivery");
|
||||
return ourNext_beforeRestHookDelivery_Return1;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Interceptor
|
||||
@Order(300)
|
||||
public static class MyTestInterceptorTwo {
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED)
|
||||
public void beforeRestHookDelivery(IBaseResource theResource0, IBaseResource theResource1) {
|
||||
ourLastResourceTwoA = theResource0;
|
||||
ourLastResourceTwoB = theResource1;
|
||||
ourInvocations.add("MyTestInterceptorTwo.beforeRestHookDelivery");
|
||||
}
|
||||
}
|
||||
|
||||
@Interceptor(manualRegistration = true)
|
||||
@Order(200)
|
||||
public static class MyTestInterceptorManual {
|
||||
@Hook(Pointcut.OP_PRECOMMIT_RESOURCE_CREATED)
|
||||
public void beforeRestHookDelivery() {
|
||||
ourInvocations.add("MyTestInterceptorManual.beforeRestHookDelivery");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Just a make-believe version of this class for the unit test
|
||||
*/
|
||||
private static class CanonicalSubscription {
|
||||
}
|
||||
|
||||
/**
|
||||
* Just a make-believe version of this class for the unit test
|
||||
*/
|
||||
private static class ResourceDeliveryMessage {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
<configuration>
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
<encoder>
|
||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
|
@ -87,36 +87,6 @@
|
|||
<artifactId>javax.annotation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Spring -->
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-beans</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework</groupId>
|
||||
<artifactId>spring-context</artifactId>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<artifactId>xml-apis</artifactId>
|
||||
<groupId>xml-apis</groupId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.fasterxml.jackson.core</groupId>
|
||||
<artifactId>jackson-annotations</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.jscience</groupId>
|
||||
<artifactId>jscience</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Java -->
|
||||
<dependency>
|
||||
<groupId>javax.annotation</groupId>
|
||||
<artifactId>javax.annotation-api</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Testing -->
|
||||
|
||||
<dependency>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue