Merge branch 'master' of github.com:jamesagnew/hapi-fhir
This commit is contained in:
commit
4b78fd8029
|
@ -35,6 +35,11 @@
|
|||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-r4</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
package example;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import org.hl7.fhir.r4.model.Enumerations;
|
||||
import org.hl7.fhir.r4.model.SearchParameter;
|
||||
|
||||
public class GenomicsUploader {
|
||||
|
||||
public static void main(String[] theArgs) {
|
||||
FhirContext ctx = FhirContext.forR4();
|
||||
IGenericClient client = ctx.newRestfulGenericClient("http://fhirtest.uhn.ca/baseR4");
|
||||
client.registerInterceptor(new LoggingInterceptor(false));
|
||||
|
||||
SearchParameter dnaSequenceVariantName = new SearchParameter();
|
||||
dnaSequenceVariantName.setId("SearchParameter/dnaSequenceVariantName");
|
||||
dnaSequenceVariantName.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
dnaSequenceVariantName.addBase("Observation");
|
||||
dnaSequenceVariantName.setCode("dnaSequenceVariantName");
|
||||
dnaSequenceVariantName.setType(Enumerations.SearchParamType.TOKEN);
|
||||
dnaSequenceVariantName.setTitle("DNASequenceVariantName");
|
||||
dnaSequenceVariantName.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsDNASequenceVariantName')");
|
||||
dnaSequenceVariantName.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
client.update().resource(dnaSequenceVariantName).execute();
|
||||
|
||||
SearchParameter dNAVariantId = new SearchParameter();
|
||||
dNAVariantId.setId("SearchParameter/dNAVariantId");
|
||||
dNAVariantId.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
dNAVariantId.addBase("Observation");
|
||||
dNAVariantId.setCode("dnaVariantId");
|
||||
dNAVariantId.setType(Enumerations.SearchParamType.TOKEN);
|
||||
dNAVariantId.setTitle("DNAVariantId");
|
||||
dNAVariantId.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsDNAVariantId')");
|
||||
dNAVariantId.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
client.update().resource(dNAVariantId).execute();
|
||||
|
||||
SearchParameter gene = new SearchParameter();
|
||||
gene.setId("SearchParameter/gene");
|
||||
gene.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
gene.addBase("Observation");
|
||||
gene.setCode("gene");
|
||||
gene.setType(Enumerations.SearchParamType.TOKEN);
|
||||
gene.setTitle("Gene");
|
||||
gene.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsGene')");
|
||||
gene.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
client.update().resource(gene).execute();
|
||||
|
||||
SearchParameter alleleName = new SearchParameter();
|
||||
alleleName.setId("SearchParameter/alleleName");
|
||||
alleleName.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
alleleName.addBase("Observation");
|
||||
alleleName.setCode("alleleName");
|
||||
alleleName.setType(Enumerations.SearchParamType.TOKEN);
|
||||
alleleName.setTitle("AlleleName");
|
||||
alleleName.setExpression("Observation.extension('http://hl7.org/fhir/StructureDefinition/observation-geneticsAlleleName')");
|
||||
alleleName.setXpathUsage(SearchParameter.XPathUsageType.NORMAL);
|
||||
client.update().resource(alleleName).execute();
|
||||
}
|
||||
|
||||
}
|
|
@ -214,6 +214,12 @@ public class ValidatorExamples {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
// TODO: implement
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
// TODO: implement
|
||||
|
|
|
@ -20,117 +20,113 @@ package ca.uhn.fhir.context.support;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.util.List;
|
||||
|
||||
public interface IContextValidationSupport<EVS_IN, EVS_OUT, SDT, CST, CDCT, IST> {
|
||||
|
||||
/**
|
||||
* Expands the given portion of a ValueSet
|
||||
*
|
||||
* @param theInclude
|
||||
* The portion to include
|
||||
* @return The expansion
|
||||
*/
|
||||
EVS_OUT expandValueSet(FhirContext theContext, EVS_IN theInclude);
|
||||
/**
|
||||
* Expands the given portion of a ValueSet
|
||||
*
|
||||
* @param theInclude The portion to include
|
||||
* @return The expansion
|
||||
*/
|
||||
EVS_OUT expandValueSet(FhirContext theContext, EVS_IN theInclude);
|
||||
|
||||
/**
|
||||
* Load and return all possible structure definitions
|
||||
*/
|
||||
List<SDT> fetchAllStructureDefinitions(FhirContext theContext);
|
||||
/**
|
||||
* Load and return all conformance resources associated with this
|
||||
* validation support module. This method may return null if it doesn't
|
||||
* make sense for a given module.
|
||||
*/
|
||||
List<IBaseResource> fetchAllConformanceResources(FhirContext theContext);
|
||||
|
||||
/**
|
||||
* Load and return all possible structure definitions
|
||||
*/
|
||||
List<SDT> fetchAllStructureDefinitions(FhirContext theContext);
|
||||
|
||||
/**
|
||||
* Fetch a code system by ID
|
||||
*
|
||||
* @param theSystem
|
||||
* The code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
CST fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||
/**
|
||||
* Fetch a code system by ID
|
||||
*
|
||||
* @param theSystem The code system
|
||||
* @return The valueset (must not be null, but can be an empty ValueSet)
|
||||
*/
|
||||
CST fetchCodeSystem(FhirContext theContext, String theSystem);
|
||||
|
||||
/**
|
||||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||
* ValueSet)
|
||||
*
|
||||
* @param theContext
|
||||
* The HAPI FHIR Context object current in use by the validator
|
||||
* @param theClass
|
||||
* The type of the resource to load
|
||||
* @param theUri
|
||||
* The resource URI
|
||||
* @return Returns the resource, or <code>null</code> if no resource with the
|
||||
* given URI can be found
|
||||
*/
|
||||
<T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri);
|
||||
/**
|
||||
* Loads a resource needed by the validation (a StructureDefinition, or a
|
||||
* ValueSet)
|
||||
*
|
||||
* @param theContext The HAPI FHIR Context object current in use by the validator
|
||||
* @param theClass The type of the resource to load
|
||||
* @param theUri The resource URI
|
||||
* @return Returns the resource, or <code>null</code> if no resource with the
|
||||
* given URI can be found
|
||||
*/
|
||||
<T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri);
|
||||
|
||||
SDT fetchStructureDefinition(FhirContext theCtx, String theUrl);
|
||||
SDT fetchStructureDefinition(FhirContext theCtx, String theUrl);
|
||||
|
||||
/**
|
||||
* Returns <code>true</code> if codes in the given code system can be expanded
|
||||
* or validated
|
||||
*
|
||||
* @param theSystem
|
||||
* The URI for the code system, e.g. <code>"http://loinc.org"</code>
|
||||
* @return Returns <code>true</code> if codes in the given code system can be
|
||||
* validated
|
||||
*/
|
||||
boolean isCodeSystemSupported(FhirContext theContext, String theSystem);
|
||||
/**
|
||||
* Returns <code>true</code> if codes in the given code system can be expanded
|
||||
* or validated
|
||||
*
|
||||
* @param theSystem The URI for the code system, e.g. <code>"http://loinc.org"</code>
|
||||
* @return Returns <code>true</code> if codes in the given code system can be
|
||||
* validated
|
||||
*/
|
||||
boolean isCodeSystemSupported(FhirContext theContext, String theSystem);
|
||||
|
||||
/**
|
||||
* Validates that the given code exists and if possible returns a display
|
||||
* name. This method is called to check codes which are found in "example"
|
||||
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||
*
|
||||
* @param theCodeSystem
|
||||
* The code system, e.g. "<code>http://loinc.org</code>"
|
||||
* @param theCode
|
||||
* The code, e.g. "<code>1234-5</code>"
|
||||
* @param theDisplay
|
||||
* The display name, if it should also be validated
|
||||
* @return Returns a validation result object
|
||||
*/
|
||||
CodeValidationResult<CDCT, IST> validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
|
||||
/**
|
||||
* Validates that the given code exists and if possible returns a display
|
||||
* name. This method is called to check codes which are found in "example"
|
||||
* binding fields (e.g. <code>Observation.code</code> in the default profile.
|
||||
*
|
||||
* @param theCodeSystem The code system, e.g. "<code>http://loinc.org</code>"
|
||||
* @param theCode The code, e.g. "<code>1234-5</code>"
|
||||
* @param theDisplay The display name, if it should also be validated
|
||||
* @return Returns a validation result object
|
||||
*/
|
||||
CodeValidationResult<CDCT, IST> validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay);
|
||||
|
||||
public class CodeValidationResult<CDCT, IST> {
|
||||
private CDCT definition;
|
||||
private String message;
|
||||
private IST severity;
|
||||
private CDCT definition;
|
||||
private String message;
|
||||
private IST severity;
|
||||
|
||||
public CodeValidationResult(CDCT theNext) {
|
||||
this.definition = theNext;
|
||||
}
|
||||
public CodeValidationResult(CDCT theNext) {
|
||||
this.definition = theNext;
|
||||
}
|
||||
|
||||
public CodeValidationResult(IST severity, String message) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
}
|
||||
public CodeValidationResult(IST severity, String message) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
}
|
||||
|
||||
public CodeValidationResult(IST severity, String message, CDCT definition) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
this.definition = definition;
|
||||
}
|
||||
public CodeValidationResult(IST severity, String message, CDCT definition) {
|
||||
this.severity = severity;
|
||||
this.message = message;
|
||||
this.definition = definition;
|
||||
}
|
||||
|
||||
public CDCT asConceptDefinition() {
|
||||
return definition;
|
||||
}
|
||||
public CDCT asConceptDefinition() {
|
||||
return definition;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public IST getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
public IST getSeverity() {
|
||||
return severity;
|
||||
}
|
||||
|
||||
public boolean isOk() {
|
||||
return definition != null;
|
||||
}
|
||||
public boolean isOk() {
|
||||
return definition != null;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -73,6 +73,11 @@
|
|||
<artifactId>hapi-fhir-validation-resources-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-igpacks</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
|
|
|
@ -41,6 +41,7 @@ public class App {
|
|||
ourCommands.add(new ValidationDataUploader());
|
||||
ourCommands.add(new WebsocketSubscribeCommand());
|
||||
ourCommands.add(new UploadTerminologyCommand());
|
||||
ourCommands.add(new IgPackUploader());
|
||||
|
||||
Collections.sort(ourCommands);
|
||||
}
|
||||
|
|
|
@ -1,53 +1,99 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import org.apache.commons.cli.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.impl.client.CloseableHttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.fusesource.jansi.Ansi;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public abstract class BaseCommand implements Comparable<BaseCommand> {
|
||||
|
||||
private static final String SPEC_DEFAULT_VERSION = "dstu3";
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(BaseCommand.class);
|
||||
private FhirContext myFhirCtx;
|
||||
|
||||
public BaseCommand() {
|
||||
super();
|
||||
}
|
||||
|
||||
protected void addFhirVersionOption(Options theOptions) {
|
||||
Option opt = new Option("f", "fhirversion", true, "Spec version to upload (default is '" + SPEC_DEFAULT_VERSION + "')");
|
||||
opt.setRequired(false);
|
||||
theOptions.addOption(opt);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(BaseCommand theO) {
|
||||
return getCommandName().compareTo(theO.getCommandName());
|
||||
}
|
||||
|
||||
private void downloadFileFromInternet(CloseableHttpResponse result, File localFile) throws IOException {
|
||||
FileOutputStream buffer = FileUtils.openOutputStream(localFile);
|
||||
try {
|
||||
|
||||
long maxLength = result.getEntity().getContentLength();
|
||||
long nextLog = -1;
|
||||
// ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
while ((nRead = result.getEntity().getContent().read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
long fileSize = FileUtils.sizeOf(localFile);
|
||||
if (fileSize > nextLog) {
|
||||
System.err.print("\r" + Ansi.ansi().eraseLine());
|
||||
System.err.print(FileUtils.byteCountToDisplaySize(fileSize));
|
||||
if (maxLength > 0) {
|
||||
System.err.print(" [");
|
||||
int stars = (int) (50.0f * ((float) fileSize / (float) maxLength));
|
||||
for (int i = 0; i < stars; i++) {
|
||||
System.err.print("*");
|
||||
}
|
||||
for (int i = stars; i < 50; i++) {
|
||||
System.err.print(" ");
|
||||
}
|
||||
System.err.print("]");
|
||||
}
|
||||
System.err.flush();
|
||||
nextLog += 100000;
|
||||
}
|
||||
}
|
||||
buffer.flush();
|
||||
|
||||
System.err.println();
|
||||
System.err.flush();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract String getCommandDescription();
|
||||
|
||||
public abstract String getCommandName();
|
||||
|
||||
public abstract Options getOptions();
|
||||
|
||||
protected IGenericClient newClient(FhirContext ctx, String theBaseUrl) {
|
||||
ctx.getRestfulClientFactory().setSocketTimeout(10 * 60 * 1000);
|
||||
IGenericClient fhirClient = ctx.newRestfulGenericClient(theBaseUrl);
|
||||
return fhirClient;
|
||||
}
|
||||
|
||||
public abstract void run(CommandLine theCommandLine) throws ParseException, Exception;
|
||||
|
||||
// public FhirContext getFhirCtx() {
|
||||
// if (myFhirCtx == null) {
|
||||
// myFhirCtx = FhirContext.forDstu2();
|
||||
// }
|
||||
// return myFhirCtx;
|
||||
// }
|
||||
|
||||
protected void addFhirVersionOption(Options theOptions) {
|
||||
Option opt = new Option("f", "fhirversion", true, "Spec version to upload (default is '" + SPEC_DEFAULT_VERSION + "')");
|
||||
opt.setRequired(false);
|
||||
theOptions.addOption(opt);
|
||||
}
|
||||
|
||||
protected FhirContext getSpecVersionContext(CommandLine theCommandLine) throws ParseException {
|
||||
if (myFhirCtx == null) {
|
||||
String specVersion = theCommandLine.getOptionValue("f", SPEC_DEFAULT_VERSION);
|
||||
|
@ -68,4 +114,82 @@ public abstract class BaseCommand implements Comparable<BaseCommand> {
|
|||
return myFhirCtx;
|
||||
}
|
||||
|
||||
// public FhirContext getFhirCtx() {
|
||||
// if (myFhirCtx == null) {
|
||||
// myFhirCtx = FhirContext.forDstu2();
|
||||
// }
|
||||
// return myFhirCtx;
|
||||
// }
|
||||
|
||||
protected Collection<File> loadFile(FhirContext theCtx, String theSpecUrl, String theFilepath, boolean theCacheFile) throws IOException {
|
||||
String userHomeDir = System.getProperty("user.home");
|
||||
|
||||
File applicationDir = new File(userHomeDir + File.separator + "." + "hapi-fhir-cli");
|
||||
FileUtils.forceMkdir(applicationDir);
|
||||
|
||||
Collection<File> inputFiles;
|
||||
if (isNotBlank(theFilepath)) {
|
||||
ourLog.info("Loading from local path: {}", theFilepath);
|
||||
|
||||
if (theFilepath.startsWith("~" + File.separator)) {
|
||||
theFilepath = userHomeDir + theFilepath.substring(1);
|
||||
}
|
||||
|
||||
File suppliedFile = new File(FilenameUtils.normalize(theFilepath));
|
||||
|
||||
if (suppliedFile.isDirectory()) {
|
||||
inputFiles = FileUtils.listFiles(suppliedFile, new String[]{"zip"}, false);
|
||||
} else {
|
||||
inputFiles = Collections.singletonList(suppliedFile);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
File cacheDir = new File(applicationDir, "cache");
|
||||
FileUtils.forceMkdir(cacheDir);
|
||||
|
||||
File inputFile = new File(cacheDir, "examples-json-" + theCtx.getVersion().getVersion() + ".zip");
|
||||
|
||||
Date cacheExpiryDate = DateUtils.addHours(new Date(), -12);
|
||||
|
||||
if (!inputFile.exists() | (theCacheFile && FileUtils.isFileOlder(inputFile, cacheExpiryDate))) {
|
||||
|
||||
File exampleFileDownloading = new File(cacheDir, "examples-json-" + theCtx.getVersion().getVersion() + ".zip.partial");
|
||||
|
||||
HttpGet get = new HttpGet(theSpecUrl);
|
||||
CloseableHttpClient client = HttpClientBuilder.create().build();
|
||||
CloseableHttpResponse result = client.execute(get);
|
||||
|
||||
if (result.getStatusLine().getStatusCode() != 200) {
|
||||
throw new CommandFailureException("Got HTTP " + result.getStatusLine().getStatusCode() + " response code loading " + theSpecUrl);
|
||||
}
|
||||
|
||||
ourLog.info("Downloading from remote url: {}", theSpecUrl);
|
||||
downloadFileFromInternet(result, exampleFileDownloading);
|
||||
|
||||
FileUtils.deleteQuietly(inputFile);
|
||||
FileUtils.moveFile(exampleFileDownloading, inputFile);
|
||||
|
||||
if (!theCacheFile) {
|
||||
inputFile.deleteOnExit();
|
||||
}
|
||||
|
||||
ourLog.info("Successfully Loaded example pack ({})", FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(inputFile)));
|
||||
IOUtils.closeQuietly(result.getEntity().getContent());
|
||||
}
|
||||
|
||||
inputFiles = Collections.singletonList(inputFile);
|
||||
|
||||
}
|
||||
return inputFiles;
|
||||
}
|
||||
|
||||
protected IGenericClient newClient(FhirContext ctx, String theBaseUrl) {
|
||||
ctx.getRestfulClientFactory().setSocketTimeout(10 * 60 * 1000);
|
||||
IGenericClient fhirClient = ctx.newRestfulGenericClient(theBaseUrl);
|
||||
return fhirClient;
|
||||
}
|
||||
|
||||
public abstract void run(CommandLine theCommandLine) throws ParseException, Exception;
|
||||
|
||||
}
|
||||
|
|
|
@ -127,79 +127,17 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
|
||||
boolean cacheFile = theCommandLine.hasOption('c');
|
||||
|
||||
String userHomeDir = System.getProperty("user.home");
|
||||
|
||||
File applicationDir = new File(userHomeDir + File.separator + "." + "hapi-fhir-cli");
|
||||
FileUtils.forceMkdir(applicationDir);
|
||||
|
||||
if (isNotBlank(filepath)) {
|
||||
ourLog.info("Loading from local path: {}", filepath);
|
||||
|
||||
if (filepath.startsWith("~" + File.separator)) {
|
||||
filepath = userHomeDir + filepath.substring(1);
|
||||
}
|
||||
|
||||
File suppliedFile = new File(FilenameUtils.normalize(filepath));
|
||||
|
||||
if (suppliedFile.isDirectory()) {
|
||||
Collection<File> inputFiles;
|
||||
inputFiles = FileUtils.listFiles(suppliedFile, new String[]{"zip"}, false);
|
||||
|
||||
for (File inputFile : inputFiles) {
|
||||
IBaseBundle bundle = getBundleFromFile(limit, inputFile, ctx);
|
||||
processBundle(ctx, bundle);
|
||||
sendBundleToTarget(targetServer, ctx, bundle);
|
||||
}
|
||||
} else {
|
||||
IBaseBundle bundle = getBundleFromFile(limit, suppliedFile, ctx);
|
||||
processBundle(ctx, bundle);
|
||||
sendBundleToTarget(targetServer, ctx, bundle);
|
||||
}
|
||||
|
||||
} else {
|
||||
|
||||
File cacheDir = new File(applicationDir, "cache");
|
||||
FileUtils.forceMkdir(cacheDir);
|
||||
|
||||
File inputFile = new File(cacheDir, "examples-json-" + ctx.getVersion().getVersion() + ".zip");
|
||||
|
||||
Date cacheExpiryDate = DateUtils.addHours(new Date(), -12);
|
||||
|
||||
if (!inputFile.exists() | (cacheFile && FileUtils.isFileOlder(inputFile, cacheExpiryDate))) {
|
||||
|
||||
File exampleFileDownloading = new File(cacheDir, "examples-json-" + ctx.getVersion().getVersion() + ".zip.partial");
|
||||
|
||||
HttpGet get = new HttpGet(specUrl);
|
||||
CloseableHttpClient client = HttpClientBuilder.create().build();
|
||||
CloseableHttpResponse result = client.execute(get);
|
||||
|
||||
if (result.getStatusLine().getStatusCode() != 200) {
|
||||
throw new CommandFailureException("Got HTTP " + result.getStatusLine().getStatusCode() + " response code loading " + specUrl);
|
||||
}
|
||||
|
||||
ourLog.info("Downloading from remote url: {}", specUrl);
|
||||
downloadFileFromInternet(result, exampleFileDownloading);
|
||||
|
||||
FileUtils.deleteQuietly(inputFile);
|
||||
FileUtils.moveFile(exampleFileDownloading, inputFile);
|
||||
|
||||
if (!cacheFile) {
|
||||
inputFile.deleteOnExit();
|
||||
}
|
||||
|
||||
ourLog.info("Successfully Loaded example pack ({})", FileUtils.byteCountToDisplaySize(FileUtils.sizeOf(inputFile)));
|
||||
IOUtils.closeQuietly(result.getEntity().getContent());
|
||||
}
|
||||
Collection<File> inputFiles = loadFile(ctx, specUrl, filepath, cacheFile);
|
||||
|
||||
for (File inputFile : inputFiles) {
|
||||
IBaseBundle bundle = getBundleFromFile(limit, inputFile, ctx);
|
||||
processBundle(ctx, bundle);
|
||||
|
||||
sendBundleToTarget(targetServer, ctx, bundle);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
private IBaseBundle getBundleFromFile(Integer theLimit, File theSuppliedFile, FhirContext theCtx) throws ParseException, IOException {
|
||||
switch (theCtx.getVersion().getVersion()) {
|
||||
case DSTU2:
|
||||
|
@ -791,43 +729,5 @@ public class ExampleDataUploader extends BaseCommand {
|
|||
return bundle;
|
||||
}
|
||||
|
||||
private void downloadFileFromInternet(CloseableHttpResponse result, File localFile) throws IOException {
|
||||
FileOutputStream buffer = FileUtils.openOutputStream(localFile);
|
||||
try {
|
||||
|
||||
long maxLength = result.getEntity().getContentLength();
|
||||
long nextLog = -1;
|
||||
// ByteArrayOutputStream buffer = new ByteArrayOutputStream();
|
||||
int nRead;
|
||||
byte[] data = new byte[16384];
|
||||
while ((nRead = result.getEntity().getContent().read(data, 0, data.length)) != -1) {
|
||||
buffer.write(data, 0, nRead);
|
||||
long fileSize = FileUtils.sizeOf(localFile);
|
||||
if (fileSize > nextLog) {
|
||||
System.err.print("\r" + Ansi.ansi().eraseLine());
|
||||
System.err.print(FileUtils.byteCountToDisplaySize(fileSize));
|
||||
if (maxLength > 0) {
|
||||
System.err.print(" [");
|
||||
int stars = (int) (50.0f * ((float) fileSize / (float) maxLength));
|
||||
for (int i = 0; i < stars; i++) {
|
||||
System.err.print("*");
|
||||
}
|
||||
for (int i = stars; i < 50; i++) {
|
||||
System.err.print(" ");
|
||||
}
|
||||
System.err.print("]");
|
||||
}
|
||||
System.err.flush();
|
||||
nextLog += 100000;
|
||||
}
|
||||
}
|
||||
buffer.flush();
|
||||
|
||||
System.err.println();
|
||||
System.err.flush();
|
||||
} finally {
|
||||
IOUtils.closeQuietly(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,82 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import org.apache.commons.cli.CommandLine;
|
||||
import org.apache.commons.cli.Option;
|
||||
import org.apache.commons.cli.Options;
|
||||
import org.apache.commons.cli.ParseException;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import parser.IgPackParserDstu3;
|
||||
import parser.IgPackValidationSupportDstu3;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.util.Collection;
|
||||
|
||||
public class IgPackUploader extends BaseCommand {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(IgPackUploader.class);
|
||||
|
||||
@Override
|
||||
public String getCommandDescription() {
|
||||
return "Uploads an Implementation Guide Validation Pack";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommandName() {
|
||||
return "upload-igpack";
|
||||
}
|
||||
|
||||
@Override
|
||||
public Options getOptions() {
|
||||
Options options = new Options();
|
||||
addFhirVersionOption(options);
|
||||
|
||||
Option opt = new Option("t", "target", true, "Base URL for the target server (e.g. \"http://example.com/fhir\")");
|
||||
opt.setRequired(false);
|
||||
options.addOption(opt);
|
||||
|
||||
opt = new Option("u", "url", true, "The URL to the validation.pack file, e.g. http://hl7.org/fhir/us/core/validator.pack");
|
||||
opt.setRequired(true);
|
||||
options.addOption(opt);
|
||||
|
||||
return options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run(CommandLine theCommandLine) throws ParseException, Exception {
|
||||
FhirContext ctx = getSpecVersionContext(theCommandLine);
|
||||
|
||||
String targetServer = theCommandLine.getOptionValue("t");
|
||||
IGenericClient client = ctx.newRestfulGenericClient(targetServer);
|
||||
|
||||
String url = theCommandLine.getOptionValue("u");
|
||||
|
||||
Collection<File> files = loadFile(ctx, url, null, false);
|
||||
for (File nextFile : files) {
|
||||
switch (ctx.getVersion().getVersion()) {
|
||||
case DSTU3:
|
||||
IgPackParserDstu3 packParser = new IgPackParserDstu3(ctx);
|
||||
IValidationSupport ig = packParser.parseIg(new FileInputStream(nextFile), nextFile.getName());
|
||||
Iterable<IBaseResource> conformanceResources = ig.fetchAllConformanceResources(ctx);
|
||||
for (IBaseResource nextResource : conformanceResources) {
|
||||
String nextResourceUrl = ((IPrimitiveType<?>)ctx.newTerser().getSingleValueOrNull(nextResource, "url")).getValueAsString();
|
||||
ourLog.info("Uploading resource: {}", nextResourceUrl);
|
||||
client
|
||||
.update()
|
||||
.resource(nextResource)
|
||||
.conditional()
|
||||
.and(StructureDefinition.URL.matches().value(nextResourceUrl))
|
||||
.execute();
|
||||
}
|
||||
default:
|
||||
throw new ParseException("This command does not support FHIR version " + ctx.getVersion().getVersion());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
|
@ -10,10 +11,8 @@ import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LoadingValidationSupportDstu3 implements IValidationSupport {
|
||||
|
||||
|
@ -26,6 +25,11 @@ public class LoadingValidationSupportDstu3 implements IValidationSupport {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
|
|
|
@ -1,30 +1,38 @@
|
|||
package ca.uhn.fhir.cli;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
public class LoadingValidationSupportR4 implements org.hl7.fhir.r4.hapi.ctx.IValidationSupport {
|
||||
|
||||
private FhirContext myCtx = FhirContext.forR4();
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(LoadingValidationSupportR4.class);
|
||||
private FhirContext myCtx = FhirContext.forR4();
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return null;
|
||||
|
@ -63,9 +71,4 @@ public class LoadingValidationSupportR4 implements org.hl7.fhir.r4.hapi.ctx.IVal
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
import org.junit.Test;
|
||||
|
||||
public class InstallIgPackTest {
|
||||
|
||||
@Test
|
||||
public void testInstallIgPack() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -13,12 +13,9 @@ public class ValidateTest {
|
|||
|
||||
@Test
|
||||
public void testValidateLocalProfile() {
|
||||
// String profilePath = ValidateTest.class.getResource("/uslab-patient.profile.xml").getFile();
|
||||
String resourcePath = ValidateTest.class.getResource("/patient-uslab-example1.xml").getFile();
|
||||
// ourLog.info(profilePath);
|
||||
ourLog.info(resourcePath);
|
||||
|
||||
// App.main(new String[] {"validate", "-p", "-n", resourcePath, "-l", profilePath});
|
||||
App.main(new String[] {"validate", "-p", "-n", resourcePath});
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ import java.util.Iterator;
|
|||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
@ -107,7 +108,12 @@ public class LoggingInterceptor implements IClientInterceptor {
|
|||
*/
|
||||
List<String> locationHeaders = theResponse.getHeaders(Constants.HEADER_LOCATION);
|
||||
if (locationHeaders != null && locationHeaders.size() > 0) {
|
||||
respLocation = " (Location: " + locationHeaders.get(0) + ")";
|
||||
String locationValue = locationHeaders.get(0);
|
||||
IdDt locationValueId = new IdDt(locationValue);
|
||||
if (locationValueId.hasBaseUrl() && locationValueId.hasIdPart()) {
|
||||
locationValue = locationValueId.toUnqualified().getValue();
|
||||
}
|
||||
respLocation = " (" + locationValue + ")";
|
||||
}
|
||||
myLog.info("Client response: {}{}", message, respLocation);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>hapi-deployable-pom</artifactId>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<version>3.0.0-SNAPSHOT</version>
|
||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>hapi-fhir-igpacks</artifactId>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-jpaserver-base</artifactId>
|
||||
<version>${project.version}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ca.uhn.hapi.fhir</groupId>
|
||||
<artifactId>hapi-fhir-structures-dstu3</artifactId>
|
||||
<version>${project.version}</version>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>ch.qos.logback</groupId>
|
||||
<artifactId>logback-classic</artifactId>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
</plugins>
|
||||
|
||||
</build>
|
||||
</project>
|
|
@ -0,0 +1,121 @@
|
|||
package parser;
|
||||
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.context.FhirVersionEnum;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
import org.hl7.fhir.dstu3.model.ImplementationGuide;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class IgPackParserDstu3 {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(IgPackParserDstu3.class);
|
||||
private final FhirContext myCtx;
|
||||
|
||||
public IgPackParserDstu3(FhirContext theCtx) {
|
||||
FhirVersionEnum expectedVersion = FhirVersionEnum.DSTU3;
|
||||
Validate.isTrue(theCtx.getVersion().getVersion() == expectedVersion, "theCtx is not for the correct version, expecting " + expectedVersion);
|
||||
|
||||
myCtx = theCtx;
|
||||
}
|
||||
|
||||
private IBaseResource findResource(Map<String, IBaseResource> theCandidateResources, IIdType theId) {
|
||||
IBaseResource retVal = theCandidateResources.get(theId.toUnqualifiedVersionless().getValue());
|
||||
if (retVal == null) {
|
||||
throw new InternalErrorException("Unknown reference in ImplementationGuide: " + theId);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param theIgInputStream The "validator.pack" ZIP file
|
||||
* @param theDescription A description (just used for logs)
|
||||
*/
|
||||
public IValidationSupport parseIg(InputStream theIgInputStream, String theDescription) {
|
||||
Validate.notNull(theIgInputStream, "theIdInputStream must not be null");
|
||||
|
||||
ourLog.info("Parsing IGPack: {}", theDescription);
|
||||
StopWatch sw = new StopWatch();
|
||||
|
||||
ZipInputStream zipInputStream = new ZipInputStream(theIgInputStream);
|
||||
ZipEntry entry;
|
||||
try {
|
||||
|
||||
Map<String, IBaseResource> candidateResources = new HashMap<>();
|
||||
Map<IIdType, IBaseResource> igResources = new HashMap<>();
|
||||
|
||||
while ((entry = zipInputStream.getNextEntry()) != null) {
|
||||
if (entry.getName().endsWith(".json")) {
|
||||
InputStreamReader nextReader = new InputStreamReader(zipInputStream, Constants.CHARSET_UTF8);
|
||||
IBaseResource parsed = myCtx.newJsonParser().parseResource(nextReader);
|
||||
candidateResources.put(entry.getName(), parsed);
|
||||
}
|
||||
}
|
||||
|
||||
ourLog.info("Parsed {} candidateResources in {}ms", candidateResources.size(), sw.getMillis());
|
||||
|
||||
String igResourceName = "ImplementationGuide-ig.json";
|
||||
ImplementationGuide ig = (ImplementationGuide) candidateResources.get(igResourceName);
|
||||
|
||||
if (ig == null) {
|
||||
throw new InternalErrorException("IG Pack '" + theDescription + "' does not contain a resource named: " + igResourceName);
|
||||
}
|
||||
|
||||
// ourLog.info(myCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(ig));
|
||||
|
||||
HashMap<String, IBaseResource> newCandidateResources = new HashMap<>();
|
||||
for (IBaseResource next : candidateResources.values()) {
|
||||
newCandidateResources.put(next.getIdElement().toUnqualifiedVersionless().getValue(), next);
|
||||
}
|
||||
candidateResources = newCandidateResources;
|
||||
|
||||
for (ImplementationGuide.ImplementationGuidePackageComponent nextPackage : ig.getPackage()) {
|
||||
ourLog.info("Processing package {}", nextPackage.getName());
|
||||
|
||||
for (ImplementationGuide.ImplementationGuidePackageResourceComponent nextResource : nextPackage.getResource()) {
|
||||
if (isNotBlank(nextResource.getSourceReference().getReference())) {
|
||||
IdType id = new IdType(nextResource.getSourceReference().getReference());
|
||||
if (isNotBlank(id.getResourceType())) {
|
||||
switch (id.getResourceType()) {
|
||||
case "CodeSystem":
|
||||
case "ConceptMap":
|
||||
case "StructureDefinition":
|
||||
case "ValueSet":
|
||||
IBaseResource resource = findResource(candidateResources, id);
|
||||
igResources.put(id.toUnqualifiedVersionless(), resource);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ourLog.info("IG contains {} resources", igResources.size());
|
||||
return new IgPackValidationSupportDstu3(igResources);
|
||||
|
||||
} catch (Exception e) {
|
||||
throw new InternalErrorException("Failure while parsing IG: " + e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package parser;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.ConceptMap;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class IgPackValidationSupportDstu3 implements IValidationSupport {
|
||||
private final Map<IIdType, IBaseResource> myIgResources;
|
||||
|
||||
public IgPackValidationSupportDstu3(Map<IIdType, IBaseResource> theIgResources) {
|
||||
myIgResources = theIgResources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSet.ValueSetExpansionComponent expandValueSet(FhirContext theContext, ValueSet.ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return new ArrayList<>(myIgResources.values());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<>();
|
||||
for (Map.Entry<IIdType, IBaseResource> next : myIgResources.entrySet()) {
|
||||
if (next.getKey().getResourceType().equals("StructureDefinition")) {
|
||||
retVal.add((StructureDefinition) next.getValue());
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return fetchResource(theContext, CodeSystem.class, theSystem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (Map.Entry<IIdType, IBaseResource> next : myIgResources.entrySet()) {
|
||||
if (theClass.equals(CodeSystem.class)) {
|
||||
if (theClass.isAssignableFrom(next.getValue().getClass())) {
|
||||
CodeSystem sd = ((CodeSystem) next.getValue());
|
||||
if (sd.getUrl().equals(theUri)) {
|
||||
return (T) sd;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theClass.equals(ConceptMap.class)) {
|
||||
if (theClass.isAssignableFrom(next.getValue().getClass())) {
|
||||
ConceptMap sd = ((ConceptMap) next.getValue());
|
||||
if (sd.getUrl().equals(theUri)) {
|
||||
return (T) sd;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theClass.equals(StructureDefinition.class)) {
|
||||
if (theClass.isAssignableFrom(next.getValue().getClass())) {
|
||||
StructureDefinition sd = ((StructureDefinition) next.getValue());
|
||||
if (sd.getUrl().equals(theUri)) {
|
||||
return (T) sd;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (theClass.equals(ValueSet.class)) {
|
||||
if (theClass.isAssignableFrom(next.getValue().getClass())) {
|
||||
ValueSet sd = ((ValueSet) next.getValue());
|
||||
if (sd.getUrl().equals(theUri)) {
|
||||
return (T) sd;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return fetchResource(theCtx, StructureDefinition.class, theUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
package ca.uhn.fhir.igpack.parser;
|
||||
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.dstu3.hapi.validation.IValidationSupport;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import parser.IgPackParserDstu3;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
public class IgPackParserDstu3Test {
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(IgPackParserDstu3Test.class);
|
||||
|
||||
@Test
|
||||
public void testParseIg() {
|
||||
|
||||
FhirContext ctx = FhirContext.forDstu3();
|
||||
IgPackParserDstu3 igParser = new IgPackParserDstu3(ctx);
|
||||
|
||||
IValidationSupport result = igParser.parseIg(IgPackParserDstu3Test.class.getResourceAsStream("/us-core-stu3-validator.pack"), "US-Core STU3");
|
||||
|
||||
assertNotNull(result.fetchResource(ctx, ValueSet.class, "http://hl7.org/fhir/us/core/ValueSet/simple-language"));
|
||||
assertEquals(50, result.fetchAllConformanceResources(ctx).size());
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
<configuration>
|
||||
|
||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<encoder>
|
||||
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] - %msg%n
|
||||
</pattern>
|
||||
</encoder>
|
||||
</appender>
|
||||
|
||||
<logger name="org.eclipse" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.apache" additivity="false" level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
<logger name="org.thymeleaf" additivity="false" level="warn">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
|
||||
<!--
|
||||
<logger name="ca.uhn.fhir.rest.client" additivity="false" level="trace">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</logger>
|
||||
-->
|
||||
|
||||
<root level="info">
|
||||
<appender-ref ref="STDOUT" />
|
||||
</root>
|
||||
|
||||
</configuration>
|
Binary file not shown.
|
@ -165,11 +165,6 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
@Autowired
|
||||
private IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||
|
||||
private <T extends IBaseResource> void autoCreateResource(T theResource) {
|
||||
IFhirResourceDao<T> dao = (IFhirResourceDao<T>) getDao(theResource.getClass());
|
||||
dao.create(theResource);
|
||||
}
|
||||
|
||||
protected void clearRequestAsProcessingSubRequest(ServletRequestDetails theRequestDetails) {
|
||||
if (theRequestDetails != null) {
|
||||
theRequestDetails.getUserData().remove(PROCESSING_SUB_REQUEST);
|
||||
|
@ -243,16 +238,20 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
if (nextParam.getParamName().equals(nextCompositeOf.getName())) {
|
||||
IQueryParameterType nextParamAsClientParam = nextParam.toQueryParameterType();
|
||||
String value = nextParamAsClientParam.getValueAsQueryToken(getContext());
|
||||
value = UrlUtil.escape(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escape(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (linksForCompositePart != null) {
|
||||
for (ResourceLink nextLink : linksForCompositePart) {
|
||||
String value = nextLink.getTargetResource().getIdDt().toUnqualifiedVersionless().getValue();
|
||||
value = UrlUtil.escape(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
if (isNotBlank(value)) {
|
||||
value = UrlUtil.escape(value);
|
||||
nextChoicesList.add(key + "=" + value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -260,7 +259,9 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
Set<String> queryStringsToPopulate = extractCompositeStringUniquesValueChains(theEntity.getResourceType(), partsChoices);
|
||||
|
||||
for (String nextQueryString : queryStringsToPopulate) {
|
||||
compositeStringUniques.add(new ResourceIndexedCompositeStringUnique(theEntity, nextQueryString));
|
||||
if (isNotBlank(nextQueryString)) {
|
||||
compositeStringUniques.add(new ResourceIndexedCompositeStringUnique(theEntity, nextQueryString));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -417,10 +418,12 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
if (getConfig().isAutoCreatePlaceholderReferenceTargets()) {
|
||||
IBaseResource newResource = missingResourceDef.newInstance();
|
||||
newResource.setId(resName + "/" + id);
|
||||
autoCreateResource(newResource);
|
||||
IFhirResourceDao<IBaseResource> placeholderResourceDao = (IFhirResourceDao<IBaseResource>) getDao(newResource.getClass());
|
||||
ourLog.info("Automatically creating empty placeholder resource: {}", newResource.getIdElement().getValue());
|
||||
valueOf = placeholderResourceDao.update(newResource).getEntity().getId();
|
||||
} else {
|
||||
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
|
||||
}
|
||||
|
||||
throw new InvalidRequestException("Resource " + resName + "/" + id + " not found, specified in path: " + nextPathsUnsplit);
|
||||
}
|
||||
ResourceTable target = myEntityManager.find(ResourceTable.class, valueOf);
|
||||
RuntimeResourceDefinition targetResourceDef = getContext().getResourceDefinition(type);
|
||||
|
@ -1562,7 +1565,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
theEntity.setParamsUriPopulated(uriParams.isEmpty() == false);
|
||||
theEntity.setParamsCoords(coordsParams);
|
||||
theEntity.setParamsCoordsPopulated(coordsParams.isEmpty() == false);
|
||||
theEntity.setParamsCompositeStringUnique(compositeStringUniques);
|
||||
// theEntity.setParamsCompositeStringUnique(compositeStringUniques);
|
||||
theEntity.setParamsCompositeStringUniquePresent(compositeStringUniques.isEmpty() == false);
|
||||
theEntity.setResourceLinks(links);
|
||||
theEntity.setHasLinks(links.isEmpty() == false);
|
||||
|
@ -1715,11 +1718,24 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
theEntity.setResourceLinks(links);
|
||||
|
||||
// Store composite string uniques
|
||||
for (ResourceIndexedCompositeStringUnique next : existingCompositeStringUniques) {
|
||||
myEntityManager.remove(next);
|
||||
}
|
||||
for (ResourceIndexedCompositeStringUnique next : compositeStringUniques) {
|
||||
myEntityManager.persist(next);
|
||||
if (getConfig().isUniqueIndexesEnabled()) {
|
||||
for (ResourceIndexedCompositeStringUnique next : existingCompositeStringUniques) {
|
||||
if (!compositeStringUniques.contains(next)) {
|
||||
myEntityManager.remove(next);
|
||||
}
|
||||
}
|
||||
for (ResourceIndexedCompositeStringUnique next : compositeStringUniques) {
|
||||
if (!existingCompositeStringUniques.contains(next)) {
|
||||
if (myConfig.isUniqueIndexesCheckedBeforeSave()) {
|
||||
ResourceIndexedCompositeStringUnique existing = myResourceIndexedCompositeStringUniqueDao.findByQueryString(next.getIndexString());
|
||||
if (existing != null) {
|
||||
throw new PreconditionFailedException("Can not create resource of type " + theEntity.getResourceType() + " as it would create a duplicate index matching query: " + next.getIndexString() + " (existing index belongs to " + existing.getResource().getIdDt().toUnqualifiedVersionless().getValue() + ")");
|
||||
}
|
||||
}
|
||||
ourLog.debug("Persisting unique index: {}", next);
|
||||
myEntityManager.persist(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
theEntity.toString();
|
||||
|
@ -1897,6 +1913,21 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
|
|||
*/
|
||||
public static Set<String> extractCompositeStringUniquesValueChains(String theResourceType, List<List<String>> thePartsChoices) {
|
||||
|
||||
for (List<String> next : thePartsChoices) {
|
||||
for (Iterator<String> iter = next.iterator(); iter.hasNext(); ) {
|
||||
if (isBlank(iter.next())) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
if (next.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
if (thePartsChoices.isEmpty()) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
Collections.sort(thePartsChoices, new Comparator<List<String>>() {
|
||||
@Override
|
||||
public int compare(List<String> o1, List<String> o2) {
|
||||
|
|
|
@ -75,10 +75,64 @@ public class DaoConfig {
|
|||
private boolean myDeleteStaleSearches = true;
|
||||
|
||||
private boolean myEnforceReferentialIntegrityOnDelete = true;
|
||||
private boolean myUniqueIndexesEnabled = true;
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>true</code>), indexes will be
|
||||
* created for search parameters marked as {@link ca.uhn.fhir.jpa.util.JpaConstants#EXT_SP_UNIQUE}.
|
||||
* This is a HAPI FHIR specific extension which can be used to specify that no more than one
|
||||
* resource can exist which matches a given criteria, using a database constraint to
|
||||
* enforce this.
|
||||
*/
|
||||
public boolean isUniqueIndexesEnabled() {
|
||||
return myUniqueIndexesEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to <code>true</code> (default is <code>true</code>), indexes will be
|
||||
* created for search parameters marked as {@link ca.uhn.fhir.jpa.util.JpaConstants#EXT_SP_UNIQUE}.
|
||||
* This is a HAPI FHIR specific extension which can be used to specify that no more than one
|
||||
* resource can exist which matches a given criteria, using a database constraint to
|
||||
* enforce this.
|
||||
*/
|
||||
public void setUniqueIndexesEnabled(boolean theUniqueIndexesEnabled) {
|
||||
myUniqueIndexesEnabled = theUniqueIndexesEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* When using {@link #setUniqueIndexesEnabled(boolean) unique indexes}, if this
|
||||
* setting is set to <code>true</code> (default is <code>true</code>) the system
|
||||
* will test for the existence of a particular unique index value prior to saving
|
||||
* a new one.
|
||||
* <p>
|
||||
* This causes friendlier error messages to be generated, but adds an
|
||||
* extra round-trip to the database for eavh save so it can cause
|
||||
* a small performance hit.
|
||||
* </p>
|
||||
*/
|
||||
public boolean isUniqueIndexesCheckedBeforeSave() {
|
||||
return myUniqueIndexesCheckedBeforeSave;
|
||||
}
|
||||
|
||||
/**
|
||||
* When using {@link #setUniqueIndexesEnabled(boolean) unique indexes}, if this
|
||||
* setting is set to <code>true</code> (default is <code>true</code>) the system
|
||||
* will test for the existence of a particular unique index value prior to saving
|
||||
* a new one.
|
||||
* <p>
|
||||
* This causes friendlier error messages to be generated, but adds an
|
||||
* extra round-trip to the database for eavh save so it can cause
|
||||
* a small performance hit.
|
||||
* </p>
|
||||
*/
|
||||
public void setUniqueIndexesCheckedBeforeSave(boolean theUniqueIndexesCheckedBeforeSave) {
|
||||
myUniqueIndexesCheckedBeforeSave = theUniqueIndexesCheckedBeforeSave;
|
||||
}
|
||||
|
||||
private boolean myUniqueIndexesCheckedBeforeSave = true;
|
||||
private boolean myEnforceReferentialIntegrityOnWrite = true;
|
||||
|
||||
private int myEverythingIncludesFetchPageSize = 50;
|
||||
|
||||
/**
|
||||
* update setter javadoc if default changes
|
||||
*/
|
||||
|
|
|
@ -1258,33 +1258,35 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
* Check if there is a unique key associated with the set
|
||||
* of parameters passed in
|
||||
*/
|
||||
if (myParams.getIncludes().isEmpty()) {
|
||||
if (myParams.getRevIncludes().isEmpty()) {
|
||||
if (myParams.getEverythingMode() == null) {
|
||||
if (myParams.isAllParametersHaveNoModifier()) {
|
||||
Set<String> paramNames = theParams.keySet();
|
||||
if (paramNames.isEmpty() == false) {
|
||||
List<JpaRuntimeSearchParam> searchParams = mySearchParamRegistry.getActiveUniqueSearchParams(myResourceName, paramNames);
|
||||
if (searchParams.size() > 0) {
|
||||
List<List<String>> params = new ArrayList<>();
|
||||
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamNameToValues : theParams.entrySet()) {
|
||||
String nextParamName = nextParamNameToValues.getKey();
|
||||
nextParamName = UrlUtil.escape(nextParamName);
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamNameToValues.getValue()) {
|
||||
ArrayList<String> nextValueList = new ArrayList<>();
|
||||
params.add(nextValueList);
|
||||
for (IQueryParameterType nextOr : nextAnd) {
|
||||
String nextOrValue = nextOr.getValueAsQueryToken(myContext);
|
||||
nextOrValue = UrlUtil.escape(nextOrValue);
|
||||
nextValueList.add(nextParamName + "=" + nextOrValue);
|
||||
if (myCallingDao.getConfig().isUniqueIndexesEnabled()) {
|
||||
if (myParams.getIncludes().isEmpty()) {
|
||||
if (myParams.getRevIncludes().isEmpty()) {
|
||||
if (myParams.getEverythingMode() == null) {
|
||||
if (myParams.isAllParametersHaveNoModifier()) {
|
||||
Set<String> paramNames = theParams.keySet();
|
||||
if (paramNames.isEmpty() == false) {
|
||||
List<JpaRuntimeSearchParam> searchParams = mySearchParamRegistry.getActiveUniqueSearchParams(myResourceName, paramNames);
|
||||
if (searchParams.size() > 0) {
|
||||
List<List<String>> params = new ArrayList<>();
|
||||
for (Entry<String, List<List<? extends IQueryParameterType>>> nextParamNameToValues : theParams.entrySet()) {
|
||||
String nextParamName = nextParamNameToValues.getKey();
|
||||
nextParamName = UrlUtil.escape(nextParamName);
|
||||
for (List<? extends IQueryParameterType> nextAnd : nextParamNameToValues.getValue()) {
|
||||
ArrayList<String> nextValueList = new ArrayList<>();
|
||||
params.add(nextValueList);
|
||||
for (IQueryParameterType nextOr : nextAnd) {
|
||||
String nextOrValue = nextOr.getValueAsQueryToken(myContext);
|
||||
nextOrValue = UrlUtil.escape(nextOrValue);
|
||||
nextValueList.add(nextParamName + "=" + nextOrValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Set<String> uniqueQueryStrings = BaseHapiFhirDao.extractCompositeStringUniquesValueChains(myResourceName, params);
|
||||
ourLastHandlerMechanismForUnitTest = HandlerTypeEnum.UNIQUE_INDEX;
|
||||
return new UniqueIndexIterator(uniqueQueryStrings);
|
||||
|
||||
}
|
||||
|
||||
Set<String> uniqueQueryStrings = BaseHapiFhirDao.extractCompositeStringUniquesValueChains(myResourceName, params);
|
||||
ourLastHandlerMechanismForUnitTest = HandlerTypeEnum.UNIQUE_INDEX;
|
||||
return new UniqueIndexIterator(uniqueQueryStrings);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public class FhirResourceDaoSearchParameterDstu3 extends FhirResourceDaoDstu3<Se
|
|||
String expression = theResource.getExpression();
|
||||
if (isNotBlank(expression)) {
|
||||
final String resourceType = expression.substring(0, expression.indexOf('.'));
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", expression);
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, expression);
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
|
|
|
@ -662,6 +662,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||
matchUrl = matchUrl.replace(UrlUtil.escape(nextTemporaryIdPart), nextReplacementIdPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
package ca.uhn.fhir.jpa.dao.dstu3;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.Transactional.TxType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.Transactional.TxType;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -31,18 +39,7 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
|
||||
@Transactional(value=TxType.REQUIRED)
|
||||
@Transactional(value = TxType.REQUIRED)
|
||||
public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaValidationSupportDstu3.class);
|
||||
|
@ -72,11 +69,22 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 {
|
|||
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
return fetchResource(theCtx, CodeSystem.class, theSystem);
|
||||
|
@ -103,7 +111,7 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 {
|
|||
params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myValueSetDao.search(params);
|
||||
search = myValueSetDao.search(params);
|
||||
}
|
||||
} else {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
@ -145,28 +153,20 @@ public class JpaValidationSupportDstu3 implements IJpaValidationSupportDstu3 {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return fetchResource(theCtx, StructureDefinition.class, theUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return fetchResource(theCtx, StructureDefinition.class, theUrl);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,7 +60,7 @@ public class FhirResourceDaoSearchParameterR4 extends FhirResourceDaoR4<SearchPa
|
|||
String expression = theResource.getExpression();
|
||||
if (isNotBlank(expression)) {
|
||||
final String resourceType = expression.substring(0, expression.indexOf('.'));
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", expression);
|
||||
ourLog.info("Marking all resources of type {} for reindexing due to updated search parameter with path: {}", resourceType, expression);
|
||||
|
||||
TransactionTemplate txTemplate = new TransactionTemplate(myPlatformTransactionManager);
|
||||
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
|
||||
|
|
|
@ -662,6 +662,7 @@ public class FhirSystemDaoR4 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
String nextReplacementIdPart = nextReplacementId.getValueAsString();
|
||||
if (nextTemporaryId.isUrn() && nextTemporaryIdPart.length() > IdType.URN_PREFIX.length()) {
|
||||
matchUrl = matchUrl.replace(nextTemporaryIdPart, nextReplacementIdPart);
|
||||
matchUrl = matchUrl.replace(UrlUtil.escape(nextTemporaryIdPart), nextReplacementIdPart);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,15 +1,23 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.Transactional.TxType;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import javax.transaction.Transactional;
|
||||
import javax.transaction.Transactional.TxType;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
|
@ -31,18 +39,7 @@ import org.hl7.fhir.instance.model.api.IAnyResource;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
|
||||
import ca.uhn.fhir.rest.api.server.IBundleProvider;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.param.UriParam;
|
||||
|
||||
@Transactional(value=TxType.REQUIRED)
|
||||
@Transactional(value = TxType.REQUIRED)
|
||||
public class JpaValidationSupportR4 implements IJpaValidationSupportR4 {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaValidationSupportR4.class);
|
||||
|
@ -72,11 +69,22 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4 {
|
|||
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
return fetchResource(theCtx, CodeSystem.class, theSystem);
|
||||
|
@ -103,7 +111,7 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4 {
|
|||
params = new SearchParameterMap();
|
||||
params.setLoadSynchronousUpTo(1);
|
||||
params.add(ValueSet.SP_URL, new UriParam(theUri));
|
||||
search = myValueSetDao.search(params);
|
||||
search = myValueSetDao.search(params);
|
||||
}
|
||||
} else {
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
|
@ -145,28 +153,20 @@ public class JpaValidationSupportR4 implements IJpaValidationSupportR4 {
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return fetchResource(theCtx, StructureDefinition.class, theUrl);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
@Transactional(value = TxType.SUPPORTS)
|
||||
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
return fetchResource(theCtx, StructureDefinition.class, theUrl);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(value=TxType.SUPPORTS)
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package ca.uhn.fhir.jpa.entity;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.commons.lang3.builder.*;
|
||||
import org.hl7.fhir.r4.model.Resource;
|
||||
|
||||
|
@ -108,6 +109,7 @@ public class ResourceIndexedCompositeStringUnique implements Comparable<Resource
|
|||
}
|
||||
|
||||
public void setResource(ResourceTable theResource) {
|
||||
Validate.notNull(theResource);
|
||||
myResource = theResource;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,7 @@ import ca.uhn.fhir.rest.param.DateRangeParam;
|
|||
public class BaseJpaSystemProvider<T, MT> extends BaseJpaProvider {
|
||||
|
||||
public static final String MARK_ALL_RESOURCES_FOR_REINDEXING = "$mark-all-resources-for-reindexing";
|
||||
public static final String PERFORM_REINDEXING_PASS = "$perform-reindexing-pass";
|
||||
|
||||
private IFhirSystemDao<T, MT> myDao;
|
||||
|
||||
|
|
|
@ -30,11 +30,9 @@ import ca.uhn.fhir.util.ParametersUtil;
|
|||
|
||||
public abstract class BaseJpaSystemProviderDstu2Plus<T, MT> extends BaseJpaSystemProvider<T, MT> {
|
||||
|
||||
//@formatter:off
|
||||
@Operation(name=MARK_ALL_RESOURCES_FOR_REINDEXING, idempotent=true, returnParameters= {
|
||||
@OperationParam(name="status")
|
||||
})
|
||||
//@formatter:on
|
||||
public IBaseResource markAllResourcesForReindexing() {
|
||||
int count = getDao().markAllResourcesForReindexing();
|
||||
|
||||
|
@ -46,5 +44,18 @@ public abstract class BaseJpaSystemProviderDstu2Plus<T, MT> extends BaseJpaSyste
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Operation(name=PERFORM_REINDEXING_PASS, idempotent=true, returnParameters= {
|
||||
@OperationParam(name="status")
|
||||
})
|
||||
public IBaseResource performReindexingPass() {
|
||||
int count = getDao().performReindexingPass(1000);
|
||||
|
||||
IBaseParameters retVal = ParametersUtil.newInstance(getContext());
|
||||
|
||||
IPrimitiveType<?> string = ParametersUtil.createString(getContext(), "Indexed " + count + " resources");
|
||||
ParametersUtil.addParameterToParameters(getContext(), retVal, string, "status");
|
||||
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -46,10 +46,7 @@ import org.springframework.transaction.support.TransactionSynchronizationManager
|
|||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.PreDestroy;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
public abstract class BaseSubscriptionInterceptor extends ServerOperationInterceptorAdapter {
|
||||
|
@ -63,13 +60,15 @@ public abstract class BaseSubscriptionInterceptor extends ServerOperationInterce
|
|||
private static final Integer MAX_SUBSCRIPTION_RESULTS = 1000;
|
||||
private SubscribableChannel myProcessingChannel;
|
||||
private SubscribableChannel myDeliveryChannel;
|
||||
private ExecutorService myExecutor;
|
||||
private ExecutorService myProcessingExecutor;
|
||||
private int myExecutorThreadCount;
|
||||
private SubscriptionActivatingSubscriber mySubscriptionActivatingSubscriber;
|
||||
private MessageHandler mySubscriptionCheckingSubscriber;
|
||||
private ConcurrentHashMap<String, IBaseResource> myIdToSubscription = new ConcurrentHashMap<>();
|
||||
private Logger ourLog = LoggerFactory.getLogger(BaseSubscriptionInterceptor.class);
|
||||
private BlockingQueue<Runnable> myExecutorQueue;
|
||||
private ThreadPoolExecutor myDeliveryExecutor;
|
||||
private LinkedBlockingQueue<Runnable> myProcessingExecutorQueue;
|
||||
private LinkedBlockingQueue<Runnable> myDeliveryExecutorQueue;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -89,8 +88,8 @@ public abstract class BaseSubscriptionInterceptor extends ServerOperationInterce
|
|||
myDeliveryChannel = theDeliveryChannel;
|
||||
}
|
||||
|
||||
public BlockingQueue<Runnable> getExecutorQueueForUnitTests() {
|
||||
return myExecutorQueue;
|
||||
public int getExecutorQueueSizeForUnitTests() {
|
||||
return myProcessingExecutorQueue.size() + myDeliveryExecutorQueue.size();
|
||||
}
|
||||
|
||||
public int getExecutorThreadCount() {
|
||||
|
@ -157,42 +156,73 @@ public abstract class BaseSubscriptionInterceptor extends ServerOperationInterce
|
|||
|
||||
@PostConstruct
|
||||
public void postConstruct() {
|
||||
myExecutorQueue = new LinkedBlockingQueue<>(1000);
|
||||
{
|
||||
myProcessingExecutorQueue = new LinkedBlockingQueue<>(1000);
|
||||
|
||||
RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
|
||||
@Override
|
||||
public void rejectedExecution(Runnable theRunnable, ThreadPoolExecutor theExecutor) {
|
||||
ourLog.info("Note: Executor queue is full ({} elements), waiting for a slot to become available!", myExecutorQueue.size());
|
||||
StopWatch sw = new StopWatch();
|
||||
try {
|
||||
myExecutorQueue.put(theRunnable);
|
||||
} catch (InterruptedException theE) {
|
||||
throw new RejectedExecutionException("Task " + theRunnable.toString() +
|
||||
" rejected from " + theE.toString());
|
||||
RejectedExecutionHandler rejectedExecutionHandler = new RejectedExecutionHandler() {
|
||||
@Override
|
||||
public void rejectedExecution(Runnable theRunnable, ThreadPoolExecutor theExecutor) {
|
||||
ourLog.info("Note: Executor queue is full ({} elements), waiting for a slot to become available!", myProcessingExecutorQueue.size());
|
||||
StopWatch sw = new StopWatch();
|
||||
try {
|
||||
myProcessingExecutorQueue.put(theRunnable);
|
||||
} catch (InterruptedException theE) {
|
||||
throw new RejectedExecutionException("Task " + theRunnable.toString() +
|
||||
" rejected from " + theE.toString());
|
||||
}
|
||||
ourLog.info("Slot become available after {}ms", sw.getMillis());
|
||||
}
|
||||
ourLog.info("Slot become available after {}ms", sw.getMillis());
|
||||
}
|
||||
};
|
||||
ThreadFactory threadFactory = new BasicThreadFactory.Builder()
|
||||
.namingPattern("subscription-%d")
|
||||
.daemon(false)
|
||||
.priority(Thread.NORM_PRIORITY)
|
||||
.build();
|
||||
myExecutor = new ThreadPoolExecutor(
|
||||
1,
|
||||
getExecutorThreadCount(),
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
myExecutorQueue,
|
||||
threadFactory,
|
||||
rejectedExecutionHandler);
|
||||
|
||||
};
|
||||
ThreadFactory threadFactory = new BasicThreadFactory.Builder()
|
||||
.namingPattern("subscription-proc-%d")
|
||||
.daemon(false)
|
||||
.priority(Thread.NORM_PRIORITY)
|
||||
.build();
|
||||
myProcessingExecutor = new ThreadPoolExecutor(
|
||||
1,
|
||||
getExecutorThreadCount(),
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
myProcessingExecutorQueue,
|
||||
threadFactory,
|
||||
rejectedExecutionHandler);
|
||||
}
|
||||
{
|
||||
myDeliveryExecutorQueue = new LinkedBlockingQueue<>(1000);
|
||||
BasicThreadFactory threadFactory = new BasicThreadFactory.Builder()
|
||||
.namingPattern("subscription-delivery-%d")
|
||||
.daemon(false)
|
||||
.priority(Thread.NORM_PRIORITY)
|
||||
.build();
|
||||
RejectedExecutionHandler rejectedExecutionHandler2 = new RejectedExecutionHandler() {
|
||||
@Override
|
||||
public void rejectedExecution(Runnable theRunnable, ThreadPoolExecutor theExecutor) {
|
||||
ourLog.info("Note: Executor queue is full ({} elements), waiting for a slot to become available!", myDeliveryExecutorQueue.size());
|
||||
StopWatch sw = new StopWatch();
|
||||
try {
|
||||
myDeliveryExecutorQueue.put(theRunnable);
|
||||
} catch (InterruptedException theE) {
|
||||
throw new RejectedExecutionException("Task " + theRunnable.toString() +
|
||||
" rejected from " + theE.toString());
|
||||
}
|
||||
ourLog.info("Slot become available after {}ms", sw.getMillis());
|
||||
}
|
||||
};
|
||||
myDeliveryExecutor = new ThreadPoolExecutor(
|
||||
1,
|
||||
getExecutorThreadCount(),
|
||||
0L,
|
||||
TimeUnit.MILLISECONDS,
|
||||
myDeliveryExecutorQueue,
|
||||
threadFactory,
|
||||
rejectedExecutionHandler2);
|
||||
}
|
||||
|
||||
if (getProcessingChannel() == null) {
|
||||
setProcessingChannel(new ExecutorSubscribableChannel(myExecutor));
|
||||
setProcessingChannel(new ExecutorSubscribableChannel(myProcessingExecutor));
|
||||
}
|
||||
if (getDeliveryChannel() == null) {
|
||||
setDeliveryChannel(new ExecutorSubscribableChannel(myExecutor));
|
||||
setDeliveryChannel(new ExecutorSubscribableChannel(myDeliveryExecutor));
|
||||
}
|
||||
|
||||
if (mySubscriptionActivatingSubscriber == null) {
|
||||
|
|
|
@ -21,12 +21,14 @@ package ca.uhn.fhir.jpa.subscription;
|
|||
*/
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.IClientExecutable;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.Subscription;
|
||||
|
@ -78,44 +80,51 @@ public class SubscriptionDeliveringRestHookSubscriber extends BaseSubscriptionSu
|
|||
if (!(theMessage.getPayload() instanceof ResourceDeliveryMessage)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
ResourceDeliveryMessage msg = (ResourceDeliveryMessage) theMessage.getPayload();
|
||||
|
||||
ResourceDeliveryMessage msg = (ResourceDeliveryMessage) theMessage.getPayload();
|
||||
|
||||
if (!subscriptionTypeApplies(getContext(), msg.getSubscription())) {
|
||||
return;
|
||||
}
|
||||
|
||||
IBaseResource subscription = msg.getSubscription();
|
||||
|
||||
|
||||
// Grab the endpoint from the subscription
|
||||
IPrimitiveType<?> endpoint = getContext().newTerser().getSingleValueOrNull(subscription, BaseSubscriptionInterceptor.SUBSCRIPTION_ENDPOINT, IPrimitiveType.class);
|
||||
String endpointUrl = endpoint.getValueAsString();
|
||||
|
||||
// Grab the payload type (encoding mimetype) from the subscription
|
||||
IPrimitiveType<?> payload = getContext().newTerser().getSingleValueOrNull(subscription, BaseSubscriptionInterceptor.SUBSCRIPTION_PAYLOAD, IPrimitiveType.class);
|
||||
String payloadString = payload.getValueAsString();
|
||||
if (payloadString.contains(";")) {
|
||||
payloadString = payloadString.substring(0, payloadString.indexOf(';'));
|
||||
}
|
||||
payloadString = payloadString.trim();
|
||||
EncodingEnum payloadType = EncodingEnum.forContentType(payloadString);
|
||||
payloadType = ObjectUtils.defaultIfNull(payloadType, EncodingEnum.XML);
|
||||
|
||||
// Create the client request
|
||||
getContext().getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
IGenericClient client = getContext().newRestfulGenericClient(endpointUrl);
|
||||
|
||||
// Additional headers specified in the subscription
|
||||
List<IPrimitiveType> headers = getContext().newTerser().getValues(subscription, BaseSubscriptionInterceptor.SUBSCRIPTION_HEADER, IPrimitiveType.class);
|
||||
for (IPrimitiveType next : headers) {
|
||||
if (isNotBlank(next.getValueAsString())) {
|
||||
client.registerInterceptor(new SimpleRequestHeaderInterceptor(next.getValueAsString()));
|
||||
if (!subscriptionTypeApplies(getContext(), msg.getSubscription())) {
|
||||
return;
|
||||
}
|
||||
|
||||
IBaseResource subscription = msg.getSubscription();
|
||||
|
||||
|
||||
// Grab the endpoint from the subscription
|
||||
IPrimitiveType<?> endpoint = getContext().newTerser().getSingleValueOrNull(subscription, BaseSubscriptionInterceptor.SUBSCRIPTION_ENDPOINT, IPrimitiveType.class);
|
||||
String endpointUrl = endpoint != null ? endpoint.getValueAsString() : null;
|
||||
|
||||
// Grab the payload type (encoding mimetype) from the subscription
|
||||
IPrimitiveType<?> payload = getContext().newTerser().getSingleValueOrNull(subscription, BaseSubscriptionInterceptor.SUBSCRIPTION_PAYLOAD, IPrimitiveType.class);
|
||||
String payloadString = payload != null ? payload.getValueAsString() : null;
|
||||
payloadString = StringUtils.defaultString(payloadString, Constants.CT_FHIR_XML_NEW);
|
||||
if (payloadString.contains(";")) {
|
||||
payloadString = payloadString.substring(0, payloadString.indexOf(';'));
|
||||
}
|
||||
payloadString = payloadString.trim();
|
||||
EncodingEnum payloadType = EncodingEnum.forContentType(payloadString);
|
||||
payloadType = ObjectUtils.defaultIfNull(payloadType, EncodingEnum.XML);
|
||||
|
||||
// Create the client request
|
||||
getContext().getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
IGenericClient client = null;
|
||||
if (isNotBlank(endpointUrl)) {
|
||||
client = getContext().newRestfulGenericClient(endpointUrl);
|
||||
|
||||
// Additional headers specified in the subscription
|
||||
List<IPrimitiveType> headers = getContext().newTerser().getValues(subscription, BaseSubscriptionInterceptor.SUBSCRIPTION_HEADER, IPrimitiveType.class);
|
||||
for (IPrimitiveType next : headers) {
|
||||
if (isNotBlank(next.getValueAsString())) {
|
||||
client.registerInterceptor(new SimpleRequestHeaderInterceptor(next.getValueAsString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deliverPayload(msg, subscription, payloadType, client);
|
||||
} catch (Exception e) {
|
||||
ourLog.error("Failure handling subscription payload", e);
|
||||
throw new MessagingException(theMessage, "Failure handling subscription payload", e);
|
||||
}
|
||||
|
||||
deliverPayload(msg, subscription, payloadType, client);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -254,6 +254,11 @@ public class HapiTerminologySvcDstu3 extends BaseHapiTerminologySvc implements I
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<VersionIndependentConcept> expandValueSet(String theValueSet) {
|
||||
ValueSet source = new ValueSet();
|
||||
|
|
|
@ -1,5 +1,43 @@
|
|||
package ca.uhn.fhir.jpa.term;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.DaoMethodOutcome;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.entity.ResourceTable;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.BaseServerResponseException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.hibernate.search.jpa.FullTextEntityManager;
|
||||
import org.hibernate.search.jpa.FullTextQuery;
|
||||
import org.hibernate.search.query.dsl.BooleanJunction;
|
||||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.ValueSet.*;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
|
@ -22,36 +60,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.hibernate.search.jpa.FullTextEntityManager;
|
||||
import org.hibernate.search.jpa.FullTextQuery;
|
||||
import org.hibernate.search.query.dsl.BooleanJunction;
|
||||
import org.hibernate.search.query.dsl.QueryBuilder;
|
||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.*;
|
||||
import org.hl7.fhir.r4.terminologies.ValueSetExpander.ValueSetExpansionOutcome;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.jpa.dao.*;
|
||||
import ca.uhn.fhir.jpa.entity.*;
|
||||
import ca.uhn.fhir.jpa.util.StopWatch;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.server.exceptions.*;
|
||||
import ca.uhn.fhir.util.CoverageIgnore;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
|
||||
public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IValidationSupport, IHapiTerminologySvcR4 {
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(HapiTerminologySvcR4.class);
|
||||
|
@ -63,6 +71,15 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
|
|||
@Autowired
|
||||
private IValidationSupport myValidationSupport;
|
||||
|
||||
private void addAllChildren(String theSystemString, ConceptDefinitionComponent theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
if (isNotBlank(theCode.getCode())) {
|
||||
theListToPopulate.add(new VersionIndependentConcept(theSystemString, theCode.getCode()));
|
||||
}
|
||||
for (ConceptDefinitionComponent nextChild : theCode.getConcept()) {
|
||||
addAllChildren(theSystemString, nextChild, theListToPopulate);
|
||||
}
|
||||
}
|
||||
|
||||
private void addCodeIfNotAlreadyAdded(String system, ValueSetExpansionComponent retVal, Set<String> addedCodes, TermConcept nextConcept) {
|
||||
if (addedCodes.add(nextConcept.getCode())) {
|
||||
ValueSetExpansionContainsComponent contains = retVal.addContains();
|
||||
|
@ -72,36 +89,20 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<VersionIndependentConcept> findCodesBelowUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
|
||||
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
if (system != null) {
|
||||
findCodesBelow(system, theSystem, theCode, retVal);
|
||||
}
|
||||
return retVal;
|
||||
private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction<?> bool, ConceptSetFilterComponent nextFilter) {
|
||||
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
|
||||
}
|
||||
|
||||
private void findCodesBelow(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
|
||||
findCodesBelow(theSystemString, theCode, theListToPopulate, conceptList);
|
||||
}
|
||||
|
||||
private void findCodesBelow(String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate, List<ConceptDefinitionComponent> conceptList) {
|
||||
for (ConceptDefinitionComponent next : conceptList) {
|
||||
if (theCode.equals(next.getCode())) {
|
||||
addAllChildren(theSystemString, next, theListToPopulate);
|
||||
} else {
|
||||
findCodesBelow(theSystemString, theCode, theListToPopulate, next.getConcept());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void findCodesAbove(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
|
||||
for (ConceptDefinitionComponent next : conceptList) {
|
||||
addTreeIfItContainsCode(theSystemString, next, theCode, theListToPopulate);
|
||||
}
|
||||
private void addDisplayFilterInexact(QueryBuilder qb, BooleanJunction<?> bool, ConceptSetFilterComponent nextFilter) {
|
||||
Query textQuery = qb
|
||||
.phrase()
|
||||
.withSlop(2)
|
||||
.onField("myDisplay").boostedTo(4.0f)
|
||||
.andField("myDisplayEdgeNGram").boostedTo(2.0f)
|
||||
// .andField("myDisplayNGram").boostedTo(1.0f)
|
||||
// .andField("myDisplayPhonetic").boostedTo(0.5f)
|
||||
.sentence(nextFilter.getValue().toLowerCase()).createQuery();
|
||||
bool.must(textQuery);
|
||||
}
|
||||
|
||||
private boolean addTreeIfItContainsCode(String theSystemString, ConceptDefinitionComponent theNext, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
|
@ -118,41 +119,6 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
|
|||
return false;
|
||||
}
|
||||
|
||||
private void addAllChildren(String theSystemString, ConceptDefinitionComponent theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
if (isNotBlank(theCode.getCode())) {
|
||||
theListToPopulate.add(new VersionIndependentConcept(theSystemString, theCode.getCode()));
|
||||
}
|
||||
for (ConceptDefinitionComponent nextChild : theCode.getConcept()) {
|
||||
addAllChildren(theSystemString, nextChild, theListToPopulate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<VersionIndependentConcept> findCodesAboveUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
|
||||
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
if (system != null) {
|
||||
findCodesAbove(system, theSystem, theCode, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction<?> bool, ConceptSetFilterComponent nextFilter) {
|
||||
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
|
||||
}
|
||||
|
||||
private void addDisplayFilterInexact(QueryBuilder qb, BooleanJunction<?> bool, ConceptSetFilterComponent nextFilter) {
|
||||
Query textQuery = qb
|
||||
.phrase()
|
||||
.withSlop(2)
|
||||
.onField("myDisplay").boostedTo(4.0f)
|
||||
.andField("myDisplayEdgeNGram").boostedTo(2.0f)
|
||||
// .andField("myDisplayNGram").boostedTo(1.0f)
|
||||
// .andField("myDisplayPhonetic").boostedTo(0.5f)
|
||||
.sentence(nextFilter.getValue().toLowerCase()).createQuery();
|
||||
bool.must(textQuery);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
String system = theInclude.getSystem();
|
||||
|
@ -278,6 +244,11 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
|
|||
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return Collections.emptyList();
|
||||
|
@ -300,6 +271,48 @@ public class HapiTerminologySvcR4 extends BaseHapiTerminologySvc implements IVal
|
|||
return null;
|
||||
}
|
||||
|
||||
private void findCodesAbove(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
|
||||
for (ConceptDefinitionComponent next : conceptList) {
|
||||
addTreeIfItContainsCode(theSystemString, next, theCode, theListToPopulate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<VersionIndependentConcept> findCodesAboveUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
|
||||
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
if (system != null) {
|
||||
findCodesAbove(system, theSystem, theCode, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
private void findCodesBelow(CodeSystem theSystem, String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate) {
|
||||
List<ConceptDefinitionComponent> conceptList = theSystem.getConcept();
|
||||
findCodesBelow(theSystemString, theCode, theListToPopulate, conceptList);
|
||||
}
|
||||
|
||||
private void findCodesBelow(String theSystemString, String theCode, List<VersionIndependentConcept> theListToPopulate, List<ConceptDefinitionComponent> conceptList) {
|
||||
for (ConceptDefinitionComponent next : conceptList) {
|
||||
if (theCode.equals(next.getCode())) {
|
||||
addAllChildren(theSystemString, next, theListToPopulate);
|
||||
} else {
|
||||
findCodesBelow(theSystemString, theCode, theListToPopulate, next.getConcept());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected List<VersionIndependentConcept> findCodesBelowUsingBuiltInSystems(String theSystem, String theCode) {
|
||||
ArrayList<VersionIndependentConcept> retVal = new ArrayList<VersionIndependentConcept>();
|
||||
CodeSystem system = myValidationSupport.fetchCodeSystem(myContext, theSystem);
|
||||
if (system != null) {
|
||||
findCodesBelow(system, theSystem, theCode, retVal);
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theContext, String theSystem) {
|
||||
return super.supportsSystem(theSystem);
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.util;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
/*
|
||||
|
@ -72,9 +74,15 @@ public class StopWatch {
|
|||
|
||||
static public String formatMillis(long val) {
|
||||
StringBuilder buf = new StringBuilder(20);
|
||||
append(buf, "", 2, ((val % 3600000) / 60000));
|
||||
append(buf, ":", 2, ((val % 60000) / 1000));
|
||||
append(buf, ".", 3, (val % 1000));
|
||||
if (val >= DateUtils.MILLIS_PER_DAY) {
|
||||
append(buf, "", 1, ((val / DateUtils.MILLIS_PER_DAY)));
|
||||
append(buf, "d", 2, ((val % DateUtils.MILLIS_PER_DAY) / DateUtils.MILLIS_PER_HOUR));
|
||||
} else {
|
||||
append(buf, "", 2, ((val % DateUtils.MILLIS_PER_DAY) / DateUtils.MILLIS_PER_HOUR));
|
||||
}
|
||||
append(buf, ":", 2, ((val % DateUtils.MILLIS_PER_HOUR) / DateUtils.MILLIS_PER_MINUTE));
|
||||
append(buf, ":", 2, ((val % DateUtils.MILLIS_PER_MINUTE) / DateUtils.MILLIS_PER_SECOND));
|
||||
append(buf, ".", 3, (val % DateUtils.MILLIS_PER_SECOND));
|
||||
return buf.toString();
|
||||
}
|
||||
|
||||
|
|
|
@ -57,6 +57,9 @@ public abstract class BaseJpaDstu3Test extends BaseJpaTest {
|
|||
private static JpaValidationSupportChainDstu3 ourJpaValidationSupportChainDstu3;
|
||||
private static IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> ourValueSetDao;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("myCoverageDaoDstu3")
|
||||
protected IFhirResourceDao<Coverage> myCoverageDao;
|
||||
@Autowired
|
||||
protected IResourceIndexedCompositeStringUniqueDao myResourceIndexedCompositeStringUniqueDao;
|
||||
@Autowired
|
||||
|
|
|
@ -9,6 +9,7 @@ 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;
|
||||
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.PublicationStatus;
|
||||
|
@ -36,6 +37,185 @@ public class FhirResourceDaoDstu3UniqueSearchParamTest extends BaseJpaDstu3Test
|
|||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexTransactionWithMatchUrl() {
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt2.setBirthDateElement(new DateType("2011-01-02"));
|
||||
IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
|
||||
|
||||
Coverage cov = new Coverage();
|
||||
cov.getBeneficiary().setReference(id2.getValue());
|
||||
cov.addIdentifier().setSystem("urn:foo:bar").setValue("123");
|
||||
IIdType id3 = myCoverageDao.create(cov).getId().toUnqualifiedVersionless();
|
||||
|
||||
createUniqueIndexCoverageBeneficiary();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Coverage/" + id3.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Coverage?beneficiary=Patient%2F" + id2.getIdPart() + "&identifier=urn%3Afoo%3Abar%7C123", uniques.get(0).getIndexString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testIndexTransactionWithMatchUrl2() {
|
||||
createUniqueIndexCoverageBeneficiary();
|
||||
|
||||
String input = "{\n" +
|
||||
" \"resourceType\": \"Bundle\",\n" +
|
||||
" \"type\": \"transaction\",\n" +
|
||||
" \"entry\": [\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\": \"urn:uuid:d2a46176-8e15-405d-bbda-baea1a9dc7f3\",\n" +
|
||||
" \"resource\": {\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"use\": \"official\",\n" +
|
||||
" \"type\": {\n" +
|
||||
" \"coding\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/v2/0203\",\n" +
|
||||
" \"code\": \"MR\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"system\": \"FOOORG:FOOSITE:patientid:MR:R\",\n" +
|
||||
" \"value\": \"007811959\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"request\": {\n" +
|
||||
" \"method\": \"PUT\",\n" +
|
||||
" \"url\": \"/Patient?identifier=FOOORG%3AFOOSITE%3Apatientid%3AMR%3AR%7C007811959%2CFOOORG%3AFOOSITE%3Apatientid%3AMR%3AB%7C000929990%2CFOOORG%3AFOOSITE%3Apatientid%3API%3APH%7C00589363%2Chttp%3A%2F%2Fhl7.org%2Ffhir%2Fsid%2Fus-ssn%7C657-01-8133\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\": \"urn:uuid:b58ff639-11d1-4dac-942f-abf4f9a625d7\",\n" +
|
||||
" \"resource\": {\n" +
|
||||
" \"resourceType\": \"Coverage\",\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"FOOORG:FOOSITE:coverage:planId\",\n" +
|
||||
" \"value\": \"0403-010101\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"beneficiary\": {\n" +
|
||||
" \"reference\": \"urn:uuid:d2a46176-8e15-405d-bbda-baea1a9dc7f3\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"request\": {\n" +
|
||||
" \"method\": \"PUT\",\n" +
|
||||
" \"url\": \"/Coverage?beneficiary=urn%3Auuid%3Ad2a46176-8e15-405d-bbda-baea1a9dc7f3&identifier=FOOORG%3AFOOSITE%3Acoverage%3AplanId%7C0403-010101\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\": \"urn:uuid:13f5da1a-6601-4c1a-82c9-41527be23fa0\",\n" +
|
||||
" \"resource\": {\n" +
|
||||
" \"resourceType\": \"Coverage\",\n" +
|
||||
" \"contained\": [\n" +
|
||||
" {\n" +
|
||||
" \"resourceType\": \"RelatedPerson\",\n" +
|
||||
" \"id\": \"1\",\n" +
|
||||
" \"name\": [\n" +
|
||||
" {\n" +
|
||||
" \"family\": \"SMITH\",\n" +
|
||||
" \"given\": [\n" +
|
||||
" \"FAKER\"\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"resourceType\": \"Organization\",\n" +
|
||||
" \"id\": \"2\",\n" +
|
||||
" \"name\": \"MEDICAID\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"FOOORG:FOOSITE:coverage:planId\",\n" +
|
||||
" \"value\": \"0404-010101\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"policyHolder\": {\n" +
|
||||
" \"reference\": \"#1\"\n" +
|
||||
" },\n" +
|
||||
" \"beneficiary\": {\n" +
|
||||
" \"reference\": \"urn:uuid:d2a46176-8e15-405d-bbda-baea1a9dc7f3\"\n" +
|
||||
" },\n" +
|
||||
" \"payor\": [\n" +
|
||||
" {\n" +
|
||||
" \"reference\": \"#2\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"request\": {\n" +
|
||||
" \"method\": \"PUT\",\n" +
|
||||
" \"url\": \"/Coverage?beneficiary=urn%3Auuid%3Ad2a46176-8e15-405d-bbda-baea1a9dc7f3&identifier=FOOORG%3AFOOSITE%3Acoverage%3AplanId%7C0404-010101\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
|
||||
Bundle inputBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(inputBundle));
|
||||
mySystemDao.transaction(mySrd, inputBundle);
|
||||
|
||||
inputBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
|
||||
mySystemDao.transaction(mySrd, inputBundle);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void createUniqueIndexCoverageBeneficiary() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/coverage-beneficiary");
|
||||
sp.setCode("beneficiary");
|
||||
sp.setExpression("Coverage.beneficiary");
|
||||
sp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Coverage");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/coverage-identifier");
|
||||
sp.setCode("identifier");
|
||||
sp.setExpression("Coverage.identifier");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Coverage");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/coverage-beneficiary-identifier");
|
||||
sp.setCode("coverage-beneficiary-identifier");
|
||||
sp.setExpression("Coverage.beneficiary");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Coverage");
|
||||
sp.addComponent()
|
||||
.setExpression("Coverage")
|
||||
.setDefinition(new Reference("/SearchParameter/coverage-beneficiary"));
|
||||
sp.addComponent()
|
||||
.setExpression("Coverage")
|
||||
.setDefinition(new Reference("/SearchParameter/coverage-identifier"));
|
||||
sp.addExtension()
|
||||
.setUrl(JpaConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(true);
|
||||
|
@ -143,7 +323,7 @@ public class FhirResourceDaoDstu3UniqueSearchParamTest extends BaseJpaDstu3Test
|
|||
try {
|
||||
myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
fail();
|
||||
} catch (JpaSystemException e) {
|
||||
} catch (PreconditionFailedException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
|
|
|
@ -146,6 +146,9 @@ public abstract class BaseJpaR4Test extends BaseJpaTest {
|
|||
@Qualifier("myPatientDaoR4")
|
||||
protected IFhirResourceDaoPatient<Patient> myPatientDao;
|
||||
@Autowired
|
||||
@Qualifier("myCoverageDaoR4")
|
||||
protected IFhirResourceDao<Coverage> myCoverageDao;
|
||||
@Autowired
|
||||
@Qualifier("myPractitionerDaoR4")
|
||||
protected IFhirResourceDao<Practitioner> myPractitionerDao;
|
||||
@Autowired
|
||||
|
|
|
@ -83,12 +83,32 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
Observation o = new Observation();
|
||||
o.setStatus(ObservationStatus.FINAL);
|
||||
o.getSubject().setReference("Patient/FOO");
|
||||
try {
|
||||
myObservationDao.create(o, mySrd);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Resource Patient/FOO not found, specified in path: Observation.subject", e.getMessage());
|
||||
}
|
||||
myObservationDao.create(o, mySrd);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateWithMultiplePlaceholders() {
|
||||
myDaoConfig.setAutoCreatePlaceholderReferenceTargets(true);
|
||||
|
||||
Task task = new Task();
|
||||
task.addNote().setText("A note");
|
||||
task.addPartOf().setReference("Task/AAA");
|
||||
task.addPartOf().setReference("Task/AAA");
|
||||
task.addPartOf().setReference("Task/AAA");
|
||||
IIdType id = myTaskDao.create(task).getId().toUnqualifiedVersionless();
|
||||
|
||||
task = myTaskDao.read(id);
|
||||
assertEquals(3, task.getPartOf().size());
|
||||
assertEquals("Task/AAA", task.getPartOf().get(0).getReference());
|
||||
assertEquals("Task/AAA", task.getPartOf().get(1).getReference());
|
||||
assertEquals("Task/AAA", task.getPartOf().get(2).getReference());
|
||||
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.add(Task.SP_PART_OF, new ReferenceParam("Task/AAA"));
|
||||
List<String> found = toUnqualifiedVersionlessIdValues(myTaskDao.search(params));
|
||||
assertThat(found, contains(id.getValue()));
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -123,12 +143,7 @@ public class FhirResourceDaoCreatePlaceholdersR4Test extends BaseJpaR4Test {
|
|||
o.setId(id);
|
||||
o.setStatus(ObservationStatus.FINAL);
|
||||
o.getSubject().setReference("Patient/FOO");
|
||||
try {
|
||||
myObservationDao.update(o, mySrd);
|
||||
fail();
|
||||
} catch (InvalidRequestException e) {
|
||||
assertEquals("Resource Patient/FOO not found, specified in path: Observation.subject", e.getMessage());
|
||||
}
|
||||
myObservationDao.update(o, mySrd);
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
|
|
|
@ -22,6 +22,7 @@ import org.springframework.orm.jpa.JpaSystemException;
|
|||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||
import static org.hamcrest.Matchers.empty;
|
||||
|
@ -35,6 +36,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
@After
|
||||
public void after() {
|
||||
myDaoConfig.setDefaultSearchParamsCanBeOverridden(new DaoConfig().isDefaultSearchParamsCanBeOverridden());
|
||||
myDaoConfig.setUniqueIndexesCheckedBeforeSave(new DaoConfig().isUniqueIndexesCheckedBeforeSave());
|
||||
}
|
||||
|
||||
@Before
|
||||
|
@ -118,6 +120,58 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
private void createUniqueObservationSubjectDateCode() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/obs-subject");
|
||||
sp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
sp.setCode("subject");
|
||||
sp.setExpression("Observation.subject");
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
sp.addTarget("Patient");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/obs-effective");
|
||||
sp.setType(Enumerations.SearchParamType.DATE);
|
||||
sp.setCode("date");
|
||||
sp.setExpression("Observation.effective");
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/obs-code");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setCode("code");
|
||||
sp.setExpression("Observation.code");
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/observation-subject-date-code");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Observation");
|
||||
sp.setExpression("Observation.code");
|
||||
sp.addComponent()
|
||||
.setExpression("Observation")
|
||||
.setDefinition(new Reference("SearchParameter/obs-subject"));
|
||||
sp.addComponent()
|
||||
.setExpression("Observation")
|
||||
.setDefinition(new Reference("SearchParameter/obs-effective"));
|
||||
sp.addComponent()
|
||||
.setExpression("Observation")
|
||||
.setDefinition(new Reference("SearchParameter/obs-code"));
|
||||
sp.addExtension()
|
||||
.setUrl(JpaConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectUniqueSearchParams() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
@ -131,9 +185,61 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
assertEquals("gender", params.get(0).getCompositeOf().get(1).getName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateUniqueValuesAreReIndexed() {
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setActive(true);
|
||||
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
|
||||
/*
|
||||
* Both of the following resources will match the unique index we'll
|
||||
* create afterward. So we can create them both, but then when we create
|
||||
* the unique index that matches them both that's a problem...
|
||||
*/
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("foo").setCode("bar");
|
||||
obs.setSubject(new Reference(pt1.getIdElement().toUnqualifiedVersionless().getValue()));
|
||||
obs.setEffective(new DateTimeType("2011-01-01"));
|
||||
IIdType id2 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
|
||||
|
||||
obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("foo").setCode("bar");
|
||||
obs.setSubject(new Reference(pt1.getIdElement().toUnqualifiedVersionless().getValue()));
|
||||
obs.setEffective(new DateTimeType("2011-01-01"));
|
||||
IIdType id3 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
|
||||
|
||||
ourLog.info("ID1: {} - ID2: {} - ID3: {}", id1, id2, id3);
|
||||
|
||||
createUniqueObservationSubjectDateCode();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Observation/" + id2.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||
|
||||
myResourceIndexedCompositeStringUniqueDao.deleteAll();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Observation/" + id2.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDuplicateUniqueValuesAreRejected() {
|
||||
public void testDuplicateUniqueValuesAreRejectedWithChecking_TestingDisabled() {
|
||||
myDaoConfig.setUniqueIndexesCheckedBeforeSave(false);
|
||||
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
|
@ -147,26 +253,10 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
} catch (JpaSystemException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
|
||||
|
||||
pt2 = new Patient();
|
||||
pt2.setId(id2);
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt2.setBirthDateElement(new DateType("2011-01-01"));
|
||||
try {
|
||||
myPatientDao.update(pt2);
|
||||
fail();
|
||||
} catch (JpaSystemException e) {
|
||||
// good
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreIndexed_DateAndToken() {
|
||||
public void testDuplicateUniqueValuesAreRejectedWithChecking_TestingEnabled() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
|
@ -174,10 +264,12 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(1, uniques.size());
|
||||
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale", uniques.get(0).getIndexString());
|
||||
try {
|
||||
myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
fail();
|
||||
} catch (PreconditionFailedException e) {
|
||||
assertEquals("Can not create resource of type Patient as it would create a duplicate index matching query: Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale (existing index belongs to Patient/" + id1.getIdPart() + ")", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -204,7 +296,7 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
assertEquals(SearchBuilder.HandlerTypeEnum.UNIQUE_INDEX, SearchBuilder.getLastHandlerMechanismForUnitTest());
|
||||
}
|
||||
|
||||
@Test
|
||||
@Test
|
||||
public void testSearchUsingUniqueComposite() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
|
@ -255,6 +347,227 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
private void createUniqueIndexCoverageBeneficiary() {
|
||||
SearchParameter sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/coverage-beneficiary");
|
||||
sp.setCode("beneficiary");
|
||||
sp.setExpression("Coverage.beneficiary");
|
||||
sp.setType(Enumerations.SearchParamType.REFERENCE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Coverage");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/coverage-identifier");
|
||||
sp.setCode("identifier");
|
||||
sp.setExpression("Coverage.identifier");
|
||||
sp.setType(Enumerations.SearchParamType.TOKEN);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Coverage");
|
||||
mySearchParameterDao.update(sp);
|
||||
|
||||
sp = new SearchParameter();
|
||||
sp.setId("SearchParameter/coverage-beneficiary-identifier");
|
||||
sp.setCode("coverage-beneficiary-identifier");
|
||||
sp.setExpression("Coverage.beneficiary");
|
||||
sp.setType(Enumerations.SearchParamType.COMPOSITE);
|
||||
sp.setStatus(PublicationStatus.ACTIVE);
|
||||
sp.addBase("Coverage");
|
||||
sp.addComponent()
|
||||
.setExpression("Coverage")
|
||||
.setDefinition(new Reference("/SearchParameter/coverage-beneficiary"));
|
||||
sp.addComponent()
|
||||
.setExpression("Coverage")
|
||||
.setDefinition(new Reference("/SearchParameter/coverage-identifier"));
|
||||
sp.addExtension()
|
||||
.setUrl(JpaConstants.EXT_SP_UNIQUE)
|
||||
.setValue(new BooleanType(true));
|
||||
mySearchParameterDao.update(sp);
|
||||
mySearchParamRegsitry.forceRefresh();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexTransactionWithMatchUrl() {
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt2.setBirthDateElement(new DateType("2011-01-02"));
|
||||
IIdType id2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
|
||||
|
||||
Coverage cov = new Coverage();
|
||||
cov.getBeneficiary().setReference(id2.getValue());
|
||||
cov.addIdentifier().setSystem("urn:foo:bar").setValue("123");
|
||||
IIdType id3 = myCoverageDao.create(cov).getId().toUnqualifiedVersionless();
|
||||
|
||||
createUniqueIndexCoverageBeneficiary();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Coverage/" + id3.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Coverage?beneficiary=Patient%2F" + id2.getIdPart() + "&identifier=urn%3Afoo%3Abar%7C123", uniques.get(0).getIndexString());
|
||||
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIndexTransactionWithMatchUrl2() {
|
||||
createUniqueIndexCoverageBeneficiary();
|
||||
|
||||
String input = "{\n" +
|
||||
" \"resourceType\": \"Bundle\",\n" +
|
||||
" \"type\": \"transaction\",\n" +
|
||||
" \"entry\": [\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\": \"urn:uuid:d2a46176-8e15-405d-bbda-baea1a9dc7f3\",\n" +
|
||||
" \"resource\": {\n" +
|
||||
" \"resourceType\": \"Patient\",\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"use\": \"official\",\n" +
|
||||
" \"type\": {\n" +
|
||||
" \"coding\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"http://hl7.org/fhir/v2/0203\",\n" +
|
||||
" \"code\": \"MR\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"system\": \"FOOORG:FOOSITE:patientid:MR:R\",\n" +
|
||||
" \"value\": \"007811959\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"request\": {\n" +
|
||||
" \"method\": \"PUT\",\n" +
|
||||
" \"url\": \"/Patient?identifier=FOOORG%3AFOOSITE%3Apatientid%3AMR%3AR%7C007811959%2CFOOORG%3AFOOSITE%3Apatientid%3AMR%3AB%7C000929990%2CFOOORG%3AFOOSITE%3Apatientid%3API%3APH%7C00589363%2Chttp%3A%2F%2Fhl7.org%2Ffhir%2Fsid%2Fus-ssn%7C657-01-8133\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\": \"urn:uuid:b58ff639-11d1-4dac-942f-abf4f9a625d7\",\n" +
|
||||
" \"resource\": {\n" +
|
||||
" \"resourceType\": \"Coverage\",\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"FOOORG:FOOSITE:coverage:planId\",\n" +
|
||||
" \"value\": \"0403-010101\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"beneficiary\": {\n" +
|
||||
" \"reference\": \"urn:uuid:d2a46176-8e15-405d-bbda-baea1a9dc7f3\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" \"request\": {\n" +
|
||||
" \"method\": \"PUT\",\n" +
|
||||
" \"url\": \"/Coverage?beneficiary=urn%3Auuid%3Ad2a46176-8e15-405d-bbda-baea1a9dc7f3&identifier=FOOORG%3AFOOSITE%3Acoverage%3AplanId%7C0403-010101\"\n" +
|
||||
" }\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"fullUrl\": \"urn:uuid:13f5da1a-6601-4c1a-82c9-41527be23fa0\",\n" +
|
||||
" \"resource\": {\n" +
|
||||
" \"resourceType\": \"Coverage\",\n" +
|
||||
" \"contained\": [\n" +
|
||||
" {\n" +
|
||||
" \"resourceType\": \"RelatedPerson\",\n" +
|
||||
" \"id\": \"1\",\n" +
|
||||
" \"name\": [\n" +
|
||||
" {\n" +
|
||||
" \"family\": \"SMITH\",\n" +
|
||||
" \"given\": [\n" +
|
||||
" \"FAKER\"\n" +
|
||||
" ]\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" {\n" +
|
||||
" \"resourceType\": \"Organization\",\n" +
|
||||
" \"id\": \"2\",\n" +
|
||||
" \"name\": \"MEDICAID\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"identifier\": [\n" +
|
||||
" {\n" +
|
||||
" \"system\": \"FOOORG:FOOSITE:coverage:planId\",\n" +
|
||||
" \"value\": \"0404-010101\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"policyHolder\": {\n" +
|
||||
" \"reference\": \"#1\"\n" +
|
||||
" },\n" +
|
||||
" \"beneficiary\": {\n" +
|
||||
" \"reference\": \"urn:uuid:d2a46176-8e15-405d-bbda-baea1a9dc7f3\"\n" +
|
||||
" },\n" +
|
||||
" \"payor\": [\n" +
|
||||
" {\n" +
|
||||
" \"reference\": \"#2\"\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
" },\n" +
|
||||
" \"request\": {\n" +
|
||||
" \"method\": \"PUT\",\n" +
|
||||
" \"url\": \"/Coverage?beneficiary=urn%3Auuid%3Ad2a46176-8e15-405d-bbda-baea1a9dc7f3&identifier=FOOORG%3AFOOSITE%3Acoverage%3AplanId%7C0404-010101\"\n" +
|
||||
" }\n" +
|
||||
" }\n" +
|
||||
" ]\n" +
|
||||
"}";
|
||||
|
||||
Bundle inputBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(inputBundle));
|
||||
mySystemDao.transaction(mySrd, inputBundle);
|
||||
|
||||
inputBundle = myFhirCtx.newJsonParser().parseResource(Bundle.class, input);
|
||||
mySystemDao.transaction(mySrd, inputBundle);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreIndexed_DateAndToken() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
pt1.setBirthDateElement(new DateType("2011-01-01"));
|
||||
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Patient?birthdate=2011-01-01&gender=http%3A%2F%2Fhl7.org%2Ffhir%2Fadministrative-gender%7Cmale", uniques.get(0).getIndexString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreIndexed_RefAndDateAndToken() {
|
||||
createUniqueObservationSubjectDateCode();
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 0, uniques.size());
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setActive(true);
|
||||
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("foo").setCode("bar");
|
||||
obs.setSubject(new Reference(pt1.getIdElement().toUnqualifiedVersionless().getValue()));
|
||||
obs.setEffective(new DateTimeType("2011-01-01"));
|
||||
IIdType id2 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setActive(false);
|
||||
IIdType id3 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
|
||||
ourLog.info("ID1: {} - ID2: {} - ID3: {}", id1, id2, id3);
|
||||
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Observation/" + id2.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreIndexed_StringAndReference() {
|
||||
createUniqueNameAndManagingOrganizationSps();
|
||||
|
@ -287,6 +600,219 @@ public class FhirResourceDaoR4UniqueSearchParamTest extends BaseJpaR4Test {
|
|||
assertEquals("Patient?name=GIVEN2&organization=Organization%2FORG", uniques.get(2).getIndexString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreIndexed_StringAndReference_UsingConditional() {
|
||||
createUniqueNameAndManagingOrganizationSps();
|
||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setId("Organization/ORG");
|
||||
org.setName("ORG");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("FAMILY1");
|
||||
pt1.setManagingOrganization(new Reference("Organization/ORG"));
|
||||
IIdType id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization.name=ORG").getId().toUnqualifiedVersionless();
|
||||
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(1, uniques.size());
|
||||
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Patient?name=FAMILY1&organization=Organization%2FORG", uniques.get(0).getIndexString());
|
||||
|
||||
// Again
|
||||
|
||||
pt1 = new Patient();
|
||||
pt1.addName().setFamily("FAMILY1");
|
||||
pt1.setManagingOrganization(new Reference("Organization/ORG"));
|
||||
id1 = myPatientDao.update(pt1, "Patient?name=FAMILY1&organization.name=ORG").getId().toUnqualifiedVersionless();
|
||||
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(1, uniques.size());
|
||||
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Patient?name=FAMILY1&organization=Organization%2FORG", uniques.get(0).getIndexString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreIndexed_StringAndReference_UsingConditionalInTransaction() {
|
||||
createUniqueNameAndManagingOrganizationSps();
|
||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setId("Organization/ORG");
|
||||
org.setName("ORG");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||
|
||||
String orgId = "urn:uuid:" + UUID.randomUUID().toString();
|
||||
org = new Organization();
|
||||
org.setName("ORG");
|
||||
bundle
|
||||
.addEntry()
|
||||
.setResource(org)
|
||||
.setFullUrl(orgId)
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.PUT)
|
||||
.setUrl("/Organization?name=ORG");
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.addName().setFamily("FAMILY1");
|
||||
pt1.setManagingOrganization(new Reference(orgId));
|
||||
bundle
|
||||
.addEntry()
|
||||
.setResource(pt1)
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.PUT)
|
||||
.setUrl("/Patient?name=FAMILY1&organization=" + orgId.replace(":", "%3A"));
|
||||
|
||||
Bundle resp = mySystemDao.transaction(mySrd, bundle);
|
||||
|
||||
IIdType id1 = new IdType(resp.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(1, uniques.size());
|
||||
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Patient?name=FAMILY1&organization=Organization%2FORG", uniques.get(0).getIndexString());
|
||||
|
||||
// Again
|
||||
|
||||
bundle = new Bundle();
|
||||
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||
|
||||
orgId = IdType.newRandomUuid().getValue();
|
||||
org = new Organization();
|
||||
org.setName("ORG");
|
||||
bundle
|
||||
.addEntry()
|
||||
.setResource(org)
|
||||
.setFullUrl(orgId)
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.PUT)
|
||||
.setUrl("/Organization?name=ORG");
|
||||
|
||||
pt1 = new Patient();
|
||||
pt1.addName().setFamily("FAMILY1");
|
||||
pt1.setManagingOrganization(new Reference(orgId));
|
||||
bundle
|
||||
.addEntry()
|
||||
.setResource(pt1)
|
||||
.getRequest()
|
||||
.setMethod(Bundle.HTTPVerb.PUT)
|
||||
.setUrl("/Patient?name=FAMILY1&organization=" + orgId);
|
||||
|
||||
resp = mySystemDao.transaction(mySrd, bundle);
|
||||
|
||||
id1 = new IdType(resp.getEntry().get(1).getResponse().getLocation());
|
||||
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(1, uniques.size());
|
||||
assertEquals("Patient/" + id1.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Patient?name=FAMILY1&organization=Organization%2FORG", uniques.get(0).getIndexString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreNotIndexedIfNotAllParamsAreFound_DateAndToken() {
|
||||
createUniqueBirthdateAndGenderSps();
|
||||
|
||||
Patient pt;
|
||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
||||
|
||||
pt = new Patient();
|
||||
pt.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
myPatientDao.create(pt).getId().toUnqualifiedVersionless();
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 0, uniques.size());
|
||||
|
||||
pt = new Patient();
|
||||
myPatientDao.create(pt).getId().toUnqualifiedVersionless();
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 0, uniques.size());
|
||||
|
||||
pt = new Patient();
|
||||
pt.setBirthDateElement(new DateType());
|
||||
pt.setGender(Enumerations.AdministrativeGender.MALE);
|
||||
myPatientDao.create(pt).getId().toUnqualifiedVersionless();
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 0, uniques.size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreNotIndexedIfNotAllParamsAreFound_StringAndReference() {
|
||||
createUniqueNameAndManagingOrganizationSps();
|
||||
|
||||
Organization org = new Organization();
|
||||
org.setId("Organization/ORG");
|
||||
org.setName("ORG");
|
||||
myOrganizationDao.update(org);
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques;
|
||||
Patient pt;
|
||||
|
||||
pt = new Patient();
|
||||
pt.setManagingOrganization(new Reference("Organization/ORG"));
|
||||
myPatientDao.create(pt).getId().toUnqualifiedVersionless();
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 0, uniques.size());
|
||||
|
||||
pt = new Patient();
|
||||
pt.addName()
|
||||
.setFamily("FAMILY1")
|
||||
.addGiven("GIVEN1")
|
||||
.addGiven("GIVEN2")
|
||||
.addGiven("GIVEN2"); // GIVEN2 happens twice
|
||||
myPatientDao.create(pt).getId().toUnqualifiedVersionless();
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 0, uniques.size());
|
||||
|
||||
pt = new Patient();
|
||||
pt.setActive(true);
|
||||
myPatientDao.create(pt).getId().toUnqualifiedVersionless();
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 0, uniques.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUniqueValuesAreReIndexed() {
|
||||
createUniqueObservationSubjectDateCode();
|
||||
|
||||
Patient pt1 = new Patient();
|
||||
pt1.setActive(true);
|
||||
IIdType id1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
|
||||
Observation obs = new Observation();
|
||||
obs.getCode().addCoding().setSystem("foo").setCode("bar");
|
||||
obs.setSubject(new Reference(pt1.getIdElement().toUnqualifiedVersionless().getValue()));
|
||||
obs.setEffective(new DateTimeType("2011-01-01"));
|
||||
IIdType id2 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
|
||||
|
||||
Patient pt2 = new Patient();
|
||||
pt2.setActive(false);
|
||||
myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
|
||||
List<ResourceIndexedCompositeStringUnique> uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Observation/" + id2.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||
|
||||
myResourceIndexedCompositeStringUniqueDao.deleteAll();
|
||||
|
||||
mySystemDao.markAllResourcesForReindexing();
|
||||
mySystemDao.performReindexingPass(1000);
|
||||
|
||||
uniques = myResourceIndexedCompositeStringUniqueDao.findAll();
|
||||
assertEquals(uniques.toString(), 1, uniques.size());
|
||||
assertEquals("Observation/" + id2.getIdPart(), uniques.get(0).getResource().getIdDt().toUnqualifiedVersionless().getValue());
|
||||
assertEquals("Observation?code=foo%7Cbar&date=2011-01-01&subject=Patient%2F" + id1.getIdPart(), uniques.get(0).getIndexString());
|
||||
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() {
|
||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||
|
|
|
@ -362,6 +362,17 @@ public class SystemProviderR4Test extends BaseJpaR4Test {
|
|||
} finally {
|
||||
IOUtils.closeQuietly(http);;
|
||||
}
|
||||
|
||||
get = new HttpGet(ourServerBase + "/$perform-reindexing-pass");
|
||||
http = ourHttpClient.execute(get);
|
||||
try {
|
||||
String output = IOUtils.toString(http.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
ourLog.info(output);
|
||||
assertEquals(200, http.getStatusLine().getStatusCode());
|
||||
} finally {
|
||||
IOUtils.closeQuietly(http);;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Transactional(propagation = Propagation.NEVER)
|
||||
|
|
|
@ -281,11 +281,11 @@ public class RestHookTestDstu2Test extends BaseResourceProviderDstu2Test {
|
|||
}
|
||||
|
||||
public static void waitForQueueToDrain(BaseSubscriptionInterceptor theRestHookSubscriptionInterceptor) throws InterruptedException {
|
||||
ourLog.info("QUEUE HAS {} ITEMS", theRestHookSubscriptionInterceptor.getExecutorQueueForUnitTests().size());
|
||||
while (theRestHookSubscriptionInterceptor.getExecutorQueueForUnitTests().size() > 0) {
|
||||
ourLog.info("QUEUE HAS {} ITEMS", theRestHookSubscriptionInterceptor.getExecutorQueueSizeForUnitTests());
|
||||
while (theRestHookSubscriptionInterceptor.getExecutorQueueSizeForUnitTests() > 0) {
|
||||
Thread.sleep(50);
|
||||
}
|
||||
ourLog.info("QUEUE HAS {} ITEMS", theRestHookSubscriptionInterceptor.getExecutorQueueForUnitTests().size());
|
||||
ourLog.info("QUEUE HAS {} ITEMS", theRestHookSubscriptionInterceptor.getExecutorQueueSizeForUnitTests());
|
||||
}
|
||||
|
||||
private void waitForQueueToDrain() throws InterruptedException {
|
||||
|
|
|
@ -84,11 +84,11 @@ public class RestHookTestWithInterceptorRegisteredToDaoConfigR4Test extends Base
|
|||
}
|
||||
|
||||
private void waitForQueueToDrain() throws InterruptedException {
|
||||
ourLog.info("QUEUE HAS {} ITEMS", getRestHookSubscriptionInterceptor().getExecutorQueueForUnitTests().size());
|
||||
while (getRestHookSubscriptionInterceptor().getExecutorQueueForUnitTests().size() > 0) {
|
||||
ourLog.info("QUEUE HAS {} ITEMS", getRestHookSubscriptionInterceptor().getExecutorQueueSizeForUnitTests());
|
||||
while (getRestHookSubscriptionInterceptor().getExecutorQueueSizeForUnitTests() > 0) {
|
||||
Thread.sleep(250);
|
||||
}
|
||||
ourLog.info("QUEUE HAS {} ITEMS", getRestHookSubscriptionInterceptor().getExecutorQueueForUnitTests().size());
|
||||
ourLog.info("QUEUE HAS {} ITEMS", getRestHookSubscriptionInterceptor().getExecutorQueueSizeForUnitTests());
|
||||
}
|
||||
|
||||
private Observation sendObservation(String code, String system) throws InterruptedException {
|
||||
|
|
|
@ -3,10 +3,12 @@ package ca.uhn.fhir.jpa.util;
|
|||
import static org.hamcrest.Matchers.greaterThan;
|
||||
import static org.hamcrest.Matchers.lessThan;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.apache.commons.lang3.time.DateUtils;
|
||||
import org.junit.Test;
|
||||
|
||||
public class StopWatchTest {
|
||||
|
@ -46,4 +48,14 @@ public class StopWatchTest {
|
|||
assertThat(string, startsWith("00:00"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFormatMillis() throws Exception {
|
||||
assertEquals("00:00:01.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_SECOND));
|
||||
assertEquals("00:01:00.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_MINUTE));
|
||||
assertEquals("01:00:00.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_HOUR));
|
||||
assertEquals("1d00:00:00.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_DAY));
|
||||
assertEquals("2d00:00:00.000", StopWatch.formatMillis(DateUtils.MILLIS_PER_DAY*2));
|
||||
assertEquals("2d00:00:00.001", StopWatch.formatMillis((DateUtils.MILLIS_PER_DAY*2)+1));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,12 +44,34 @@ delete from hfj_forced_id where resource_pid = 16940;
|
|||
delete from hfj_resource where res_id = 16940;
|
||||
|
||||
|
||||
# Drop all tables
|
||||
drop table hfj_history_tag cascade constraints;
|
||||
drop table hfj_res_ver cascade constraints;
|
||||
drop table hfj_forced_id cascade constraints;
|
||||
drop table hfj_res_link cascade constraints;
|
||||
drop table hfj_res_link cascade constraints;
|
||||
drop table hfj_spidx_coords cascade constraints;
|
||||
drop table hfj_spidx_date cascade constraints;
|
||||
drop table hfj_spidx_number cascade constraints;
|
||||
drop table hfj_spidx_quantity cascade constraints;
|
||||
drop table hfj_spidx_string cascade constraints;
|
||||
drop table hfj_spidx_token cascade constraints;
|
||||
drop table hfj_spidx_uri cascade constraints;
|
||||
drop table hfj_res_tag cascade constraints;
|
||||
drop table hfj_search_result cascade constraints;
|
||||
drop table hfj_res_param_present cascade constraints;
|
||||
drop table hfj_resource cascade constraints;
|
||||
drop table hfj_idx_cmp_string_uniq cascade constraints;
|
||||
drop table hfj_search cascade constraints;
|
||||
drop table hfj_search_include cascade constraints;
|
||||
drop table hfj_search_parm cascade constraints;
|
||||
drop table hfj_subscription cascade constraints;
|
||||
drop table hfj_subscription_flag_res cascade constraints;
|
||||
drop table hfj_tag_def cascade constraints;
|
||||
drop table trm_codesystem cascade constraints;
|
||||
drop table trm_codesystem_var cascade constraints;
|
||||
drop table trm_concept cascade constraints;
|
||||
drop table trm_concept_pc_link cascade constraints;
|
||||
drop table trm_concept_property cascade constraints;
|
||||
|
||||
|
||||
delete from hfj_res_link where src_resource_id in ( 156618, 1092 , 1114 , 1139 , 1140 , 1141, 1142 , 1143 , 1144 , 1146 , 1147, 1148, 1062912, 1062916, 1062918, 1062919, 1062922, 1062929, 1062930, 1062934, 1062939, 1062940, 1062944, 1062949, 1062955, 1062957, 1062958, 1062959, 1062966, 1062969, 1062975, 1062976, 1062979, 1062981, 1062985, 1062987, 1062992, 1063002, 1063005, 1063007, 1063013, 1063016, 1063018, 1063020, 1063022, 1063062, 1063068, 1063075, 1063078, 1063080, 1063083, 1063084, 1063091, 1063095, 1063096, 1063098, 1107579, 1107591, 1107598, 1107761, 1107705, 1107748, 1109361, 1109388, 1109378, 1109399, 1109400, 1109401, 1109403, 1109404, 1109406, 1109409, 1109411, 1109414, 1109417, 1109418, 1109421, 1109427, 1109428, 1109429, 1109431, 1109432, 1109433, 1109891, 1109893, 1109947, 1179553, 1182781, 1182788, 1182791, 1182792, 1182795, 1182798, 1182801, 1182806, 1182811, 1182815) or target_resource_id in ( 156618, 1092 , 1114 , 1139 , 1140 , 1141, 1142 , 1143 , 1144 , 1146 , 1147, 1148, 1062912, 1062916, 1062918, 1062919, 1062922, 1062929, 1062930, 1062934, 1062939, 1062940, 1062944, 1062949, 1062955, 1062957, 1062958, 1062959, 1062966, 1062969, 1062975, 1062976, 1062979, 1062981, 1062985, 1062987, 1062992, 1063002, 1063005, 1063007, 1063013, 1063016, 1063018, 1063020, 1063022, 1063062, 1063068, 1063075, 1063078, 1063080, 1063083, 1063084, 1063091, 1063095, 1063096, 1063098, 1107579, 1107591, 1107598, 1107761, 1107705, 1107748, 1109361, 1109388, 1109378, 1109399, 1109400, 1109401, 1109403, 1109404, 1109406, 1109409, 1109411, 1109414, 1109417, 1109418, 1109421, 1109427, 1109428, 1109429, 1109431, 1109432, 1109433, 1109891, 1109893, 1109947, 1179553, 1182781, 1182788, 1182791, 1182792, 1182795, 1182798, 1182801, 1182806, 1182811, 1182815);
|
||||
delete from hfj_spidx_date where res_id in ( 156618, 1092 , 1114 , 1139 , 1140 , 1141, 1142 , 1143 , 1144 , 1146 , 1147, 1148, 1062912, 1062916, 1062918, 1062919, 1062922, 1062929, 1062930, 1062934, 1062939, 1062940, 1062944, 1062949, 1062955, 1062957, 1062958, 1062959, 1062966, 1062969, 1062975, 1062976, 1062979, 1062981, 1062985, 1062987, 1062992, 1063002, 1063005, 1063007, 1063013, 1063016, 1063018, 1063020, 1063022, 1063062, 1063068, 1063075, 1063078, 1063080, 1063083, 1063084, 1063091, 1063095, 1063096, 1063098, 1107579, 1107591, 1107598, 1107761, 1107705, 1107748, 1109361, 1109388, 1109378, 1109399, 1109400, 1109401, 1109403, 1109404, 1109406, 1109409, 1109411, 1109414, 1109417, 1109418, 1109421, 1109427, 1109428, 1109429, 1109431, 1109432, 1109433, 1109891, 1109893, 1109947, 1179553, 1182781, 1182788, 1182791, 1182792, 1182795, 1182798, 1182801, 1182806, 1182811, 1182815);
|
||||
delete from hfj_spidx_string where res_id in ( 156618, 1092 , 1114 , 1139 , 1140 , 1141, 1142 , 1143 , 1144 , 1146 , 1147, 1148, 1062912, 1062916, 1062918, 1062919, 1062922, 1062929, 1062930, 1062934, 1062939, 1062940, 1062944, 1062949, 1062955, 1062957, 1062958, 1062959, 1062966, 1062969, 1062975, 1062976, 1062979, 1062981, 1062985, 1062987, 1062992, 1063002, 1063005, 1063007, 1063013, 1063016, 1063018, 1063020, 1063022, 1063062, 1063068, 1063075, 1063078, 1063080, 1063083, 1063084, 1063091, 1063095, 1063096, 1063098, 1107579, 1107591, 1107598, 1107761, 1107705, 1107748, 1109361, 1109388, 1109378, 1109399, 1109400, 1109401, 1109403, 1109404, 1109406, 1109409, 1109411, 1109414, 1109417, 1109418, 1109421, 1109427, 1109428, 1109429, 1109431, 1109432, 1109433, 1109891, 1109893, 1109947, 1179553, 1182781, 1182788, 1182791, 1182792, 1182795, 1182798, 1182801, 1182806, 1182811, 1182815);
|
||||
delete from hfj_spidx_token where res_id in ( 156618, 1092 , 1114 , 1139 , 1140 , 1141, 1142 , 1143 , 1144 , 1146 , 1147, 1148, 1062912, 1062916, 1062918, 1062919, 1062922, 1062929, 1062930, 1062934, 1062939, 1062940, 1062944, 1062949, 1062955, 1062957, 1062958, 1062959, 1062966, 1062969, 1062975, 1062976, 1062979, 1062981, 1062985, 1062987, 1062992, 1063002, 1063005, 1063007, 1063013, 1063016, 1063018, 1063020, 1063022, 1063062, 1063068, 1063075, 1063078, 1063080, 1063083, 1063084, 1063091, 1063095, 1063096, 1063098, 1107579, 1107591, 1107598, 1107761, 1107705, 1107748, 1109361, 1109388, 1109378, 1109399, 1109400, 1109401, 1109403, 1109404, 1109406, 1109409, 1109411, 1109414, 1109417, 1109418, 1109421, 1109427, 1109428, 1109429, 1109431, 1109432, 1109433, 1109891, 1109893, 1109947, 1179553, 1182781, 1182788, 1182791, 1182792, 1182795, 1182798, 1182801, 1182806, 1182811, 1182815);
|
||||
delete from hfj_search_result where resource_pid in ( 156618, 1092 , 1114 , 1139 , 1140 , 1141, 1142 , 1143 , 1144 , 1146 , 1147, 1148, 1062912, 1062916, 1062918, 1062919, 1062922, 1062929, 1062930, 1062934, 1062939, 1062940, 1062944, 1062949, 1062955, 1062957, 1062958, 1062959, 1062966, 1062969, 1062975, 1062976, 1062979, 1062981, 1062985, 1062987, 1062992, 1063002, 1063005, 1063007, 1063013, 1063016, 1063018, 1063020, 1063022, 1063062, 1063068, 1063075, 1063078, 1063080, 1063083, 1063084, 1063091, 1063095, 1063096, 1063098, 1107579, 1107591, 1107598, 1107761, 1107705, 1107748, 1109361, 1109388, 1109378, 1109399, 1109400, 1109401, 1109403, 1109404, 1109406, 1109409, 1109411, 1109414, 1109417, 1109418, 1109421, 1109427, 1109428, 1109429, 1109431, 1109432, 1109433, 1109891, 1109893, 1109947, 1179553, 1182781, 1182788, 1182791, 1182792, 1182795, 1182798, 1182801, 1182806, 1182811, 1182815);
|
||||
delete from hfj_resource where res_id in ( 156618, 1092 , 1114 , 1139 , 1140 , 1141, 1142 , 1143 , 1144 , 1146 , 1147, 1148, 1062912, 1062916, 1062918, 1062919, 1062922, 1062929, 1062930, 1062934, 1062939, 1062940, 1062944, 1062949, 1062955, 1062957, 1062958, 1062959, 1062966, 1062969, 1062975, 1062976, 1062979, 1062981, 1062985, 1062987, 1062992, 1063002, 1063005, 1063007, 1063013, 1063016, 1063018, 1063020, 1063022, 1063062, 1063068, 1063075, 1063078, 1063080, 1063083, 1063084, 1063091, 1063095, 1063096, 1063098, 1107579, 1107591, 1107598, 1107761, 1107705, 1107748, 1109361, 1109388, 1109378, 1109399, 1109400, 1109401, 1109403, 1109404, 1109406, 1109409, 1109411, 1109414, 1109417, 1109418, 1109421, 1109427, 1109428, 1109429, 1109431, 1109432, 1109433, 1109891, 1109893, 1109947, 1179553, 1182781, 1182788, 1182791, 1182792, 1182795, 1182798, 1182801, 1182806, 1182811, 1182815);
|
||||
|
||||
|
|
|
@ -1,32 +1,22 @@
|
|||
package org.hl7.fhir.dstu2016may.hapi.validation;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.apache.commons.io.Charsets;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu2016may.model.Bundle;
|
||||
import org.hl7.fhir.dstu2016may.model.*;
|
||||
import org.hl7.fhir.dstu2016may.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.dstu2016may.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu2016may.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.dstu2016may.model.DomainResource;
|
||||
import org.hl7.fhir.dstu2016may.model.OperationOutcome.IssueSeverity;
|
||||
import org.hl7.fhir.dstu2016may.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
|
||||
|
@ -55,6 +45,15 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||
retVal.addAll(myCodeSystems.values());
|
||||
retVal.addAll(myStructureDefinitions.values());
|
||||
retVal.addAll(myValueSets.values());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<StructureDefinition>(provideStructureDefinitionMap(theContext).values());
|
||||
|
@ -219,25 +218,6 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return structureDefinitions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
|
||||
if (cs != null) {
|
||||
boolean caseSensitive = true;
|
||||
if (cs.hasCaseSensitive()) {
|
||||
caseSensitive = cs.getCaseSensitive();
|
||||
}
|
||||
|
||||
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
|
||||
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||
}
|
||||
|
||||
private CodeValidationResult testIfConceptIsInList(String theCode, List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive) {
|
||||
String code = theCode;
|
||||
if (theCaseSensitive == false) {
|
||||
|
@ -269,4 +249,23 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
|
||||
if (cs != null) {
|
||||
boolean caseSensitive = true;
|
||||
if (cs.hasCaseSensitive()) {
|
||||
caseSensitive = cs.getCaseSensitive();
|
||||
}
|
||||
|
||||
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
|
||||
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,6 @@
|
|||
package org.hl7.fhir.dstu2016may.hapi.validation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu2016may.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu2016may.model.StructureDefinition;
|
||||
|
@ -13,7 +9,10 @@ import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetComponent;
|
|||
import org.hl7.fhir.dstu2016may.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* This class is an implementation of {@link IValidationSupport} which may be pre-populated
|
||||
|
@ -29,11 +28,36 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
* Constructor
|
||||
*/
|
||||
public PrePopulatedValidationSupport() {
|
||||
myStructureDefinitions = new HashMap<String,StructureDefinition>();
|
||||
myValueSets = new HashMap<String,ValueSet>();
|
||||
myCodeSystems = new HashMap<String,CodeSystem>();
|
||||
myStructureDefinitions = new HashMap<String, StructureDefinition>();
|
||||
myValueSets = new HashMap<String, ValueSet>();
|
||||
myCodeSystems = new HashMap<String, CodeSystem>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theStructureDefinitions The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||
* values are the resource itself.
|
||||
* @param theValueSets The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theCodeSystems The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
*/
|
||||
public PrePopulatedValidationSupport(Map<String, StructureDefinition> theStructureDefinitions, Map<String, ValueSet> theValueSets, Map<String, CodeSystem> theCodeSystems) {
|
||||
myStructureDefinitions = theStructureDefinitions;
|
||||
myValueSets = theValueSets;
|
||||
myCodeSystems = theCodeSystems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new CodeSystem resource which will be available to the validator. Note that
|
||||
* {@link CodeSystem#getUrl() the URL field) in this resource must contain a value as this
|
||||
* value will be used as the logical URL.
|
||||
*/
|
||||
public void addCodeSystem(CodeSystem theCodeSystem) {
|
||||
Validate.notBlank(theCodeSystem.getUrl(), "theCodeSystem.getUrl() must not return a value");
|
||||
myCodeSystems.put(theCodeSystem.getUrl(), theCodeSystem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new StructureDefinition resource which will be available to the validator. Note that
|
||||
|
@ -55,40 +79,20 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
myValueSets.put(theValueSet.getUrl(), theValueSet);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new CodeSystem resource which will be available to the validator. Note that
|
||||
* {@link CodeSystem#getUrl() the URL field) in this resource must contain a value as this
|
||||
* value will be used as the logical URL.
|
||||
*/
|
||||
public void addCodeSystem(CodeSystem theCodeSystem) {
|
||||
Validate.notBlank(theCodeSystem.getUrl(), "theCodeSystem.getUrl() must not return a value");
|
||||
myCodeSystems.put(theCodeSystem.getUrl(), theCodeSystem);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theStructureDefinitions
|
||||
* The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||
* values are the resource itself.
|
||||
* @param theValueSets
|
||||
* The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theCodeSystems
|
||||
* The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
*/
|
||||
public PrePopulatedValidationSupport(Map<String, StructureDefinition> theStructureDefinitions, Map<String, ValueSet> theValueSets, Map<String, CodeSystem> theCodeSystems) {
|
||||
myStructureDefinitions = theStructureDefinitions;
|
||||
myValueSets = theValueSets;
|
||||
myCodeSystems = theCodeSystems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theContext, ConceptSetComponent theInclude) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||
retVal.addAll(myCodeSystems.values());
|
||||
retVal.addAll(myStructureDefinitions.values());
|
||||
retVal.addAll(myValueSets.values());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<StructureDefinition>(myStructureDefinitions.values());
|
||||
|
|
|
@ -1,19 +1,18 @@
|
|||
package org.hl7.fhir.dstu2016may.hapi.validation;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.dstu2016may.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu2016may.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu2016may.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class ValidationSupportChain implements IValidationSupport {
|
||||
|
||||
|
@ -52,6 +51,32 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
List<IBaseResource> retVal = new ArrayList<>();
|
||||
for (IValidationSupport next : myChain) {
|
||||
List<IBaseResource> candidates = next.fetchAllConformanceResources(theContext);
|
||||
if (candidates != null) {
|
||||
retVal.addAll(candidates);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<StructureDefinition>();
|
||||
Set<String> urls = new HashSet<String>();
|
||||
for (IValidationSupport nextSupport : myChain) {
|
||||
for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) {
|
||||
if (isBlank(next.getUrl()) || urls.add(next.getUrl())) {
|
||||
retVal.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
|
@ -105,18 +130,4 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<StructureDefinition>();
|
||||
Set<String> urls= new HashSet<String>();
|
||||
for (IValidationSupport nextSupport : myChain) {
|
||||
for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) {
|
||||
if (isBlank(next.getUrl()) || urls.add(next.getUrl())) {
|
||||
retVal.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
package org.hl7.fhir.dstu3.hapi.validation;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.apache.commons.io.Charsets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
@ -19,7 +14,11 @@ import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
|||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
|
||||
|
@ -52,6 +51,15 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||
retVal.addAll(myCodeSystems.values());
|
||||
retVal.addAll(myStructureDefinitions.values());
|
||||
retVal.addAll(myValueSets.values());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<StructureDefinition>(provideStructureDefinitionMap(theContext).values());
|
||||
|
@ -195,25 +203,6 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return structureDefinitions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
|
||||
if (cs != null) {
|
||||
boolean caseSensitive = true;
|
||||
if (cs.hasCaseSensitive()) {
|
||||
caseSensitive = cs.getCaseSensitive();
|
||||
}
|
||||
|
||||
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
|
||||
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||
}
|
||||
|
||||
private CodeValidationResult testIfConceptIsInList(String theCode, List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive) {
|
||||
String code = theCode;
|
||||
if (theCaseSensitive == false) {
|
||||
|
@ -245,4 +234,23 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
|
||||
if (cs != null) {
|
||||
boolean caseSensitive = true;
|
||||
if (cs.hasCaseSensitive()) {
|
||||
caseSensitive = cs.getCaseSensitive();
|
||||
}
|
||||
|
||||
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
|
||||
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,19 +1,21 @@
|
|||
package org.hl7.fhir.dstu3.hapi.validation;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.MetadataResource;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.dstu3.model.*;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* This class is an implementation of {@link IValidationSupport} which may be pre-populated
|
||||
|
@ -29,23 +31,20 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
* Constructor
|
||||
*/
|
||||
public PrePopulatedValidationSupport() {
|
||||
myStructureDefinitions = new HashMap<String, StructureDefinition>();
|
||||
myValueSets = new HashMap<String, ValueSet>();
|
||||
myCodeSystems = new HashMap<String, CodeSystem>();
|
||||
myStructureDefinitions = new HashMap<>();
|
||||
myValueSets = new HashMap<>();
|
||||
myCodeSystems = new HashMap<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theStructureDefinitions
|
||||
* The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||
* values are the resource itself.
|
||||
* @param theValueSets
|
||||
* The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theCodeSystems
|
||||
* The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theStructureDefinitions The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||
* values are the resource itself.
|
||||
* @param theValueSets The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theCodeSystems The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
*/
|
||||
public PrePopulatedValidationSupport(Map<String, StructureDefinition> theStructureDefinitions, Map<String, ValueSet> theValueSets, Map<String, CodeSystem> theCodeSystems) {
|
||||
myStructureDefinitions = theStructureDefinitions;
|
||||
|
@ -131,6 +130,15 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||
retVal.addAll(myCodeSystems.values());
|
||||
retVal.addAll(myStructureDefinitions.values());
|
||||
retVal.addAll(myValueSets.values());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<StructureDefinition>(myStructureDefinitions.values());
|
||||
|
|
|
@ -1,131 +1,143 @@
|
|||
package org.hl7.fhir.dstu3.hapi.validation;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.dstu3.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class ValidationSupportChain implements IValidationSupport {
|
||||
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationSupportChain.class);
|
||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ValidationSupportChain.class);
|
||||
|
||||
private List<IValidationSupport> myChain;
|
||||
private List<IValidationSupport> myChain;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain() {
|
||||
myChain = new ArrayList<IValidationSupport>();
|
||||
}
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain() {
|
||||
myChain = new ArrayList<IValidationSupport>();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain(IValidationSupport... theValidationSupportModules) {
|
||||
this();
|
||||
for (IValidationSupport next : theValidationSupportModules) {
|
||||
if (next != null) {
|
||||
myChain.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public ValidationSupportChain(IValidationSupport... theValidationSupportModules) {
|
||||
this();
|
||||
for (IValidationSupport next : theValidationSupportModules) {
|
||||
if (next != null) {
|
||||
myChain.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void addValidationSupport(IValidationSupport theValidationSupport) {
|
||||
myChain.add(theValidationSupport);
|
||||
}
|
||||
public void addValidationSupport(IValidationSupport theValidationSupport) {
|
||||
myChain.add(theValidationSupport);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) {
|
||||
return next.expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
}
|
||||
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
@Override
|
||||
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theInclude.getSystem())) {
|
||||
return next.expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
}
|
||||
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
List<IBaseResource> retVal = new ArrayList<>();
|
||||
for (IValidationSupport next : myChain) {
|
||||
List<IBaseResource> candidates = next.fetchAllConformanceResources(theContext);
|
||||
if (candidates != null) {
|
||||
retVal.addAll(candidates);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
T retVal = next.fetchResource(theContext, theClass, theUri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<StructureDefinition>();
|
||||
Set<String> urls = new HashSet<String>();
|
||||
for (IValidationSupport nextSupport : myChain) {
|
||||
for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) {
|
||||
if (isBlank(next.getUrl()) || urls.add(next.getUrl())) {
|
||||
retVal.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
StructureDefinition retVal = next.fetchStructureDefinition(theCtx, theUrl);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Override
|
||||
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
T retVal = next.fetchResource(theContext, theClass, theUri);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||
@Override
|
||||
public StructureDefinition fetchStructureDefinition(FhirContext theCtx, String theUrl) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
StructureDefinition retVal = next.fetchStructureDefinition(theCtx, theUrl);
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
ourLog.info("Validating code {} in chain with {} items", theCode, myChain.size());
|
||||
@Override
|
||||
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theSystem)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theCodeSystem)) {
|
||||
CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
ourLog.info("Chain item {} returned outcome {}", next, result.isOk());
|
||||
return result;
|
||||
} else {
|
||||
ourLog.info("Chain item {} does not support code system {}", next, theCodeSystem);
|
||||
}
|
||||
}
|
||||
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
}
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
|
||||
|
||||
ourLog.info("Validating code {} in chain with {} items", theCode, myChain.size());
|
||||
|
||||
for (IValidationSupport next : myChain) {
|
||||
if (next.isCodeSystemSupported(theCtx, theCodeSystem)) {
|
||||
CodeValidationResult result = next.validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
ourLog.info("Chain item {} returned outcome {}", next, result.isOk());
|
||||
return result;
|
||||
} else {
|
||||
ourLog.info("Chain item {} does not support code system {}", next, theCodeSystem);
|
||||
}
|
||||
}
|
||||
return myChain.get(0).validateCode(theCtx, theCodeSystem, theCode, theDisplay);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
ArrayList<StructureDefinition> retVal = new ArrayList<StructureDefinition>();
|
||||
Set<String> urls= new HashSet<String>();
|
||||
for (IValidationSupport nextSupport : myChain) {
|
||||
for (StructureDefinition next : nextSupport.fetchAllStructureDefinitions(theContext)) {
|
||||
if (isBlank(next.getUrl()) || urls.add(next.getUrl())) {
|
||||
retVal.add(next);
|
||||
}
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.apache.commons.io.Charsets;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
|
@ -14,10 +9,16 @@ import org.hl7.fhir.r4.model.*;
|
|||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.CodeSystemContentMode;
|
||||
import org.hl7.fhir.r4.model.CodeSystem.ConceptDefinitionComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.*;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptReferenceComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
||||
import org.hl7.fhir.utilities.validation.ValidationMessage.IssueSeverity;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
public class DefaultProfileValidationSupport implements IValidationSupport {
|
||||
|
||||
|
@ -51,10 +52,20 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<StructureDefinition>(provideStructureDefinitionMap(theContext).values());
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||
retVal.addAll(myCodeSystems.values());
|
||||
retVal.addAll(myStructureDefinitions.values());
|
||||
retVal.addAll(myValueSets.values());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<>(provideStructureDefinitionMap(theContext).values());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theContext, String theSystem) {
|
||||
return (CodeSystem) fetchCodeSystemOrValueSet(theContext, theSystem, true);
|
||||
|
@ -65,8 +76,8 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
Map<String, CodeSystem> codeSystems = myCodeSystems;
|
||||
Map<String, ValueSet> valueSets = myValueSets;
|
||||
if (codeSystems == null || valueSets == null) {
|
||||
codeSystems = new HashMap<String, CodeSystem>();
|
||||
valueSets = new HashMap<String, ValueSet>();
|
||||
codeSystems = new HashMap<>();
|
||||
valueSets = new HashMap<>();
|
||||
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r4/model/valueset/valuesets.xml");
|
||||
loadCodeSystems(theContext, codeSystems, valueSets, "/org/hl7/fhir/r4/model/valueset/v2-tables.xml");
|
||||
|
@ -193,25 +204,6 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return structureDefinitions;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
|
||||
if (cs != null) {
|
||||
boolean caseSensitive = true;
|
||||
if (cs.hasCaseSensitive()) {
|
||||
caseSensitive = cs.getCaseSensitive();
|
||||
}
|
||||
|
||||
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
|
||||
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||
}
|
||||
|
||||
private CodeValidationResult testIfConceptIsInList(String theCode, List<ConceptDefinitionComponent> conceptList, boolean theCaseSensitive) {
|
||||
String code = theCode;
|
||||
if (theCaseSensitive == false) {
|
||||
|
@ -243,4 +235,23 @@ public class DefaultProfileValidationSupport implements IValidationSupport {
|
|||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeValidationResult validateCode(FhirContext theContext, String theCodeSystem, String theCode, String theDisplay) {
|
||||
CodeSystem cs = fetchCodeSystem(theContext, theCodeSystem);
|
||||
if (cs != null) {
|
||||
boolean caseSensitive = true;
|
||||
if (cs.hasCaseSensitive()) {
|
||||
caseSensitive = cs.getCaseSensitive();
|
||||
}
|
||||
|
||||
CodeValidationResult retVal = testIfConceptIsInList(theCode, cs.getConcept(), caseSensitive);
|
||||
|
||||
if (retVal != null) {
|
||||
return retVal;
|
||||
}
|
||||
}
|
||||
|
||||
return new CodeValidationResult(IssueSeverity.WARNING, "Unknown code: " + theCodeSystem + " / " + theCode);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,16 +1,21 @@
|
|||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.MetadataResource;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/**
|
||||
* This class is an implementation of {@link IValidationSupport} which may be pre-populated
|
||||
|
@ -26,23 +31,21 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
* Constructor
|
||||
*/
|
||||
public PrePopulatedValidationSupport() {
|
||||
myStructureDefinitions = new HashMap<String, StructureDefinition>();
|
||||
myValueSets = new HashMap<String, ValueSet>();
|
||||
myCodeSystems = new HashMap<String, CodeSystem>();
|
||||
myStructureDefinitions = new HashMap<>();
|
||||
myValueSets = new HashMap<>();
|
||||
myCodeSystems = new HashMap<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param theStructureDefinitions
|
||||
* The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||
* values are the resource itself.
|
||||
* @param theValueSets
|
||||
* The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theCodeSystems
|
||||
* The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theStructureDefinitions The StructureDefinitions to be returned by this module. Keys are the logical URL for the resource, and
|
||||
* values are the resource itself.
|
||||
* @param theValueSets The ValueSets to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
* @param theCodeSystems The CodeSystems to be returned by this module. Keys are the logical URL for the resource, and values are
|
||||
* the resource itself.
|
||||
*/
|
||||
public PrePopulatedValidationSupport(Map<String, StructureDefinition> theStructureDefinitions, Map<String, ValueSet> theValueSets, Map<String, CodeSystem> theCodeSystems) {
|
||||
myStructureDefinitions = theStructureDefinitions;
|
||||
|
@ -128,6 +131,15 @@ public class PrePopulatedValidationSupport implements IValidationSupport {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<>();
|
||||
retVal.addAll(myCodeSystems.values());
|
||||
retVal.addAll(myStructureDefinitions.values());
|
||||
retVal.addAll(myValueSets.values());
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<StructureDefinition> fetchAllStructureDefinitions(FhirContext theContext) {
|
||||
return new ArrayList<StructureDefinition>(myStructureDefinitions.values());
|
||||
|
|
|
@ -1,16 +1,18 @@
|
|||
package org.hl7.fhir.r4.hapi.ctx;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.model.CodeSystem;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ConceptSetComponent;
|
||||
import org.hl7.fhir.r4.model.ValueSet.ValueSetExpansionComponent;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
|
||||
public class ValidationSupportChain implements IValidationSupport {
|
||||
|
||||
|
@ -51,7 +53,19 @@ public class ValidationSupportChain implements IValidationSupport {
|
|||
return myChain.get(0).expandValueSet(theCtx, theInclude);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Override
|
||||
public List<IBaseResource> fetchAllConformanceResources(FhirContext theContext) {
|
||||
List<IBaseResource> retVal = new ArrayList<>();
|
||||
for (IValidationSupport next : myChain) {
|
||||
List<IBaseResource> candidates = next.fetchAllConformanceResources(theContext);
|
||||
if (candidates != null) {
|
||||
retVal.addAll(candidates);
|
||||
}
|
||||
}
|
||||
return retVal;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CodeSystem fetchCodeSystem(FhirContext theCtx, String theSystem) {
|
||||
for (IValidationSupport next : myChain) {
|
||||
CodeSystem retVal = next.fetchCodeSystem(theCtx, theSystem);
|
||||
|
|
|
@ -85,7 +85,7 @@ public class LoggingInterceptorTest {
|
|||
System.out.flush();
|
||||
return
|
||||
formattedMessage.contains("Client request: GET http://localhost:" + ourPort + "/Patient/1 HTTP/1.1") ||
|
||||
formattedMessage.contains("Client response: HTTP 200 OK (Location: http://localhost:" + ourPort + "/Patient/1/_history/1)");
|
||||
formattedMessage.contains("Client response: HTTP 200 OK (Patient/1/_history/1)");
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
|
3
pom.xml
3
pom.xml
|
@ -1828,6 +1828,7 @@
|
|||
<module>example-projects/hapi-fhir-base-example-embedded-ws</module>
|
||||
<module>example-projects/hapi-fhir-standalone-overlay-example</module>
|
||||
<module>hapi-fhir-jacoco</module>
|
||||
<module>hapi-fhir-igpacks</module>
|
||||
<!--<module>hapi-fhir-osgi-core</module>-->
|
||||
</modules>
|
||||
</profile>
|
||||
|
@ -1875,6 +1876,4 @@
|
|||
</profile>
|
||||
</profiles>
|
||||
|
||||
<modules>
|
||||
</modules>
|
||||
</project>
|
||||
|
|
Loading…
Reference in New Issue