Add DSTU2.1 resources

This commit is contained in:
jamesagnew 2015-11-29 11:43:09 -05:00
parent 45502ba5ff
commit d47e0e5e77
531 changed files with 1928607 additions and 392 deletions

View File

@ -513,12 +513,19 @@ public class FhirContext {
}
/**
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2}
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2 DSTU 2}
*/
public static FhirContext forDstu2() {
return new FhirContext(FhirVersionEnum.DSTU2);
}
/**
* Creates and returns a new FhirContext with version {@link FhirVersionEnum#DSTU2_1 DSTU 2.1}
*/
public static FhirContext forDstu2_1() {
return new FhirContext(FhirVersionEnum.DSTU2_1);
}
public static FhirContext forDstu2Hl7Org() {
return new FhirContext(FhirVersionEnum.DSTU2_HL7ORG);
}

View File

@ -40,7 +40,9 @@ public enum FhirVersionEnum {
DEV("ca.uhn.fhir.model.dev.FhirDev", null),
DSTU2_HL7ORG("org.hl7.fhir.instance.FhirDstu2Hl7Org", DSTU2);
DSTU2_HL7ORG("org.hl7.fhir.instance.FhirDstu2Hl7Org", DSTU2),
DSTU2_1("ca.uhn.fhir.model.dstu21.FhirDstu21", null);
private final String myVersionClass;

View File

@ -22,10 +22,16 @@ package org.hl7.fhir.instance.model.api;
public interface IBaseCoding {
IBaseCoding setSystem(String theScheme);
String getCode();
String getDisplay();
String getSystem();
IBaseCoding setCode(String theTerm);
IBaseCoding setDisplay(String theLabel);
IBaseCoding setSystem(String theScheme);
}

View File

@ -21,15 +21,28 @@ package org.hl7.fhir.instance.model.api;
*/
import java.util.Date;
import java.util.List;
public interface IBaseMetaType extends ICompositeType {
IBaseCoding addTag();
IBaseMetaType addProfile(String theProfile);
IBaseMetaType setLastUpdated(Date theHeaderDateValue);
IBaseCoding addSecurity();
IBaseCoding addTag();
Date getLastUpdated();
List<? extends IPrimitiveType<String>> getProfile();
List<? extends IBaseCoding> getSecurity();
List<? extends IBaseCoding> getTag();
String getVersionId();
IBaseMetaType setLastUpdated(Date theHeaderDateValue);
IBaseMetaType setVersionId(String theVersionId);
}

View File

@ -39,6 +39,11 @@
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
@ -49,6 +54,11 @@
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>

View File

@ -19,6 +19,8 @@ import org.fusesource.jansi.Ansi.Color;
import org.fusesource.jansi.AnsiConsole;
import org.slf4j.LoggerFactory;
import com.phloc.commons.io.file.FileUtils;
import ca.uhn.fhir.util.VersionUtil;
import ch.qos.logback.classic.LoggerContext;
import ch.qos.logback.classic.joran.JoranConfigurator;
@ -113,6 +115,8 @@ public class App {
System.out.println("------------------------------------------------------------");
System.out.println("\ud83d\udd25 " + ansi().bold() + "HAPI FHIR" + ansi().boldOff() + " " + VersionUtil.getVersion() + " - Command Line Tool");
System.out.println("------------------------------------------------------------");
System.out.println("Max configured JVM memory (Xmx): " + FileUtils.getFileSizeDisplay(Runtime.getRuntime().maxMemory(), 1));
System.out.println("------------------------------------------------------------");
}
public static void main(String[] theArgs) {

View File

@ -5,6 +5,9 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -24,12 +27,15 @@ import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.hl7.fhir.instance.model.api.IBaseResource;
import com.phloc.commons.io.file.FileUtils;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Bundle.EntryRequest;
import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
import ca.uhn.fhir.model.dstu2.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.parser.DataFormatException;
@ -38,7 +44,7 @@ import ca.uhn.fhir.util.ResourceReferenceInfo;
public class ExampleDataUploader extends BaseCommand {
private static final String SPEC_DEFAULT_VERSION = "2015Sep";
private static final String SPEC_DEFAULT_VERSION = "dstu2";
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(ExampleDataUploader.class);
@ -78,21 +84,31 @@ public class ExampleDataUploader extends BaseCommand {
String targetServer = theCommandLine.getOptionValue("t");
if (isBlank(targetServer)) {
throw new ParseException("No target server (-t) specified");
} else if (targetServer.startsWith("http") == false) {
throw new ParseException("Invalid target server specified, must begin with 'http'");
} else if (targetServer.startsWith("http") == false && targetServer.startsWith("file") == false) {
throw new ParseException("Invalid target server specified, must begin with 'http' or 'file'");
}
Integer limit = null;
String limitString = theCommandLine.getOptionValue('l');
if (isNotBlank(limitString)) {
try {
limit = Integer.parseInt(limitString);
limit = Integer.parseInt(limitString);
} catch (NumberFormatException e) {
throw new ParseException("Invalid number for limit (-l) option, must be a number: " + limitString);
}
}
FhirContext ctx = FhirContext.forDstu2();
String specUrl = "http://hl7.org/fhir/" + specVersion + "/examples-json.zip";
FhirContext ctx;
String specUrl;
if (SPEC_DEFAULT_VERSION.equals(specVersion)) {
ctx = FhirContext.forDstu2();
specUrl = "http://hl7.org/fhir/" + specVersion + "/examples-json.zip";
} else if ("dstu2.1".equals(specVersion)) {
ctx = FhirContext.forDstu2_1();
specUrl = "http://hl7-fhir.github.io/examples-json.zip";
} else {
throw new ParseException("Unknown spec version: " + specVersion);
}
ourLog.info("HTTP fetching: {}", specUrl);
@ -103,180 +119,197 @@ public class ExampleDataUploader extends BaseCommand {
if (result.getStatusLine().getStatusCode() != 200) {
throw new CommandFailureException("Got HTTP " + result.getStatusLine().getStatusCode() + " response code loading " + specUrl);
}
byte[] bytes = IOUtils.toByteArray(result.getEntity().getContent());
IOUtils.closeQuietly(result.getEntity().getContent());
ourLog.info("Successfully Loaded example pack ({} bytes)", bytes.length);
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes));
byte[] buffer = new byte[2048];
Bundle bundle = new Bundle();
{
int count = 0;
while (true) {
count++;
if (limit != null && count > limit) {
break;
}
ZipEntry nextEntry = zis.getNextEntry();
if (nextEntry == null) {
break;
}
byte[] inputBytes = IOUtils.toByteArray(result.getEntity().getContent());
IOUtils.closeQuietly(result.getEntity().getContent());
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = zis.read(buffer)) > 0) {
bos.write(buffer, 0, len);
}
byte[] exampleBytes = bos.toByteArray();
String exampleString = new String(exampleBytes, "UTF-8");
ourLog.info("Successfully Loaded example pack ({} bytes)", inputBytes.length);
if (ourLog.isTraceEnabled()) {
ourLog.trace("Next example: " + exampleString);
}
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(inputBytes));
byte[] buffer = new byte[2048];
IBaseResource parsed;
try {
parsed = ctx.newJsonParser().parseResource(exampleString);
} catch (DataFormatException e) {
ourLog.info("FAILED to parse example {}", nextEntry.getName(), e);
continue;
}
ourLog.info("Found example {} - {} - {} chars", nextEntry.getName(), parsed.getClass().getSimpleName(), exampleString.length());
if (parsed instanceof Bundle) {
Bundle b = (Bundle) parsed;
for (Entry nextEntry1 : b.getEntry()) {
if (nextEntry1.getResource() == null) {
continue;
}
if (nextEntry1.getResource() instanceof Bundle) {
continue;
}
if (nextEntry1.getResource() instanceof SearchParameter) {
continue;
}
bundle.addEntry().setRequest(new EntryRequest().setMethod(HTTPVerbEnum.POST)).setResource(nextEntry1.getResource());
int count = 0;
while (true) {
count++;
if (limit != null && count > limit) {
break;
}
} else {
if (parsed instanceof SearchParameter) {
ZipEntry nextEntry = zis.getNextEntry();
if (nextEntry == null) {
break;
}
int len = 0;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while ((len = zis.read(buffer)) > 0) {
bos.write(buffer, 0, len);
}
byte[] exampleBytes = bos.toByteArray();
String exampleString = new String(exampleBytes, "UTF-8");
if (ourLog.isTraceEnabled()) {
ourLog.trace("Next example: " + exampleString);
}
IBaseResource parsed;
try {
parsed = ctx.newJsonParser().parseResource(exampleString);
} catch (DataFormatException e) {
ourLog.info("FAILED to parse example {}", nextEntry.getName(), e);
continue;
}
bundle.addEntry().setRequest(new EntryRequest().setMethod(HTTPVerbEnum.POST)).setResource((IResource) parsed);
}
ourLog.info("Found example {} - {} - {} chars", nextEntry.getName(), parsed.getClass().getSimpleName(), exampleString.length());
}
if (parsed instanceof Bundle) {
Bundle b = (Bundle) parsed;
if (b.getTypeElement().getValueAsEnum() != BundleTypeEnum.DOCUMENT) {
continue;
}
Map<String, Integer> ids = new HashMap<String, Integer>();
Set<String> fullIds = new HashSet<String>();
for (int i = 0; i < bundle.getEntry().size(); i++) {
Entry next = bundle.getEntry().get(i);
// DataElement have giant IDs that seem invalid, need to investigate this..
if ("DataElement".equals(next.getResource().getResourceName()) || "OperationOutcome".equals(next.getResource().getResourceName())
|| "OperationDefinition".equals(next.getResource().getResourceName())) {
ourLog.info("Skipping " + next.getResource().getResourceName() + " example");
bundle.getEntry().remove(i);
i--;
} else {
IdDt resourceId = next.getResource().getId();
if (!fullIds.add(resourceId.toUnqualifiedVersionless().getValue())) {
ourLog.info("Discarding duplicate resource: " + resourceId.getValue());
bundle.getEntry().remove(i);
i--;
continue;
}
String idPart = resourceId.getIdPart();
if (idPart != null) {
if (!ids.containsKey(idPart)) {
ids.put(idPart, 1);
} else {
ids.put(idPart, ids.get(idPart) + 1);
for (Entry nextEntry1 : b.getEntry()) {
if (nextEntry1.getResource() == null) {
continue;
}
if (nextEntry1.getResource() instanceof Bundle) {
continue;
}
if (nextEntry1.getResource() instanceof SearchParameter) {
continue;
}
bundle.addEntry().setRequest(new EntryRequest().setMethod(HTTPVerbEnum.POST)).setResource(nextEntry1.getResource());
}
} else {
ourLog.info("Discarding resource with not explicit ID");
if (parsed instanceof SearchParameter) {
continue;
}
bundle.addEntry().setRequest(new EntryRequest().setMethod(HTTPVerbEnum.POST)).setResource((IResource) parsed);
}
}
Map<String, Integer> ids = new HashMap<String, Integer>();
Set<String> fullIds = new HashSet<String>();
for (int i = 0; i < bundle.getEntry().size(); i++) {
Entry next = bundle.getEntry().get(i);
// DataElement have giant IDs that seem invalid, need to investigate this..
if ("DataElement".equals(next.getResource().getResourceName()) || "OperationOutcome".equals(next.getResource().getResourceName()) || "OperationDefinition".equals(next.getResource().getResourceName())) {
ourLog.info("Skipping " + next.getResource().getResourceName() + " example");
bundle.getEntry().remove(i);
i--;
} else {
IdDt resourceId = next.getResource().getId();
if (!fullIds.add(resourceId.toUnqualifiedVersionless().getValue())) {
ourLog.info("Discarding duplicate resource: " + resourceId.getValue());
bundle.getEntry().remove(i);
i--;
continue;
}
String idPart = resourceId.getIdPart();
if (idPart != null) {
if (!ids.containsKey(idPart)) {
ids.put(idPart, 1);
} else {
ids.put(idPart, ids.get(idPart) + 1);
}
} else {
ourLog.info("Discarding resource with not explicit ID");
bundle.getEntry().remove(i);
i--;
}
}
}
}
Set<String> qualIds = new HashSet<String>();
Map<String, String> renames = new HashMap<String,String>();
for (int i = 0; i < bundle.getEntry().size(); i++) {
Entry next = bundle.getEntry().get(i);
if (next.getResource().getId().getIdPart() != null) {
String idPart = next.getResource().getId().getIdPart();
String originalId = next.getResource().getResourceName() + '/' + idPart;
if (ids.get(idPart) > 1 || next.getResource().getId().isIdPartValidLong()) {
idPart = next.getResource().getResourceName() + idPart;
Set<String> qualIds = new HashSet<String>();
Map<String, String> renames = new HashMap<String, String>();
for (int i = 0; i < bundle.getEntry().size(); i++) {
Entry next = bundle.getEntry().get(i);
if (next.getResource().getId().getIdPart() != null) {
String idPart = next.getResource().getId().getIdPart();
String originalId = next.getResource().getResourceName() + '/' + idPart;
if (ids.get(idPart) > 1 || next.getResource().getId().isIdPartValidLong()) {
idPart = next.getResource().getResourceName() + idPart;
}
String nextId = next.getResource().getResourceName() + '/' + idPart;
if (!qualIds.add(nextId)) {
ourLog.info("Discarding duplicate resource with ID: " + nextId);
bundle.getEntry().remove(i);
i--;
}
next.getRequest().setMethod(HTTPVerbEnum.PUT);
next.getRequest().setUrl(nextId);
renames.put(originalId, nextId);
}
String nextId = next.getResource().getResourceName() + '/' + idPart;
if (!qualIds.add(nextId)) {
ourLog.info("Discarding duplicate resource with ID: " + nextId);
bundle.getEntry().remove(i);
i--;
}
next.getRequest().setMethod(HTTPVerbEnum.PUT);
next.getRequest().setUrl(nextId);
renames.put(originalId, nextId);
}
}
int goodRefs = 0;
for (Entry next : bundle.getEntry()) {
List<ResourceReferenceInfo> refs = ctx.newTerser().getAllResourceReferences(next.getResource());
for (ResourceReferenceInfo nextRef : refs) {
// if (nextRef.getResourceReference().getReferenceElement().isAbsolute()) {
// ourLog.info("Discarding absolute reference: {}",
// nextRef.getResourceReference().getReferenceElement().getValue());
// nextRef.getResourceReference().getReferenceElement().setValue(null);
// }
nextRef.getResourceReference().getReferenceElement().setValue(nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue());
String value = nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue();
if (!qualIds.contains(value) && !nextRef.getResourceReference().getReferenceElement().isLocal()) {
if (renames.containsKey(value)) {
nextRef.getResourceReference().setReference(renames.get(value));
int goodRefs = 0;
for (Entry next : bundle.getEntry()) {
List<ResourceReferenceInfo> refs = ctx.newTerser().getAllResourceReferences(next.getResource());
for (ResourceReferenceInfo nextRef : refs) {
// if (nextRef.getResourceReference().getReferenceElement().isAbsolute()) {
// ourLog.info("Discarding absolute reference: {}",
// nextRef.getResourceReference().getReferenceElement().getValue());
// nextRef.getResourceReference().getReferenceElement().setValue(null);
// }
nextRef.getResourceReference().setResource(null);
String value = nextRef.getResourceReference().getReferenceElement().toUnqualifiedVersionless().getValue();
if (!qualIds.contains(value) && !nextRef.getResourceReference().getReferenceElement().isLocal()) {
if (renames.containsKey(value)) {
nextRef.getResourceReference().setReference(renames.get(value));
goodRefs++;
} else {
ourLog.info("Discarding unknown reference: {}", value);
nextRef.getResourceReference().getReferenceElement().setValue(null);
}
} else {
goodRefs++;
} else {
ourLog.info("Discarding unknown reference: {}", value);
nextRef.getResourceReference().getReferenceElement().setValue(null);
}
} else {
goodRefs++;
}
}
// for (Entry next : bundle.getEntry()) {
// if (next.getResource().getId().hasIdPart() &&
// Character.isLetter(next.getResource().getId().getIdPart().charAt(0))) {
// next.getTransaction().setUrl(next.getResource().getResourceName() + '/' +
// next.getResource().getId().getIdPart());
// next.getTransaction().setMethod(HTTPVerbEnum.PUT);
// }
// }
ourLog.info("{} good references", goodRefs);
System.gc();
}
// for (Entry next : bundle.getEntry()) {
// if (next.getResource().getId().hasIdPart() &&
// Character.isLetter(next.getResource().getId().getIdPart().charAt(0))) {
// next.getTransaction().setUrl(next.getResource().getResourceName() + '/' +
// next.getResource().getId().getIdPart());
// next.getTransaction().setMethod(HTTPVerbEnum.PUT);
// }
// }
ourLog.info("{} good references", goodRefs);
String encoded = ctx.newJsonParser().encodeResourceToString(bundle);
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(bundle);
ourLog.info("Final bundle: {} entries", bundle.getEntry().size());
ourLog.info("Final bundle: {} chars", encoded.length());
ourLog.info("Final bundle: {}", FileUtils.getFileSizeDisplay(encoded.length(), 1));
ourLog.info("Uploading bundle to server: " + targetServer);
if (targetServer.startsWith("file://")) {
String path = targetServer.substring("file://".length());
ourLog.info("Writing bundle to: {}", path);
File file = new File(path);
if (file.exists()) {
throw new Exception("File already exists: " + file.getAbsolutePath());
}
FileWriter w = new FileWriter(file, false);
w.append(encoded);
w.close();
} else {
ourLog.info("Uploading bundle to server: " + targetServer);
IGenericClient fhirClient = newClient(ctx, targetServer);
IGenericClient fhirClient = newClient(ctx, targetServer);
long start = System.currentTimeMillis();
;
fhirClient.transaction().withBundle(bundle).execute();
long delay = System.currentTimeMillis() - start;
long start = System.currentTimeMillis();
;
fhirClient.transaction().withBundle(bundle).execute();
long delay = System.currentTimeMillis() - start;
ourLog.info("Finished uploading bundle to server (took {} ms)", delay);
ourLog.info("Finished uploading bundle to server (took {} ms)", delay);
}
}
}

View File

@ -8,19 +8,6 @@
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<repositories>
<repository>
<id>maven.java.net</id>
<snapshots>
<enabled>true</enabled>
</snapshots>
<releases>
<enabled>false</enabled>
</releases>
<url>https://maven.java.net/service/local/repositories/snapshots/content/</url>
</repository>
</repositories>
<artifactId>hapi-fhir-jaxrsserver-base</artifactId>
<packaging>jar</packaging>
@ -49,50 +36,42 @@
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.ejb</groupId>
<artifactId>ejb-api</artifactId>
<version>3.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<version>${jetty_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-server</artifactId>
<version>${jersey_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-servlet-core</artifactId>
<version>${jersey_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.containers</groupId>
<artifactId>jersey-container-jetty-http</artifactId>
<version>${jersey_version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-moxy</artifactId>
<version>${jersey_version}</version>
<scope>test</scope>
</dependency>

View File

@ -48,6 +48,11 @@
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-hl7org-dstu2</artifactId>
@ -58,6 +63,11 @@
<artifactId>hapi-fhir-validation-resources-dstu2</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
@ -361,6 +371,22 @@
</excludeResourceNames>
</configuration>
</execution>
<execution>
<id>build_dstu21</id>
<goals>
<goal>generate-jparest-server</goal>
</goals>
<configuration>
<version>dstu21</version>
<configPackageBase>ca.uhn.fhir.jpa.config</configPackageBase>
<packageBase>ca.uhn.fhir.jpa.rp.dstu21</packageBase>
<targetResourceSpringBeansFile>hapi-fhir-server-resourceproviders-dstu21.xml</targetResourceSpringBeansFile>
<baseResourceNames></baseResourceNames>
<excludeResourceNames>
<!-- <excludeResourceName>OperationDefinition</excludeResourceName> <excludeResourceName>OperationOutcome</excludeResourceName> -->
</excludeResourceNames>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
@ -373,6 +399,11 @@
<artifactId>hapi-fhir-structures-dstu2</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
</dependencies>
</plugin>
</plugins>

View File

@ -43,6 +43,7 @@ import ca.uhn.fhir.context.FhirContext;
@EnableJpaRepositories(basePackages = "ca.uhn.fhir.jpa.dao.data")
public class BaseConfig implements SchedulingConfigurer {
private static FhirContext ourFhirContextDstu21;
private static FhirContext ourFhirContextDstu2;
private static FhirContext ourFhirContextDstu1;
private static FhirContext ourFhirContextDstu2Hl7Org;
@ -70,6 +71,15 @@ public class BaseConfig implements SchedulingConfigurer {
return ourFhirContextDstu2;
}
@Bean(name = "myFhirContextDstu21")
@Lazy
public FhirContext fhirContextDstu21() {
if (ourFhirContextDstu21 == null) {
ourFhirContextDstu21 = FhirContext.forDstu2_1();
}
return ourFhirContextDstu21;
}
@Bean(name = "myFhirContextDstu1")
@Lazy
public FhirContext fhirContextDstu1() {

View File

@ -29,6 +29,7 @@ import org.springframework.context.annotation.Primary;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
@Configuration
public class BaseDstu1Config extends BaseConfig {
@ -40,7 +41,7 @@ public class BaseDstu1Config extends BaseConfig {
}
@Bean(name = "mySystemDaoDstu1", autowire = Autowire.BY_NAME)
public ca.uhn.fhir.jpa.dao.IFhirSystemDao<List<IResource>> fhirSystemDaoDstu1() {
public ca.uhn.fhir.jpa.dao.IFhirSystemDao<List<IResource>, MetaDt> fhirSystemDaoDstu1() {
ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu1 retVal = new ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu1();
return retVal;
}

View File

@ -0,0 +1,69 @@
package ca.uhn.fhir.jpa.config;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.FhirSearchDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.ISearchDao;
@Configuration
@EnableTransactionManagement
public class BaseDstu21Config extends BaseConfig {
@Bean
@Primary
public FhirContext defaultFhirContext() {
return fhirContextDstu21();
}
@Bean(name = "mySystemDaoDstu21", autowire = Autowire.BY_NAME)
public IFhirSystemDao<ca.uhn.fhir.model.dstu21.resource.Bundle, ca.uhn.fhir.model.dstu21.composite.MetaDt> systemDaoDstu21() {
ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu21 retVal = new ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu21();
return retVal;
}
@Bean(name = "mySystemProviderDstu21")
public ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21 systemProviderDstu2() {
ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21 retVal = new ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21();
retVal.setDao(systemDaoDstu21());
return retVal;
}
@Bean(name = "myJpaValidationSupportDstu21", autowire = Autowire.BY_NAME)
public ca.uhn.fhir.jpa.dao.IJpaValidationSupport jpaValidationSupportDstu2() {
ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu21 retVal = new ca.uhn.fhir.jpa.dao.JpaValidationSupportDstu21();
return retVal;
}
@Bean(autowire = Autowire.BY_TYPE)
public ISearchDao searchDao() {
FhirSearchDao searchDao = new FhirSearchDao();
return searchDao;
}
}

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.dao.FhirSearchDao;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.ISearchDao;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
@Configuration
@EnableTransactionManagement
@ -42,7 +43,7 @@ public class BaseDstu2Config extends BaseConfig {
}
@Bean(name = "mySystemDaoDstu2", autowire = Autowire.BY_NAME)
public IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle> systemDaoDstu2() {
public IFhirSystemDao<ca.uhn.fhir.model.dstu2.resource.Bundle, MetaDt> systemDaoDstu2() {
ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu2 retVal = new ca.uhn.fhir.jpa.dao.FhirSystemDaoDstu2();
return retVal;
}

View File

@ -0,0 +1,57 @@
package ca.uhn.fhir.jpa.config;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
import org.springframework.web.socket.WebSocketHandler;
import org.springframework.web.socket.config.annotation.EnableWebSocket;
import org.springframework.web.socket.config.annotation.WebSocketConfigurer;
import org.springframework.web.socket.config.annotation.WebSocketHandlerRegistry;
import org.springframework.web.socket.handler.PerConnectionWebSocketHandler;
import ca.uhn.fhir.jpa.subscription.SubscriptionWebsocketHandler;
@Configuration
@EnableWebSocket()
public class WebsocketDstu21Config implements WebSocketConfigurer {
@Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry theRegistry) {
theRegistry.addHandler(subscriptionWebSocketHandler(), "/websocket/dstu2.1");
}
@Bean(autowire = Autowire.BY_TYPE)
public WebSocketHandler subscriptionWebSocketHandler() {
return new PerConnectionWebSocketHandler(SubscriptionWebsocketHandler.class);
}
@Bean
public TaskScheduler websocketTaskScheduler() {
ThreadPoolTaskScheduler retVal = new ThreadPoolTaskScheduler();
retVal.setPoolSize(5);
return retVal;
}
}

View File

@ -105,7 +105,6 @@ import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.BaseResource;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
@ -138,9 +137,9 @@ import net.sourceforge.cobertura.CoverageIgnore;
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
static final String OO_SEVERITY_ERROR = "error";
static final String OO_SEVERITY_INFO = "information";
static final String OO_SEVERITY_WARN = "warning";
public static final String OO_SEVERITY_ERROR = "error";
public static final String OO_SEVERITY_INFO = "information";
public static final String OO_SEVERITY_WARN = "warning";
/**
* These are parameters which are supported by {@link BaseHapiFhirResourceDao#searchForIds(Map)}
@ -1035,33 +1034,36 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao {
}
}
protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
MetaDt retVal = new MetaDt();
for (TagDefinition next : tagDefinitions) {
switch (next.getTagType()) {
case PROFILE:
retVal.addProfile(next.getCode());
break;
case SECURITY_LABEL:
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
case TAG:
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
}
}
return retVal;
}
// protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
// MetaDt retVal = new MetaDt();
// for (TagDefinition next : tagDefinitions) {
// switch (next.getTagType()) {
// case PROFILE:
// retVal.addProfile(next.getCode());
// break;
// case SECURITY_LABEL:
// retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
// break;
// case TAG:
// retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
// break;
// }
// }
// return retVal;
// }
@Autowired
public void setContext(FhirContext theContext) {
myContext = theContext;
switch (myContext.getVersion().getVersion()) {
case DSTU1:
mySearchParamExtractor = new SearchParamExtractorDstu1(theContext);
break;
case DSTU2:
mySearchParamExtractor = new SearchParamExtractorDstu2(theContext);
break;
case DSTU1:
mySearchParamExtractor = new SearchParamExtractorDstu1(theContext);
case DSTU2_1:
mySearchParamExtractor = new SearchParamExtractorDstu21(theContext);
break;
case DSTU2_HL7ORG:
case DEV:

View File

@ -40,9 +40,12 @@ import javax.persistence.PersistenceContextType;
import javax.persistence.TemporalType;
import javax.persistence.TypedQuery;
import org.hl7.fhir.instance.model.api.IBaseCoding;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.transaction.PlatformTransactionManager;
@ -69,15 +72,13 @@ import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
@ -168,11 +169,11 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return doCreate(theResource, theIfNoneExist, thePerformIndexing, new Date());
}
protected IBaseOperationOutcome createErrorOperationOutcome(String theMessage) {
public IBaseOperationOutcome createErrorOperationOutcome(String theMessage) {
return createOperationOutcome(OO_SEVERITY_ERROR, theMessage);
}
protected IBaseOperationOutcome createInfoOperationOutcome(String theMessage) {
public IBaseOperationOutcome createInfoOperationOutcome(String theMessage) {
return createOperationOutcome(OO_SEVERITY_INFO, theMessage);
}
@ -502,7 +503,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
}
@Override
public MetaDt metaAddOperation(IIdType theResourceId, MetaDt theMetaAdd) {
public <MT extends IBaseMetaType> MT metaAddOperation(IIdType theResourceId, MT theMetaAdd) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName());
notifyInterceptors(RestOperationTypeEnum.META_ADD, requestDetails);
@ -541,7 +542,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
myEntityManager.merge(entity);
ourLog.info("Processed metaAddOperation on {} in {}ms", new Object[] { theResourceId, w.getMillisAndRestart() });
return metaGetOperation(theResourceId);
@SuppressWarnings("unchecked")
MT retVal = (MT) metaGetOperation(theMetaAdd.getClass(), theResourceId);
return retVal;
}
// @Override
@ -627,7 +630,7 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
// }
@Override
public MetaDt metaDeleteOperation(IIdType theResourceId, MetaDt theMetaDel) {
public <MT extends IBaseMetaType> MT metaDeleteOperation(IIdType theResourceId, MT theMetaDel) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theResourceId, getResourceName());
notifyInterceptors(RestOperationTypeEnum.META_DELETE, requestDetails);
@ -662,11 +665,13 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
ourLog.info("Processed metaDeleteOperation on {} in {}ms", new Object[] { theResourceId.getValue(), w.getMillisAndRestart() });
return metaGetOperation(theResourceId);
@SuppressWarnings("unchecked")
MT retVal = (MT)metaGetOperation(theMetaDel.getClass(), theResourceId);
return retVal;
}
@Override
public MetaDt metaGetOperation() {
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName());
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
@ -676,13 +681,36 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
q.setParameter("res_type", myResourceName);
List<TagDefinition> tagDefinitions = q.getResultList();
MetaDt retVal = super.toMetaDt(tagDefinitions);
MT retVal = toMetaDt(theType, tagDefinitions);
return retVal;
}
protected <MT extends IBaseMetaType> MT toMetaDt(Class<MT> theType, Collection<TagDefinition> tagDefinitions) {
MT retVal;
try {
retVal = theType.newInstance();
} catch (Exception e) {
throw new InternalErrorException("Failed to instantiate " + theType.getName(), e);
}
for (TagDefinition next : tagDefinitions) {
switch (next.getTagType()) {
case PROFILE:
retVal.addProfile(next.getCode());
break;
case SECURITY_LABEL:
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
case TAG:
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
}
}
return retVal;
}
@Override
public MetaDt metaGetOperation(IIdType theId) {
public <MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, IIdType theId) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, getResourceName());
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
@ -692,9 +720,9 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
for (BaseTag next : entity.getTags()) {
tagDefs.add(next.getTag());
}
MetaDt retVal = super.toMetaDt(tagDefs);
MT retVal = toMetaDt(theType, tagDefs);
retVal.setLastUpdated(entity.getUpdated());
retVal.setLastUpdated(entity.getUpdatedDate());
retVal.setVersionId(Long.toString(entity.getVersion()));
return retVal;
@ -934,16 +962,16 @@ public abstract class BaseHapiFhirResourceDao<T extends IResource> extends BaseH
return retVal;
}
private ArrayList<TagDefinition> toTagList(MetaDt theMeta) {
private ArrayList<TagDefinition> toTagList(IBaseMetaType theMeta) {
ArrayList<TagDefinition> retVal = new ArrayList<TagDefinition>();
for (CodingDt next : theMeta.getTag()) {
for (IBaseCoding next : theMeta.getTag()) {
retVal.add(new TagDefinition(TagTypeEnum.TAG, next.getSystem(), next.getCode(), next.getDisplay()));
}
for (CodingDt next : theMeta.getSecurity()) {
for (IBaseCoding next : theMeta.getSecurity()) {
retVal.add(new TagDefinition(TagTypeEnum.SECURITY_LABEL, next.getSystem(), next.getCode(), next.getDisplay()));
}
for (UriDt next : theMeta.getProfile()) {
for (IPrimitiveType<String> next : theMeta.getProfile()) {
retVal.add(new TagDefinition(TagTypeEnum.PROFILE, BaseHapiFhirDao.NS_JPA_PROFILE, next.getValue(), null));
}

View File

@ -53,7 +53,7 @@ import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
public abstract class BaseHapiFhirSystemDao<T> extends BaseHapiFhirDao<IBaseResource> implements IFhirSystemDao<T> {
public abstract class BaseHapiFhirSystemDao<T, MT> extends BaseHapiFhirDao<IBaseResource> implements IFhirSystemDao<T, MT> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(BaseHapiFhirSystemDao.class);

View File

@ -0,0 +1,46 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.model.dstu21.resource.Bundle;
import ca.uhn.fhir.model.dstu21.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu21.valueset.BundleTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class FhirResourceDaoBundleDstu21 extends FhirResourceDaoDstu21<Bundle> {
@Override
protected void preProcessResourceForStorage(Bundle theResource) {
super.preProcessResourceForStorage(theResource);
if (theResource.getTypeElement().getValueAsEnum() != BundleTypeEnum.DOCUMENT) {
String message = "Unable to store a Bundle resource on this server with a Bundle.type value other than '" + BundleTypeEnum.DOCUMENT.getCode() + "' - Value was: " + (theResource.getTypeElement().getValueAsEnum() != null ? theResource.getTypeElement().getValueAsEnum().getCode() : "(missing)");
throw new UnprocessableEntityException(message);
}
for (Entry next : theResource.getEntry()) {
next.setFullUrl((String)null);
}
}
}

View File

@ -66,13 +66,11 @@ import net.sourceforge.cobertura.CoverageIgnore;
public class FhirResourceDaoDstu2<T extends IResource> extends BaseHapiFhirResourceDao<T> {
/**
* TODO: set this to required after the next release
*/
@Autowired(required = false)
@Autowired()
@Qualifier("myJpaValidationSupportDstu2")
private IValidationSupport myJpaValidationSupport;
@Override
protected List<Object> getIncludeValues(FhirTerser theTerser, Include theInclude, IBaseResource theResource, RuntimeResourceDefinition theResourceDef) {
List<Object> values;
@ -139,7 +137,7 @@ public class FhirResourceDaoDstu2<T extends IResource> extends BaseHapiFhirResou
if (result.isSuccessful()) {
MethodOutcome retVal = new MethodOutcome();
retVal.setOperationOutcome((OperationOutcome) result.toOperationOutcome());
retVal.setOperationOutcome(result.toOperationOutcome());
return retVal;
} else {
throw new PreconditionFailedException("Validation failed", result.toOperationOutcome());

View File

@ -0,0 +1,157 @@
package ca.uhn.fhir.jpa.dao;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.validation.IResourceValidator.BestPracticeWarningLevel;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.util.DeleteConflict;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.dstu21.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu21.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.validation.DefaultProfileValidationSupport;
import ca.uhn.fhir.validation.FhirInstanceValidator;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.IValidationContext;
import ca.uhn.fhir.validation.IValidationSupport;
import ca.uhn.fhir.validation.IValidatorModule;
import ca.uhn.fhir.validation.ValidationResult;
import ca.uhn.fhir.validation.ValidationSupportChain;
import net.sourceforge.cobertura.CoverageIgnore;
public class FhirResourceDaoDstu21<T extends IResource> extends BaseHapiFhirResourceDao<T> {
@Autowired()
@Qualifier("myJpaValidationSupportDstu21")
private IValidationSupport myJpaValidationSupport;
@Override
protected List<Object> getIncludeValues(FhirTerser theTerser, Include theInclude, IBaseResource theResource, RuntimeResourceDefinition theResourceDef) {
List<Object> values;
if ("*".equals(theInclude.getValue())) {
values = new ArrayList<Object>();
values.addAll(theTerser.getAllPopulatedChildElementsOfType(theResource, BaseResourceReferenceDt.class));
} else if (theInclude.getValue().startsWith(theResourceDef.getName() + ":")) {
values = new ArrayList<Object>();
RuntimeSearchParam sp = theResourceDef.getSearchParam(theInclude.getValue().substring(theInclude.getValue().indexOf(':') + 1));
for (String nextPath : sp.getPathsSplit()) {
values.addAll(theTerser.getValues(theResource, nextPath));
}
} else {
values = Collections.emptyList();
}
return values;
}
@Override
protected IBaseOperationOutcome createOperationOutcome(String theSeverity, String theMessage) {
OperationOutcome oo = new OperationOutcome();
oo.getIssueFirstRep().getSeverityElement().setValue(theSeverity);
oo.getIssueFirstRep().getDiagnosticsElement().setValue(theMessage);
return oo;
}
@Override
public MethodOutcome validate(T theResource, IIdType theId, String theRawResource, EncodingEnum theEncoding, ValidationModeEnum theMode, String theProfile) {
ActionRequestDetails requestDetails = new ActionRequestDetails(theId, null, theResource);
notifyInterceptors(RestOperationTypeEnum.VALIDATE, requestDetails);
if (theMode == ValidationModeEnum.DELETE) {
if (theId == null || theId.hasIdPart() == false) {
throw new InvalidRequestException("No ID supplied. ID is required when validating with mode=DELETE");
}
final ResourceTable entity = readEntityLatestVersion(theId);
// Validate that there are no resources pointing to the candidate that
// would prevent deletion
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
validateOkToDelete(deleteConflicts, entity);
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDiagnostics("Ok to delete");
return new MethodOutcome(new IdDt(theId.getValue()), oo);
}
FhirValidator validator = getContext().newValidator();
FhirInstanceValidator val = new FhirInstanceValidator();
val.setBestPracticeWarningLevel(BestPracticeWarningLevel.Warning);
val.setValidationSupport(new ValidationSupportChain(new DefaultProfileValidationSupport(), myJpaValidationSupport));
validator.registerValidatorModule(val);
validator.registerValidatorModule(new IdChecker(theMode));
ValidationResult result;
if (isNotBlank(theRawResource)) {
result = validator.validateWithResult(theRawResource);
} else {
result = validator.validateWithResult(theResource);
}
if (result.isSuccessful()) {
MethodOutcome retVal = new MethodOutcome();
retVal.setOperationOutcome(result.toOperationOutcome());
return retVal;
} else {
throw new PreconditionFailedException("Validation failed", result.toOperationOutcome());
}
}
private class IdChecker implements IValidatorModule {
private ValidationModeEnum myMode;
public IdChecker(ValidationModeEnum theMode) {
myMode = theMode;
}
@Override
public void validateResource(IValidationContext<IBaseResource> theCtx) {
boolean hasId = theCtx.getResource().getIdElement().hasIdPart();
if (myMode == ValidationModeEnum.CREATE) {
if (hasId) {
throw new InvalidRequestException("Resource has an ID - ID must not be populated for a FHIR create");
}
} else if (myMode == ValidationModeEnum.UPDATE) {
if (hasId == false) {
throw new InvalidRequestException("Resource has no ID - ID must be populated for a FHIR update");
}
}
}
@CoverageIgnore
@Override
public void validateBundle(IValidationContext<Bundle> theContext) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,63 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu21.resource.Encounter;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.UnsignedIntDt;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
public class FhirResourceDaoEncounterDstu21 extends FhirResourceDaoDstu21<Encounter>implements IFhirResourceDaoEncounter<Encounter> {
@Override
public IBundleProvider encounterInstanceEverything(HttpServletRequest theServletRequest, IdDt theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
SearchParameterMap paramMap = new SearchParameterMap();
if (theCount != null) {
paramMap.setCount(theCount.getValue());
}
// paramMap.setRevIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
paramMap.setEverythingMode(theId != null ? EverythingModeEnum.ENCOUNTER_INSTANCE : EverythingModeEnum.ENCOUNTER_TYPE);
paramMap.setSort(theSort);
paramMap.setLastUpdated(theLastUpdated);
if (theId != null) {
paramMap.add("_id", new StringParam(theId.getIdPart()));
}
ca.uhn.fhir.rest.server.IBundleProvider retVal = search(paramMap);
return retVal;
}
@Override
public IBundleProvider encounterTypeEverything(HttpServletRequest theServletRequest, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort) {
return encounterInstanceEverything(theServletRequest, null, theCount, theLastUpdated, theSort);
}
}

View File

@ -0,0 +1,86 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Collections;
import javax.servlet.http.HttpServletRequest;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.jpa.dao.SearchParameterMap.EverythingModeEnum;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.primitive.UnsignedIntDt;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
public class FhirResourceDaoPatientDstu21 extends FhirResourceDaoDstu21<Patient>implements IFhirResourceDaoPatient<Patient> {
private IBundleProvider doEverythingOperation(IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) {
SearchParameterMap paramMap = new SearchParameterMap();
if (theCount != null) {
paramMap.setCount(theCount.getValue());
}
if (theContent != null) {
paramMap.add(Constants.PARAM_CONTENT, theContent);
}
if (theNarrative != null) {
paramMap.add(Constants.PARAM_TEXT, theNarrative);
}
paramMap.setIncludes(Collections.singleton(IResource.INCLUDE_ALL.asRecursive()));
paramMap.setEverythingMode(theId != null ? EverythingModeEnum.PATIENT_INSTANCE : EverythingModeEnum.PATIENT_TYPE);
paramMap.setSort(theSort);
paramMap.setLastUpdated(theLastUpdated);
if (theId != null) {
paramMap.add("_id", new StringParam(theId.getIdPart()));
}
SearchBuilder builder = new SearchBuilder(getContext(), myEntityManager, myPlatformTransactionManager, mySearchDao, mySearchResultDao, this);
builder.setType(getResourceType(), getResourceName());
return builder.search(paramMap);
}
@Override
public IBundleProvider patientInstanceEverything(HttpServletRequest theServletRequest, IIdType theId, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName());
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_INSTANCE, requestDetails);
return doEverythingOperation(theId, theCount, theLastUpdated, theSort, theContent, theNarrative);
}
@Override
public IBundleProvider patientTypeEverything(HttpServletRequest theServletRequest, UnsignedIntDt theCount, DateRangeParam theLastUpdated, SortSpec theSort, StringAndListParam theContent, StringAndListParam theNarrative) {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, getResourceName());
notifyInterceptors(RestOperationTypeEnum.EXTENDED_OPERATION_TYPE, requestDetails);
return doEverythingOperation(null, theCount, theLastUpdated, theSort, theContent, theNarrative);
}
}

View File

@ -0,0 +1,123 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import javax.annotation.PostConstruct;
import org.hl7.fhir.instance.model.api.IBaseOperationOutcome;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
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.entity.ResourceTable;
import ca.uhn.fhir.model.dstu21.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu21.resource.Questionnaire;
import ca.uhn.fhir.model.dstu21.resource.QuestionnaireResponse;
import ca.uhn.fhir.model.dstu21.resource.ValueSet;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.validation.FhirQuestionnaireResponseValidator;
import ca.uhn.fhir.validation.FhirValidator;
import ca.uhn.fhir.validation.IResourceLoader;
import ca.uhn.fhir.validation.ValidationResult;
public class FhirResourceDaoQuestionnaireResponseDstu21 extends FhirResourceDaoDstu21<QuestionnaireResponse> {
@Autowired
@Qualifier("myFhirContextDstu2Hl7Org")
private FhirContext myRefImplCtx;
private Boolean myValidateResponses;
/**
* Initialize the bean
*/
@PostConstruct
public void initialize() {
try {
Class.forName("org.hl7.fhir.instance.model.QuestionnaireResponse");
myValidateResponses = true;
} catch (ClassNotFoundException e) {
myValidateResponses = Boolean.FALSE;
}
}
@Override
protected void validateResourceForStorage(QuestionnaireResponse theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
if (!myValidateResponses) {
return;
}
QuestionnaireResponse qa = (QuestionnaireResponse) theResource;
if (qa == null || qa.getQuestionnaire() == null || qa.getQuestionnaire().getReference() == null || qa.getQuestionnaire().getReference().isEmpty()) {
return;
}
FhirValidator val = myRefImplCtx.newValidator();
val.setValidateAgainstStandardSchema(false);
val.setValidateAgainstStandardSchematron(false);
FhirQuestionnaireResponseValidator module = new FhirQuestionnaireResponseValidator();
module.setResourceLoader(new JpaResourceLoader());
val.registerValidatorModule(module);
ValidationResult result = val.validateWithResult(myRefImplCtx.newJsonParser().parseResource(getContext().newJsonParser().encodeResourceToString(qa)));
if (!result.isSuccessful()) {
IBaseOperationOutcome oo = getContext().newJsonParser().parseResource(OperationOutcome.class, myRefImplCtx.newJsonParser().encodeResourceToString(result.toOperationOutcome()));
throw new UnprocessableEntityException(getContext(), oo);
}
}
public class JpaResourceLoader implements IResourceLoader {
@Override
public <T extends IBaseResource> T load(Class<T> theType, IIdType theId) throws ResourceNotFoundException {
/*
* The QuestionnaireResponse validator uses RI structures, so for now we need to convert between that and HAPI
* structures. This is a bit hackish, but hopefully it will go away at some point.
*/
if ("ValueSet".equals(theType.getSimpleName())) {
IFhirResourceDao<ValueSet> dao = getDao(ValueSet.class);
ValueSet in = dao.read(theId);
String encoded = getContext().newJsonParser().encodeResourceToString(in);
// TODO: this is temporary until structures-dstu2 catches up to structures-hl7org.dstu2
encoded = encoded.replace("\"define\"", "\"codeSystem\"");
return myRefImplCtx.newJsonParser().parseResource(theType, encoded);
} else if ("Questionnaire".equals(theType.getSimpleName())) {
IFhirResourceDao<Questionnaire> dao = getDao(Questionnaire.class);
Questionnaire vs = dao.read(theId);
return myRefImplCtx.newJsonParser().parseResource(theType, getContext().newJsonParser().encodeResourceToString(vs));
} else {
// Should not happen, validator will only ask for these two
throw new IllegalStateException("Unexpected request to load resource of type " + theType);
}
}
}
}

View File

@ -24,13 +24,14 @@ import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.SearchParameter;
public class FhirResourceDaoSearchParameterDstu2 extends FhirResourceDaoDstu2<SearchParameter>implements IFhirResourceDaoSearchParameter<SearchParameter> {
@Autowired
private IFhirSystemDao<Bundle> mySystemDao;
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
/**
* This method is called once per minute to perform any required re-indexing. During most passes this will

View File

@ -0,0 +1,61 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.apache.commons.lang3.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import ca.uhn.fhir.model.dstu21.composite.MetaDt;
import ca.uhn.fhir.model.dstu21.resource.Bundle;
import ca.uhn.fhir.model.dstu21.resource.SearchParameter;
public class FhirResourceDaoSearchParameterDstu21 extends FhirResourceDaoDstu21<SearchParameter>implements IFhirResourceDaoSearchParameter<SearchParameter> {
@Autowired
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
/**
* This method is called once per minute to perform any required re-indexing. During most passes this will
* just check and find that there are no resources requiring re-indexing. In that case the method just returns
* immediately. If the search finds that some resources require reindexing, the system will do a bunch of
* reindexing and then return.
*/
@Override
@Scheduled(fixedDelay=DateUtils.MILLIS_PER_MINUTE)
public void performReindexingPass() {
if (getConfig().isSchedulingDisabled()) {
return;
}
int count = mySystemDao.performReindexingPass(100);
for (int i = 0; i < 50 && count > 0; i++) {
count = mySystemDao.performReindexingPass(100);
try {
Thread.sleep(DateUtils.MILLIS_PER_SECOND);
} catch (InterruptedException e) {
break;
}
}
}
}

View File

@ -85,7 +85,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
subscriptionEntity.setSubscriptionResource(theEntity);
subscriptionEntity.setNextCheck(theEntity.getPublished().getValue());
subscriptionEntity.setMostRecentMatch(theEntity.getPublished().getValue());
subscriptionEntity.setStatus(theSubscription.getStatusElement().getValueAsEnum());
subscriptionEntity.setStatus(theSubscription.getStatusElement().getValue());
myEntityManager.persist(subscriptionEntity);
}
@ -125,7 +125,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
// SubscriptionCandidateResource
Collection<Long> subscriptions = mySubscriptionTableDao.finsSubscriptionsWhichNeedToBeChecked(SubscriptionStatusEnum.ACTIVE, new Date());
Collection<Long> subscriptions = mySubscriptionTableDao.findSubscriptionsWhichNeedToBeChecked(SubscriptionStatusEnum.ACTIVE.getCode(), new Date());
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
@ -273,7 +273,7 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
} else {
Query q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_SET_STATUS");
q.setParameter("res_id", resourceId);
q.setParameter("status", resource.getStatusElement().getValueAsEnum());
q.setParameter("status", resource.getStatusElement().getValue());
if (q.executeUpdate() > 0) {
ourLog.info("Updated subscription status for subscription {} to {}", resourceId, resource.getStatusElement().getValueAsEnum());
} else {

View File

@ -0,0 +1,333 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.persistence.Query;
import org.apache.commons.lang3.time.DateUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.dao.data.ISubscriptionFlaggedResourceDataDao;
import ca.uhn.fhir.jpa.dao.data.ISubscriptionTableDao;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu.valueset.QuantityCompararatorEnum;
import ca.uhn.fhir.model.dstu21.resource.Subscription;
import ca.uhn.fhir.model.dstu21.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.rest.api.SortOrderEnum;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateParam;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class FhirResourceDaoSubscriptionDstu21 extends FhirResourceDaoDstu21<Subscription>implements IFhirResourceDaoSubscription<Subscription> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoSubscriptionDstu21.class);
@Autowired
private ISubscriptionFlaggedResourceDataDao mySubscriptionFlaggedResourceDataDao;
@Autowired
private ISubscriptionTableDao mySubscriptionTableDao;
@Autowired
private PlatformTransactionManager myTxManager;
private void createSubscriptionTable(ResourceTable theEntity, Subscription theSubscription) {
SubscriptionTable subscriptionEntity = new SubscriptionTable();
subscriptionEntity.setCreated(new Date());
subscriptionEntity.setSubscriptionResource(theEntity);
subscriptionEntity.setNextCheck(theEntity.getPublished().getValue());
subscriptionEntity.setMostRecentMatch(theEntity.getPublished().getValue());
subscriptionEntity.setStatus(theSubscription.getStatusElement().getValue());
myEntityManager.persist(subscriptionEntity);
}
@Override
public Long getSubscriptionTablePidForSubscriptionResource(IIdType theId) {
ResourceTable entity = readEntityLatestVersion(theId);
SubscriptionTable table = mySubscriptionTableDao.findOneByResourcePid(entity.getId());
if (table == null) {
return null;
}
return table.getId();
}
@Override
public synchronized List<IBaseResource> getUndeliveredResourcesAndPurge(Long theSubscriptionPid) {
List<IBaseResource> retVal = new ArrayList<IBaseResource>();
Page<SubscriptionFlaggedResource> flaggedResources = mySubscriptionFlaggedResourceDataDao.findAllBySubscriptionId(theSubscriptionPid, new PageRequest(0, 100));
for (SubscriptionFlaggedResource nextFlaggedResource : flaggedResources) {
retVal.add(toResource(nextFlaggedResource.getResource(), false));
}
mySubscriptionFlaggedResourceDataDao.delete(flaggedResources);
mySubscriptionFlaggedResourceDataDao.flush();
mySubscriptionTableDao.updateLastClientPoll(new Date());
return retVal;
}
@Override
@Transactional(propagation = Propagation.NOT_SUPPORTED)
public synchronized int pollForNewUndeliveredResources() {
if (getConfig().isSubscriptionEnabled() == false) {
return 0;
}
ourLog.trace("Beginning pollForNewUndeliveredResources()");
// SubscriptionCandidateResource
Collection<Long> subscriptions = mySubscriptionTableDao.findSubscriptionsWhichNeedToBeChecked(SubscriptionStatusEnum.ACTIVE.getCode(), new Date());
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
int retVal = 0;
for (final Long nextSubscriptionTablePid : subscriptions) {
retVal += txTemplate.execute(new TransactionCallback<Integer>() {
@Override
public Integer doInTransaction(TransactionStatus theStatus) {
SubscriptionTable nextSubscriptionTable = mySubscriptionTableDao.findOne(nextSubscriptionTablePid);
return pollForNewUndeliveredResources(nextSubscriptionTable);
}
});
}
return retVal;
}
private int pollForNewUndeliveredResources(SubscriptionTable theSubscriptionTable) {
Subscription subscription = toResource(Subscription.class, theSubscriptionTable.getSubscriptionResource(), false);
RuntimeResourceDefinition resourceDef = validateCriteriaAndReturnResourceDefinition(subscription);
SearchParameterMap criteriaUrl = translateMatchUrl(subscription.getCriteria(), resourceDef);
criteriaUrl = new SearchParameterMap();
long start = theSubscriptionTable.getMostRecentMatch().getTime();
long end = System.currentTimeMillis() - getConfig().getSubscriptionPollDelay();
if (end <= start) {
ourLog.trace("Skipping search for subscription");
return 0;
}
ourLog.debug("Subscription {} search from {} to {}", new Object[] { subscription.getId().getIdPart(), new InstantDt(new Date(start)), new InstantDt(new Date(end)) });
DateRangeParam range = new DateRangeParam();
range.setLowerBound(new DateParam(QuantityCompararatorEnum.GREATERTHAN, start));
range.setUpperBound(new DateParam(QuantityCompararatorEnum.LESSTHAN, end));
criteriaUrl.setLastUpdated(range);
criteriaUrl.setSort(new SortSpec(Constants.PARAM_LASTUPDATED, SortOrderEnum.ASC));
IFhirResourceDao<? extends IBaseResource> dao = getDao(resourceDef.getImplementingClass());
IBundleProvider results = dao.search(criteriaUrl);
if (results.size() == 0) {
return 0;
}
ourLog.info("Found {} new results for Subscription {}", results.size(), subscription.getId().getIdPart());
List<SubscriptionFlaggedResource> flags = new ArrayList<SubscriptionFlaggedResource>();
Date mostRecentMatch = null;
for (IBaseResource next : results.getResources(0, results.size())) {
Date updated = ResourceMetadataKeyEnum.UPDATED.get((IResource) next).getValue();
if (mostRecentMatch == null) {
mostRecentMatch = updated;
} else {
long mostRecentMatchTime = mostRecentMatch.getTime();
long updatedTime = updated.getTime();
if (mostRecentMatchTime < updatedTime) {
mostRecentMatch = updated;
}
}
SubscriptionFlaggedResource nextFlag = new SubscriptionFlaggedResource();
Long pid = IDao.RESOURCE_PID.get((IResource) next);
ourLog.info("New resource for subscription: {}", pid);
nextFlag.setResource(myEntityManager.find(ResourceTable.class, pid));
nextFlag.setSubscription(theSubscriptionTable);
nextFlag.setVersion(next.getIdElement().getVersionIdPartAsLong());
flags.add(nextFlag);
}
mySubscriptionFlaggedResourceDataDao.save(flags);
ourLog.debug("Updating most recent match for subcription {} to {}", subscription.getId().getIdPart(), new InstantDt(mostRecentMatch));
theSubscriptionTable.setMostRecentMatch(mostRecentMatch);
mySubscriptionTableDao.save(theSubscriptionTable);
return results.size();
}
@Scheduled(fixedDelay = 10 * DateUtils.MILLIS_PER_SECOND)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public synchronized void pollForNewUndeliveredResourcesScheduler() {
if (getConfig().isSchedulingDisabled()) {
return;
}
pollForNewUndeliveredResources();
}
@Override
protected void postPersist(ResourceTable theEntity, Subscription theSubscription) {
super.postPersist(theEntity, theSubscription);
createSubscriptionTable(theEntity, theSubscription);
}
@Scheduled(fixedDelay = DateUtils.MILLIS_PER_MINUTE)
@Transactional(propagation = Propagation.NOT_SUPPORTED)
@Override
public void purgeInactiveSubscriptions() {
if (getConfig().isSchedulingDisabled()) {
return;
}
Long purgeInactiveAfterMillis = getConfig().getSubscriptionPurgeInactiveAfterMillis();
if (getConfig().isSubscriptionEnabled() == false || purgeInactiveAfterMillis == null) {
return;
}
Date cutoff = new Date(System.currentTimeMillis() - purgeInactiveAfterMillis);
Collection<SubscriptionTable> toPurge = mySubscriptionTableDao.findInactiveBeforeCutoff(cutoff);
for (SubscriptionTable subscriptionTable : toPurge) {
final IdDt subscriptionId = subscriptionTable.getSubscriptionResource().getIdDt();
ourLog.info("Deleting inactive subscription {} - Created {}, last client poll {}",
new Object[] { subscriptionId.toUnqualified(), subscriptionTable.getCreated(), subscriptionTable.getLastClientPoll() });
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
delete(subscriptionId);
return null;
}
});
}
}
@Override
protected ResourceTable updateEntity(IResource theResource, ResourceTable theEntity, boolean theUpdateHistory, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
Date theUpdateTime) {
ResourceTable retVal = super.updateEntity(theResource, theEntity, theUpdateHistory, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime);
Subscription resource = (Subscription) theResource;
Long resourceId = theEntity.getId();
if (theDeletedTimestampOrNull != null) {
Long subscriptionId = getSubscriptionTablePidForSubscriptionResource(theEntity.getIdDt());
if (subscriptionId != null) {
mySubscriptionFlaggedResourceDataDao.deleteAllForSubscription(subscriptionId);
mySubscriptionTableDao.deleteAllForSubscription(subscriptionId);
}
} else {
Query q = myEntityManager.createNamedQuery("Q_HFJ_SUBSCRIPTION_SET_STATUS");
q.setParameter("res_id", resourceId);
q.setParameter("status", resource.getStatusElement().getValue());
if (q.executeUpdate() > 0) {
ourLog.info("Updated subscription status for subscription {} to {}", resourceId, resource.getStatusElement().getValueAsEnum());
} else {
createSubscriptionTable(retVal, resource);
}
}
return retVal;
}
private RuntimeResourceDefinition validateCriteriaAndReturnResourceDefinition(Subscription theResource) {
String query = theResource.getCriteria();
if (isBlank(query)) {
throw new UnprocessableEntityException("Subscription.criteria must be populated");
}
int sep = query.indexOf('?');
if (sep <= 1) {
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
}
String resType = query.substring(0, sep);
if (resType.contains("/")) {
throw new UnprocessableEntityException("Subscription.criteria must be in the form \"{Resource Type}?[params]\"");
}
RuntimeResourceDefinition resDef;
try {
resDef = getContext().getResourceDefinition(resType);
} catch (DataFormatException e) {
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resType);
}
return resDef;
}
@Override
protected void validateResourceForStorage(Subscription theResource, ResourceTable theEntityToSave) {
super.validateResourceForStorage(theResource, theEntityToSave);
RuntimeResourceDefinition resDef = validateCriteriaAndReturnResourceDefinition(theResource);
IFhirResourceDao<? extends IBaseResource> dao = getDao(resDef.getImplementingClass());
if (dao == null) {
throw new UnprocessableEntityException("Subscription.criteria contains invalid/unsupported resource type: " + resDef);
}
if (theResource.getChannel().getType() == null) {
throw new UnprocessableEntityException("Subscription.channel.type must be populated on this server");
}
SubscriptionStatusEnum status = theResource.getStatusElement().getValueAsEnum();
if (status == null) {
throw new UnprocessableEntityException("Subscription.status must be populated on this server");
}
}
}

View File

@ -58,7 +58,7 @@ import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.validation.DefaultProfileValidationSupport;
import ca.uhn.fhir.validation.ValidationSupportChain;
public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>implements IFhirResourceDaoValueSet<ValueSet> {
public class FhirResourceDaoValueSetDstu2 extends FhirResourceDaoDstu2<ValueSet>implements IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> {
@Autowired
private IJpaValidationSupport myJpaValidationSupport;

View File

@ -0,0 +1,358 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import javax.annotation.PostConstruct;
import org.apache.commons.codec.binary.StringUtils;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
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.entity.BaseHasResource;
import ca.uhn.fhir.model.dstu21.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
import ca.uhn.fhir.model.dstu21.resource.ValueSet;
import ca.uhn.fhir.model.dstu21.resource.ValueSet.CodeSystemConcept;
import ca.uhn.fhir.model.dstu21.resource.ValueSet.ComposeInclude;
import ca.uhn.fhir.model.dstu21.resource.ValueSet.ComposeIncludeConcept;
import ca.uhn.fhir.model.dstu21.resource.ValueSet.ExpansionContains;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.param.TokenParam;
import ca.uhn.fhir.rest.param.UriParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.validation.DefaultProfileValidationSupport;
import ca.uhn.fhir.validation.ValidationSupportChain;
public class FhirResourceDaoValueSetDstu21 extends FhirResourceDaoDstu21<ValueSet>implements IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> {
@Autowired
private IJpaValidationSupport myJpaValidationSupport;
private ValidationSupportChain myValidationSupport;
@Autowired
@Qualifier("myFhirContextDstu2Hl7Org")
private FhirContext myRiCtx;
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
@Override
@PostConstruct
public void postConstruct() {
super.postConstruct();
myDefaultProfileValidationSupport = new DefaultProfileValidationSupport();
myValidationSupport = new ValidationSupportChain(myDefaultProfileValidationSupport, myJpaValidationSupport);
}
@Override
public ValueSet expand(IIdType theId, String theFilter) {
ValueSet source = loadValueSetForExpansion(theId);
return expand(source, theFilter);
}
private ValueSet loadValueSetForExpansion(IIdType theId) {
if (theId.getValue().startsWith("http://hl7.org/fhir/")) {
org.hl7.fhir.instance.model.ValueSet valueSet = myValidationSupport.fetchResource(myRiCtx, org.hl7.fhir.instance.model.ValueSet.class, theId.getValue());
if (valueSet != null) {
return getContext().newJsonParser().parseResource(ValueSet.class, myRiCtx.newJsonParser().encodeResourceToString(valueSet));
}
}
BaseHasResource sourceEntity = readEntity(theId);
if (sourceEntity == null) {
throw new ResourceNotFoundException(theId);
}
ValueSet source = (ValueSet) toResource(sourceEntity, false);
return source;
}
@Override
public ValueSet expandByIdentifier(String theUri, String theFilter) {
if (isBlank(theUri)) {
throw new InvalidRequestException("URI must not be blank or missing");
}
ValueSet source;
org.hl7.fhir.instance.model.ValueSet defaultValueSet = myDefaultProfileValidationSupport.fetchResource(myRiCtx, org.hl7.fhir.instance.model.ValueSet.class, theUri);
if (defaultValueSet != null) {
source = getContext().newJsonParser().parseResource(ValueSet.class, myRiCtx.newJsonParser().encodeResourceToString(defaultValueSet));
} else {
IBundleProvider ids = search(ValueSet.SP_URL, new UriParam(theUri));
if (ids.size() == 0) {
throw new InvalidRequestException("Unknown ValueSet URI: " + theUri);
}
source = (ValueSet) ids.getResources(0, 1).get(0);
}
return expand(source, theFilter);
}
@Override
public ValueSet expand(ValueSet source, String theFilter) {
ValueSet retVal = new ValueSet();
retVal.setDate(DateTimeDt.withCurrentTime());
/*
* Add composed concepts
*/
for (ComposeInclude nextInclude : source.getCompose().getInclude()) {
for (ComposeIncludeConcept next : nextInclude.getConcept()) {
if (isBlank(theFilter)) {
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
} else {
String filter = theFilter.toLowerCase();
if (next.getDisplay().toLowerCase().contains(filter) || next.getCode().toLowerCase().contains(filter)) {
addCompose(retVal, nextInclude.getSystem(), next.getCode(), next.getDisplay());
}
}
}
}
/*
* Add defined concepts
*/
for (CodeSystemConcept next : source.getCodeSystem().getConcept()) {
addCompose(theFilter, retVal, source, next);
}
return retVal;
}
private void addCompose(String theFilter, ValueSet theValueSetToPopulate, ValueSet theSourceValueSet, CodeSystemConcept theConcept) {
if (isBlank(theFilter)) {
addCompose(theValueSetToPopulate, theSourceValueSet.getCodeSystem().getSystem(), theConcept.getCode(), theConcept.getDisplay());
} else {
String filter = theFilter.toLowerCase();
if (theConcept.getDisplay().toLowerCase().contains(filter) || theConcept.getCode().toLowerCase().contains(filter)) {
addCompose(theValueSetToPopulate, theSourceValueSet.getCodeSystem().getSystem(), theConcept.getCode(), theConcept.getDisplay());
}
}
for (CodeSystemConcept nextChild : theConcept.getConcept()) {
addCompose(theFilter, theValueSetToPopulate, theSourceValueSet, nextChild);
}
}
private void addCompose(ValueSet retVal, String theSystem, String theCode, String theDisplay) {
if (isBlank(theCode)) {
return;
}
ExpansionContains contains = retVal.getExpansion().addContains();
contains.setSystem(theSystem);
contains.setCode(theCode);
contains.setDisplay(theDisplay);
}
@Override
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCode(UriDt theValueSetIdentifier, IIdType theId, CodeDt theCode, UriDt theSystem, StringDt theDisplay,
CodingDt theCoding, CodeableConceptDt theCodeableConcept) {
List<IIdType> valueSetIds;
boolean haveCodeableConcept = theCodeableConcept != null && theCodeableConcept.getCoding().size() > 0;
boolean haveCoding = theCoding != null && theCoding.isEmpty() == false;
boolean haveCode = theCode != null && theCode.isEmpty() == false;
if (!haveCodeableConcept && !haveCoding && !haveCode) {
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate");
}
if (!multiXor(haveCodeableConcept, haveCoding, haveCode)) {
throw new InvalidRequestException("$validate-code can only validate (system AND code) OR (coding) OR (codeableConcept)");
}
boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false;
if (theId != null) {
valueSetIds = Collections.singletonList(theId);
} else if (haveIdentifierParam) {
Set<Long> ids = searchForIds(ValueSet.SP_IDENTIFIER, new TokenParam(null, theValueSetIdentifier.getValue()));
valueSetIds = new ArrayList<IIdType>();
for (Long next : ids) {
valueSetIds.add(new IdDt("ValueSet", next));
}
} else {
if (theCode == null || theCode.isEmpty()) {
throw new InvalidRequestException("Either ValueSet ID or ValueSet identifier or system and code must be provided. Unable to validate.");
}
String code = theCode.getValue();
String system = toStringOrNull(theSystem);
valueSetIds = findValueSetIdsContainingSystemAndCode(code, system);
}
for (IIdType nextId : valueSetIds) {
ValueSet expansion = expand(nextId, null);
List<ExpansionContains> contains = expansion.getExpansion().getContains();
ValidateCodeResult result = validateCodeIsInContains(contains, toStringOrNull(theSystem), toStringOrNull(theCode), theCoding, theCodeableConcept);
if (result != null) {
if (theDisplay != null && isNotBlank(theDisplay.getValue()) && isNotBlank(result.getDisplay())) {
if (!theDisplay.getValue().equals(result.getDisplay())) {
return new ValidateCodeResult(false, "Display for code does not match", result.getDisplay());
}
}
return result;
}
}
return new ValidateCodeResult(false, "Code not found", null);
}
private List<IIdType> findValueSetIdsContainingSystemAndCode(String theCode, String theSystem) {
if (theSystem != null && theSystem.startsWith("http://hl7.org/fhir/")) {
return Collections.singletonList((IIdType)new IdDt(theSystem));
}
List<IIdType> valueSetIds;
Set<Long> ids = searchForIds(ValueSet.SP_CODE, new TokenParam(theSystem, theCode));
valueSetIds = new ArrayList<IIdType>();
for (Long next : ids) {
valueSetIds.add(new IdDt("ValueSet", next));
}
return valueSetIds;
}
private static boolean multiXor(boolean... theValues) {
int count = 0;
for (int i = 0; i < theValues.length; i++) {
if (theValues[i]) {
count++;
}
}
return count == 1;
}
private String toStringOrNull(IPrimitiveType<String> thePrimitive) {
return thePrimitive != null ? thePrimitive.getValue() : null;
}
private ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult validateCodeIsInContains(List<ExpansionContains> contains, String theSystem, String theCode, CodingDt theCoding,
CodeableConceptDt theCodeableConcept) {
for (ExpansionContains nextCode : contains) {
ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult result = validateCodeIsInContains(nextCode.getContains(), theSystem, theCode, theCoding, theCodeableConcept);
if (result != null) {
return result;
}
String system = nextCode.getSystem();
String code = nextCode.getCode();
if (isNotBlank(theCode)) {
if (theCode.equals(code) && (isBlank(theSystem) || theSystem.equals(system))) {
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
}
} else if (theCoding != null) {
if (StringUtils.equals(system, theCoding.getSystem()) && StringUtils.equals(code, theCoding.getCode())) {
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
}
} else {
for (CodingDt next : theCodeableConcept.getCoding()) {
if (StringUtils.equals(system, next.getSystem()) && StringUtils.equals(code, next.getCode())) {
return new ValidateCodeResult(true, "Validation succeeded", nextCode.getDisplay());
}
}
}
}
return null;
}
@Override
public ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.LookupCodeResult lookupCode(CodeDt theCode, UriDt theSystem, CodingDt theCoding) {
boolean haveCoding = theCoding != null && isNotBlank(theCoding.getSystem()) && isNotBlank(theCoding.getCode());
boolean haveCode = theCode != null && theCode.isEmpty() == false;
boolean haveSystem = theSystem != null && theSystem.isEmpty() == false;
if (!haveCoding && !(haveSystem && haveCode)) {
throw new InvalidRequestException("No code, coding, or codeableConcept provided to validate");
}
if (!multiXor(haveCoding, (haveSystem && haveCode)) || (haveSystem != haveCode)) {
throw new InvalidRequestException("$lookup can only validate (system AND code) OR (coding.system AND coding.code)");
}
String code;
String system;
if (haveCoding) {
code = theCoding.getCode();
system = theCoding.getSystem();
} else {
code = theCode.getValue();
system = theSystem.getValue();
}
List<IIdType> valueSetIds = findValueSetIdsContainingSystemAndCode(code, system);
for (IIdType nextId : valueSetIds) {
ValueSet expansion = expand(nextId, null);
List<ExpansionContains> contains = expansion.getExpansion().getContains();
ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.LookupCodeResult result = lookup(contains, system, code);
if (result != null) {
return result;
}
}
LookupCodeResult retVal = new LookupCodeResult();
retVal.setFound(false);
retVal.setSearchedForCode(code);
retVal.setSearchedForSystem(system);
return retVal;
}
private ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.LookupCodeResult lookup(List<ExpansionContains> theContains, String theSystem, String theCode) {
for (ExpansionContains nextCode : theContains) {
String system = nextCode.getSystem();
String code = nextCode.getCode();
if (theSystem.equals(system) && theCode.equals(code)) {
ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.LookupCodeResult retVal = new LookupCodeResult();
retVal.setSearchedForCode(code);
retVal.setSearchedForSystem(system);
retVal.setFound(true);
if (nextCode.getAbstract() != null) {
retVal.setCodeIsAbstract(nextCode.getAbstract().booleanValue());
}
retVal.setCodeDisplay(nextCode.getDisplay());
retVal.setCodeSystemVersion(nextCode.getVersion());
retVal.setCodeSystemDisplayName("Unknown"); // TODO: implement
return retVal;
}
}
return null;
}
}

View File

@ -50,7 +50,7 @@ import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.util.FhirTerser;
public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>> {
public class FhirSystemDaoDstu1 extends BaseHapiFhirSystemDao<List<IResource>, MetaDt> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu1.class);
@Override

View File

@ -90,7 +90,7 @@ import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.util.UrlUtil.UrlParts;
public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu2.class);
@Autowired
@ -207,11 +207,30 @@ public class FhirSystemDaoDstu2 extends BaseHapiFhirSystemDao<Bundle> {
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
List<TagDefinition> tagDefinitions = q.getResultList();
MetaDt retVal = super.toMetaDt(tagDefinitions);
MetaDt retVal = toMetaDt(tagDefinitions);
return retVal;
}
protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
MetaDt retVal = new MetaDt();
for (TagDefinition next : tagDefinitions) {
switch (next.getTagType()) {
case PROFILE:
retVal.addProfile(next.getCode());
break;
case SECURITY_LABEL:
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
case TAG:
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
}
}
return retVal;
}
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
RuntimeResourceDefinition resType;
try {

View File

@ -0,0 +1,660 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.defaultString;
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.TypedQuery;
import org.apache.http.NameValuePair;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionDefinition;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import com.google.common.collect.ArrayListMultimap;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.jpa.provider.ServletSubRequestDetails;
import ca.uhn.fhir.jpa.util.DeleteConflict;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.dstu21.composite.MetaDt;
import ca.uhn.fhir.model.dstu21.resource.Bundle;
import ca.uhn.fhir.model.dstu21.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu21.resource.Bundle.EntryResponse;
import ca.uhn.fhir.model.dstu21.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu21.valueset.BundleTypeEnum;
import ca.uhn.fhir.model.dstu21.valueset.HTTPVerbEnum;
import ca.uhn.fhir.model.dstu21.valueset.IssueSeverityEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.parser.DataFormatException;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.api.RequestTypeEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.method.BaseMethodBinding;
import ca.uhn.fhir.rest.method.BaseResourceReturningMethodBinding;
import ca.uhn.fhir.rest.method.BaseResourceReturningMethodBinding.ResourceOrDstu1Bundle;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.RestfulServerUtils;
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.rest.server.exceptions.NotModifiedException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
import ca.uhn.fhir.util.FhirTerser;
import ca.uhn.fhir.util.UrlUtil;
import ca.uhn.fhir.util.UrlUtil.UrlParts;
public class FhirSystemDaoDstu21 extends BaseHapiFhirSystemDao<Bundle, MetaDt> {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu21.class);
@Autowired
private PlatformTransactionManager myTxManager;
private Bundle batch(final RequestDetails theRequestDetails, Bundle theRequest) {
ourLog.info("Beginning batch with {} resources", theRequest.getEntry().size());
long start = System.currentTimeMillis();
TransactionTemplate txTemplate = new TransactionTemplate(myTxManager);
txTemplate.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRES_NEW);
Bundle resp = new Bundle();
resp.setType(BundleTypeEnum.BATCH_RESPONSE);
OperationOutcome ooResp = new OperationOutcome();
resp.addEntry().setResource(ooResp);
/*
* For batch, we handle each entry as a mini-transaction in its own database transaction so that if one fails, it doesn't prevent others
*/
for (final Entry nextRequestEntry : theRequest.getEntry()) {
TransactionCallback<Bundle> callback = new TransactionCallback<Bundle>() {
@Override
public Bundle doInTransaction(TransactionStatus theStatus) {
Bundle subRequestBundle = new Bundle();
subRequestBundle.setType(BundleTypeEnum.TRANSACTION);
subRequestBundle.addEntry(nextRequestEntry);
Bundle subResponseBundle = transaction((ServletRequestDetails) theRequestDetails, subRequestBundle, "Batch sub-request");
return subResponseBundle;
}
};
BaseServerResponseException caughtEx;
try {
Bundle nextResponseBundle = txTemplate.execute(callback);
caughtEx = null;
Entry subResponseEntry = nextResponseBundle.getEntry().get(0);
resp.addEntry(subResponseEntry);
/*
* If the individual entry didn't have a resource in its response, bring the sub-transaction's OperationOutcome across so the client can see it
*/
if (subResponseEntry.getResource() == null) {
subResponseEntry.setResource(nextResponseBundle.getEntry().get(0).getResource());
}
} catch (BaseServerResponseException e) {
caughtEx = e;
} catch (Throwable t) {
ourLog.error("Failure during BATCH sub transaction processing", t);
caughtEx = new InternalErrorException(t);
}
if (caughtEx != null) {
Entry nextEntry = resp.addEntry();
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setSeverity(IssueSeverityEnum.ERROR).setDiagnostics(caughtEx.getMessage());
nextEntry.setResource(oo);
EntryResponse nextEntryResp = nextEntry.getResponse();
nextEntryResp.setStatus(toStatusString(caughtEx.getStatusCode()));
}
}
long delay = System.currentTimeMillis() - start;
ourLog.info("Batch completed in {}ms", new Object[] { delay });
ooResp.addIssue().setSeverity(IssueSeverityEnum.INFORMATION).setDiagnostics("Batch completed in " + delay + "ms");
return resp;
}
private String extractTransactionUrlOrThrowException(Entry nextEntry, HTTPVerbEnum verb) {
String url = nextEntry.getRequest().getUrl();
if (isBlank(url)) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionMissingUrl", verb.name()));
}
return url;
}
/**
* This method is called for nested bundles (e.g. if we received a transaction with an entry that
* was a GET search, this method is called on the bundle for the search result, that will be placed in the
* outer bundle). This method applies the _summary and _content parameters to the output of
* that bundle.
*
* TODO: This isn't the most efficient way of doing this.. hopefully we can come up with something better in the future.
*/
private IBaseResource filterNestedBundle(RequestDetails theRequestDetails, IBaseResource theResource) {
IParser p = getContext().newJsonParser();
RestfulServerUtils.configureResponseParser(theRequestDetails, p);
return p.parseResource(theResource.getClass(), p.encodeResourceToString(theResource));
}
private IFhirResourceDao<?> getDaoOrThrowException(Class<? extends IResource> theClass) {
IFhirResourceDao<? extends IResource> retVal = getDao(theClass);
if (retVal == null) {
throw new InvalidRequestException("Unable to process request, this server does not know how to handle resources of type " + getContext().getResourceDefinition(theClass).getName());
}
return retVal;
}
@Override
public MetaDt metaGetOperation() {
// Notify interceptors
ActionRequestDetails requestDetails = new ActionRequestDetails(null, null);
notifyInterceptors(RestOperationTypeEnum.META, requestDetails);
String sql = "SELECT d FROM TagDefinition d WHERE d.myId IN (SELECT DISTINCT t.myTagId FROM ResourceTag t)";
TypedQuery<TagDefinition> q = myEntityManager.createQuery(sql, TagDefinition.class);
List<TagDefinition> tagDefinitions = q.getResultList();
MetaDt retVal = toMetaDt(tagDefinitions);
return retVal;
}
protected MetaDt toMetaDt(Collection<TagDefinition> tagDefinitions) {
MetaDt retVal = new MetaDt();
for (TagDefinition next : tagDefinitions) {
switch (next.getTagType()) {
case PROFILE:
retVal.addProfile(next.getCode());
break;
case SECURITY_LABEL:
retVal.addSecurity().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
case TAG:
retVal.addTag().setSystem(next.getSystem()).setCode(next.getCode()).setDisplay(next.getDisplay());
break;
}
}
return retVal;
}
private ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> toDao(UrlParts theParts, String theVerb, String theUrl) {
RuntimeResourceDefinition resType;
try {
resType = getContext().getResourceDefinition(theParts.getResourceType());
} catch (DataFormatException e) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
throw new InvalidRequestException(msg);
}
IFhirResourceDao<? extends IBaseResource> dao = null;
if (resType != null) {
dao = getDao(resType.getImplementingClass());
}
if (dao == null) {
String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
throw new InvalidRequestException(msg);
}
// if (theParts.getResourceId() == null && theParts.getParams() == null) {
// String msg = getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionInvalidUrl", theVerb, theUrl);
// throw new InvalidRequestException(msg);
// }
return dao;
}
@Transactional(propagation = Propagation.REQUIRED)
@Override
public Bundle transaction(RequestDetails theRequestDetails, Bundle theRequest) {
ActionRequestDetails requestDetails = new ActionRequestDetails(null, "Bundle", theRequest);
notifyInterceptors(RestOperationTypeEnum.TRANSACTION, requestDetails);
String actionName = "Transaction";
return transaction((ServletRequestDetails) theRequestDetails, theRequest, actionName);
}
@SuppressWarnings("unchecked")
private Bundle transaction(ServletRequestDetails theRequestDetails, Bundle theRequest, String theActionName) {
BundleTypeEnum transactionType = theRequest.getTypeElement().getValueAsEnum();
if (transactionType == BundleTypeEnum.BATCH) {
return batch(theRequestDetails, theRequest);
}
if (transactionType == null) {
String message = "Transactiion Bundle did not specify valid Bundle.type, assuming " + BundleTypeEnum.TRANSACTION.getCode();
ourLog.warn(message);
transactionType = BundleTypeEnum.TRANSACTION;
}
if (transactionType != BundleTypeEnum.TRANSACTION) {
throw new InvalidRequestException("Unable to process transaction where incoming Bundle.type = " + transactionType.getCode());
}
ourLog.info("Beginning {} with {} resources", theActionName, theRequest.getEntry().size());
long start = System.currentTimeMillis();
Date updateTime = new Date();
Set<IdDt> allIds = new LinkedHashSet<IdDt>();
Map<IdDt, IdDt> idSubstitutions = new HashMap<IdDt, IdDt>();
Map<IdDt, DaoMethodOutcome> idToPersistedOutcome = new HashMap<IdDt, DaoMethodOutcome>();
/*
* We want to execute the transaction request bundle elements in the order
* specified by the FHIR specification (see TransactionSorter) so we save the
* original order in the request, then sort it.
*
* Entries with a type of GET are removed from the bundle so that they
* can be processed at the very end. We do this because the incoming resources
* are saved in a two-phase way in order to deal with interdependencies, and
* we want the GET processing to use the final indexing state
*/
Bundle response = new Bundle();
List<Entry> getEntries = new ArrayList<Entry>();
IdentityHashMap<Entry, Integer> originalRequestOrder = new IdentityHashMap<Bundle.Entry, Integer>();
for (int i = 0; i < theRequest.getEntry().size(); i++) {
originalRequestOrder.put(theRequest.getEntry().get(i), i);
response.addEntry();
if (theRequest.getEntry().get(i).getRequest().getMethodElement().getValueAsEnum() == HTTPVerbEnum.GET) {
getEntries.add(theRequest.getEntry().get(i));
}
}
Collections.sort(theRequest.getEntry(), new TransactionSorter());
List<IIdType> deletedResources = new ArrayList<IIdType>();
List<DeleteConflict> deleteConflicts = new ArrayList<DeleteConflict>();
/*
* Loop through the request and process any entries of type
* PUT, POST or DELETE
*/
for (int i = 0; i < theRequest.getEntry().size(); i++) {
if (i % 100 == 0) {
ourLog.info("Processed {} non-GET entries out of {}", i, theRequest.getEntry().size());
}
Entry nextReqEntry = theRequest.getEntry().get(i);
IResource res = nextReqEntry.getResource();
IdDt nextResourceId = null;
if (res != null) {
nextResourceId = res.getId();
if (nextResourceId.hasIdPart() == false) {
if (isNotBlank(nextReqEntry.getFullUrl())) {
nextResourceId = new IdDt(nextReqEntry.getFullUrl());
}
}
if (nextResourceId.hasIdPart() && nextResourceId.getIdPart().matches("[a-zA-Z]+\\:.*") && !isPlaceholder(nextResourceId)) {
throw new InvalidRequestException("Invalid placeholder ID found: " + nextResourceId.getIdPart() + " - Must be of the form 'urn:uuid:[uuid]' or 'urn:oid:[oid]'");
}
if (nextResourceId.hasIdPart() && !nextResourceId.hasResourceType() && !isPlaceholder(nextResourceId)) {
nextResourceId = new IdDt(toResourceName(res.getClass()), nextResourceId.getIdPart());
res.setId(nextResourceId);
}
/*
* Ensure that the bundle doesn't have any duplicates, since this causes all kinds of weirdness
*/
if (isPlaceholder(nextResourceId)) {
if (!allIds.add(nextResourceId)) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextResourceId));
}
} else if (nextResourceId.hasResourceType() && nextResourceId.hasIdPart()) {
IdDt nextId = nextResourceId.toUnqualifiedVersionless();
if (!allIds.add(nextId)) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionContainsMultipleWithDuplicateId", nextId));
}
}
}
HTTPVerbEnum verb = nextReqEntry.getRequest().getMethodElement().getValueAsEnum();
if (verb == null) {
throw new InvalidRequestException(getContext().getLocalizer().getMessage(BaseHapiFhirSystemDao.class, "transactionEntryHasInvalidVerb", nextReqEntry.getRequest().getMethod()));
}
String resourceType = res != null ? getContext().getResourceDefinition(res).getName() : null;
Entry nextRespEntry = response.getEntry().get(originalRequestOrder.get(nextReqEntry));
switch (verb) {
case POST: {
// CREATE
@SuppressWarnings("rawtypes")
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
res.setId((String) null);
DaoMethodOutcome outcome;
outcome = resourceDao.create(res, nextReqEntry.getRequest().getIfNoneExist(), false);
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
break;
}
case DELETE: {
// DELETE
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
UrlParts parts = UrlUtil.parseUrl(url);
ca.uhn.fhir.jpa.dao.IFhirResourceDao<? extends IBaseResource> dao = toDao(parts, verb.getCode(), url);
int status = Constants.STATUS_HTTP_204_NO_CONTENT;
if (parts.getResourceId() != null) {
ResourceTable deleted = dao.delete(new IdDt(parts.getResourceType(), parts.getResourceId()), deleteConflicts);
if (deleted != null) {
deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless());
}
} else {
List<ResourceTable> allDeleted = dao.deleteByUrl(parts.getResourceType() + '?' + parts.getParams(), deleteConflicts);
for (ResourceTable deleted : allDeleted) {
deletedResources.add(deleted.getIdDt().toUnqualifiedVersionless());
}
if (allDeleted.isEmpty()) {
status = Constants.STATUS_HTTP_404_NOT_FOUND;
}
}
nextRespEntry.getResponse().setStatus(toStatusString(status));
break;
}
case PUT: {
// UPDATE
@SuppressWarnings("rawtypes")
IFhirResourceDao resourceDao = getDaoOrThrowException(res.getClass());
DaoMethodOutcome outcome;
String url = extractTransactionUrlOrThrowException(nextReqEntry, verb);
UrlParts parts = UrlUtil.parseUrl(url);
if (isNotBlank(parts.getResourceId())) {
res.setId(new IdDt(parts.getResourceType(), parts.getResourceId()));
outcome = resourceDao.update(res, null, false);
} else {
res.setId((String) null);
outcome = resourceDao.update(res, parts.getResourceType() + '?' + parts.getParams(), false);
}
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
break;
}
}
}
/*
* Make sure that there are no conflicts from deletions. E.g. we can't delete something
* if something else has a reference to it.. Unless the thing that has a reference to it
* was also deleted as a part of this transaction, which is why we check this now at the
* end.
*/
for (Iterator<DeleteConflict> iter = deleteConflicts.iterator(); iter.hasNext(); ) {
DeleteConflict next = iter.next();
if (deletedResources.contains(next.getTargetId().toVersionless())) {
iter.remove();
}
}
validateDeleteConflictsEmptyOrThrowException(deleteConflicts);
/*
* Perform ID substitutions and then index each resource we have saved
*/
FhirTerser terser = getContext().newTerser();
for (DaoMethodOutcome nextOutcome : idToPersistedOutcome.values()) {
IResource nextResource = (IResource) nextOutcome.getResource();
if (nextResource == null) {
continue;
}
List<BaseResourceReferenceDt> allRefs = terser.getAllPopulatedChildElementsOfType(nextResource, BaseResourceReferenceDt.class);
for (BaseResourceReferenceDt nextRef : allRefs) {
IdDt nextId = nextRef.getReference();
if (idSubstitutions.containsKey(nextId)) {
IdDt newId = idSubstitutions.get(nextId);
ourLog.info(" * Replacing resource ref {} with {}", nextId, newId);
nextRef.setReference(newId);
} else {
ourLog.debug(" * Reference [{}] does not exist in bundle", nextId);
}
}
InstantDt deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get(nextResource);
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
updateEntity(nextResource, nextOutcome.getEntity(), false, deletedTimestampOrNull, true, false, updateTime);
}
myEntityManager.flush();
/*
* Double check we didn't allow any duplicates we shouldn't have
*/
for (Entry nextEntry : theRequest.getEntry()) {
if (nextEntry.getRequest().getMethodElement().getValueAsEnum() == HTTPVerbEnum.POST) {
String matchUrl = nextEntry.getRequest().getIfNoneExist();
if (isNotBlank(matchUrl)) {
IFhirResourceDao<?> resourceDao = getDao(nextEntry.getResource().getClass());
Set<Long> val = resourceDao.processMatchUrl(matchUrl);
if (val.size() > 1) {
throw new InvalidRequestException(
"Unable to process " + theActionName + " - Request would cause multiple resources to match URL: \"" + matchUrl + "\". Does transaction request contain duplicates?");
}
}
}
}
for (IdDt next : allIds) {
IdDt replacement = idSubstitutions.get(next);
if (replacement == null) {
continue;
}
if (replacement.equals(next)) {
continue;
}
ourLog.info("Placeholder resource ID \"{}\" was replaced with permanent ID \"{}\"", next, replacement);
}
/*
* Loop through the request and process any entries of type GET
*/
for (int i = 0; i < getEntries.size(); i++) {
Entry nextReqEntry = getEntries.get(i);
Integer originalOrder = originalRequestOrder.get(nextReqEntry);
Entry nextRespEntry = response.getEntry().get(originalOrder);
ServletSubRequestDetails requestDetails = new ServletSubRequestDetails();
requestDetails.setServletRequest(theRequestDetails.getServletRequest());
requestDetails.setRequestType(RequestTypeEnum.GET);
requestDetails.setServer(theRequestDetails.getServer());
String url = extractTransactionUrlOrThrowException(nextReqEntry, HTTPVerbEnum.GET);
int qIndex = url.indexOf('?');
ArrayListMultimap<String, String> paramValues = ArrayListMultimap.create();
requestDetails.setParameters(new HashMap<String, String[]>());
if (qIndex != -1) {
String params = url.substring(qIndex);
List<NameValuePair> parameters = translateMatchUrl(params);
for (NameValuePair next : parameters) {
paramValues.put(next.getName(), next.getValue());
}
for (java.util.Map.Entry<String, Collection<String>> nextParamEntry : paramValues.asMap().entrySet()) {
String[] nextValue = nextParamEntry.getValue().toArray(new String[nextParamEntry.getValue().size()]);
requestDetails.getParameters().put(nextParamEntry.getKey(), nextValue);
}
url = url.substring(0, qIndex);
}
requestDetails.setRequestPath(url);
requestDetails.setFhirServerBase(theRequestDetails.getFhirServerBase());
theRequestDetails.getServer().populateRequestDetailsFromRequestPath(requestDetails, url);
BaseMethodBinding<?> method = theRequestDetails.getServer().determineResourceMethod(requestDetails, url);
if (method == null) {
throw new IllegalArgumentException("Unable to handle GET " + url);
}
if (isNotBlank(nextReqEntry.getRequest().getIfMatch())) {
requestDetails.addHeader(Constants.HEADER_IF_MATCH, nextReqEntry.getRequest().getIfMatch());
}
if (isNotBlank(nextReqEntry.getRequest().getIfNoneExist())) {
requestDetails.addHeader(Constants.HEADER_IF_NONE_EXIST, nextReqEntry.getRequest().getIfNoneExist());
}
if (isNotBlank(nextReqEntry.getRequest().getIfNoneMatch())) {
requestDetails.addHeader(Constants.HEADER_IF_NONE_MATCH, nextReqEntry.getRequest().getIfNoneMatch());
}
if (method instanceof BaseResourceReturningMethodBinding) {
try {
ResourceOrDstu1Bundle responseData = ((BaseResourceReturningMethodBinding) method).invokeServer(theRequestDetails.getServer(), requestDetails, new byte[0]);
IBaseResource resource = responseData.getResource();
if (paramValues.containsKey(Constants.PARAM_SUMMARY) || paramValues.containsKey(Constants.PARAM_CONTENT)) {
resource = filterNestedBundle(requestDetails, resource);
}
nextRespEntry.setResource((IResource) resource);
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
} catch (NotModifiedException e) {
nextRespEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_304_NOT_MODIFIED));
}
} else {
throw new IllegalArgumentException("Unable to handle GET " + url);
}
}
long delay = System.currentTimeMillis() - start;
ourLog.info(theActionName + " completed in {}ms", new Object[] { delay });
response.setType(BundleTypeEnum.TRANSACTION_RESPONSE);
return response;
}
private static void handleTransactionCreateOrUpdateOutcome(Map<IdDt, IdDt> idSubstitutions, Map<IdDt, DaoMethodOutcome> idToPersistedOutcome, IdDt nextResourceId, DaoMethodOutcome outcome,
Entry newEntry, String theResourceType, IResource theRes) {
IdDt newId = (IdDt) outcome.getId().toUnqualifiedVersionless();
IdDt resourceId = isPlaceholder(nextResourceId) ? nextResourceId : nextResourceId.toUnqualifiedVersionless();
if (newId.equals(resourceId) == false) {
idSubstitutions.put(resourceId, newId);
if (isPlaceholder(resourceId)) {
/*
* The correct way for substitution IDs to be is to be with no resource type, but we'll accept the qualified kind too just to be lenient.
*/
idSubstitutions.put(new IdDt(theResourceType + '/' + resourceId.getValue()), newId);
}
}
idToPersistedOutcome.put(newId, outcome);
if (outcome.getCreated().booleanValue()) {
newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_201_CREATED));
} else {
newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
}
newEntry.getResponse().setLocation(outcome.getId().toUnqualified().getValue());
newEntry.getResponse().setEtag(outcome.getId().getVersionIdPart());
newEntry.getResponse().setLastModified(ResourceMetadataKeyEnum.UPDATED.get(theRes));
}
private static boolean isPlaceholder(IdDt theId) {
if ("urn:oid:".equals(theId.getBaseUrl()) || "urn:uuid:".equals(theId.getBaseUrl())) {
return true;
}
return false;
}
private static String toStatusString(int theStatusCode) {
return Integer.toString(theStatusCode) + " " + defaultString(Constants.HTTP_STATUS_NAMES.get(theStatusCode));
}
//@formatter:off
/**
* Transaction Order, per the spec:
*
* Process any DELETE interactions
* Process any POST interactions
* Process any PUT interactions
* Process any GET interactions
*/
//@formatter:off
public class TransactionSorter implements Comparator<Entry> {
@Override
public int compare(Entry theO1, Entry theO2) {
int o1 = toOrder(theO1);
int o2 = toOrder(theO2);
return o1 - o2;
}
private int toOrder(Entry theO1) {
int o1 = 0;
if (theO1.getRequest().getMethodElement().getValueAsEnum() != null) {
switch (theO1.getRequest().getMethodElement().getValueAsEnum()) {
case DELETE:
o1 = 1;
break;
case POST:
o1 = 2;
break;
case PUT:
o1 = 3;
break;
case GET:
o1 = 4;
break;
}
}
return o1;
}
}
}

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IBaseMetaType;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
@ -36,7 +37,6 @@ import ca.uhn.fhir.jpa.entity.TagTypeEnum;
import ca.uhn.fhir.jpa.util.DeleteConflict;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.param.DateRangeParam;
@ -97,22 +97,22 @@ public interface IFhirResourceDao<T extends IBaseResource> extends IDao {
/**
* Not supported in DSTU1!
*/
MetaDt metaAddOperation(IIdType theId1, MetaDt theMetaAdd);
<MT extends IBaseMetaType> MT metaAddOperation(IIdType theId1, MT theMetaAdd);
/**
* Not supported in DSTU1!
*/
MetaDt metaDeleteOperation(IIdType theId1, MetaDt theMetaDel);
<MT extends IBaseMetaType> MT metaDeleteOperation(IIdType theId1, MT theMetaDel);
/**
* Not supported in DSTU1!
*/
MetaDt metaGetOperation();
<MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType);
/**
* Not supported in DSTU1!
*/
MetaDt metaGetOperation(IIdType theId);
<MT extends IBaseMetaType> MT metaGetOperation(Class<MT> theType, IIdType theId);
Set<Long> processMatchUrl(String theMatchUrl);

View File

@ -23,24 +23,21 @@ package ca.uhn.fhir.jpa.dao;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.resource.ValueSet;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
public interface IFhirResourceDaoValueSet<T extends IBaseResource> extends IFhirResourceDao<T> {
public interface IFhirResourceDaoValueSet<T extends IBaseResource, CD, CC> extends IFhirResourceDao<T> {
ValueSet expand(IIdType theId, String theFilter);
T expand(IIdType theId, String theFilter);
ValueSet expand(ValueSet theSource, String theFilter);
T expand(T theSource, String theFilter);
ValueSet expandByIdentifier(String theUri, String theFilter);
T expandByIdentifier(String theUri, String theFilter);
LookupCodeResult lookupCode(CodeDt theCode, UriDt theSystem, CodingDt theCoding);
LookupCodeResult lookupCode(CodeDt theCode, UriDt theSystem, CD theCoding);
ValidateCodeResult validateCode(UriDt theValueSetIdentifier, IIdType theId, CodeDt theCode, UriDt theSystem, StringDt theDisplay, CodingDt theCoding, CodeableConceptDt theCodeableConcept);
ValidateCodeResult validateCode(UriDt theValueSetIdentifier, IIdType theId, CodeDt theCode, UriDt theSystem, StringDt theDisplay, CD theCoding, CC theCodeableConcept);
public class LookupCodeResult {
private String myCodeDisplay;

View File

@ -24,7 +24,6 @@ import java.util.Date;
import java.util.Map;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.IBundleProvider;
@ -32,7 +31,7 @@ import ca.uhn.fhir.rest.server.IBundleProvider;
* @param <T>
* The bundle type
*/
public interface IFhirSystemDao<T> extends IDao {
public interface IFhirSystemDao<T, MT> extends IDao {
/**
* Use with caution! This deletes everything!!
@ -55,7 +54,7 @@ public interface IFhirSystemDao<T> extends IDao {
/**
* Not supported for DSTU1
*/
MetaDt metaGetOperation();
MT metaGetOperation();
int performReindexingPass(Integer theCount);

View File

@ -0,0 +1,105 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.ValueSet;
import org.hl7.fhir.instance.model.ValueSet.ConceptSetComponent;
import org.hl7.fhir.instance.model.ValueSet.ValueSetExpansionComponent;
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.rest.param.UriParam;
import ca.uhn.fhir.rest.server.IBundleProvider;
public class JpaValidationSupportDstu21 implements IJpaValidationSupport {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(JpaValidationSupportDstu21.class);
@Autowired
@Qualifier("myFhirContextDstu2Hl7Org")
private FhirContext myRiCtx;
@Autowired
@Qualifier("myStructureDefinitionDaoDstu21")
private IFhirResourceDao<ca.uhn.fhir.model.dstu21.resource.StructureDefinition> myStructureDefinitionDao;
@Autowired
@Qualifier("myValueSetDaoDstu21")
private IFhirResourceDao<ca.uhn.fhir.model.dstu21.resource.ValueSet> myValueSetDao;
@Autowired
@Qualifier("myFhirContextDstu21")
private FhirContext myDstu21Ctx;
@Override
public ValueSetExpansionComponent expandValueSet(FhirContext theCtx, ConceptSetComponent theInclude) {
return null;
}
@Override
public ValueSet fetchCodeSystem(FhirContext theCtx, String theSystem) {
return null;
}
@Override
public <T extends IBaseResource> T fetchResource(FhirContext theContext, Class<T> theClass, String theUri) {
String resourceName = myRiCtx.getResourceDefinition(theClass).getName();
IBundleProvider search;
if ("ValueSet".equals(resourceName)) {
search = myValueSetDao.search(ca.uhn.fhir.model.dstu2.resource.ValueSet.SP_URL, new UriParam(theUri));
} else if ("StructureDefinition".equals(resourceName)) {
search = myStructureDefinitionDao.search(ca.uhn.fhir.model.dstu2.resource.StructureDefinition.SP_URL, new UriParam(theUri));
} else {
throw new IllegalArgumentException("Can't fetch resource type: " + resourceName);
}
if (search.size() == 0) {
return null;
}
if (search.size() > 1) {
ourLog.warn("Found multiple {} instances with URL search value of: {}", resourceName, theUri);
}
IBaseResource res = search.getResources(0, 1).get(0);
/*
* Validator wants RI structures and not HAPI ones, so convert
*
* TODO: we really need a more efficient way of converting.. Or maybe this will just go away when we move to RI structures
*/
String encoded = myDstu21Ctx.newJsonParser().encodeResourceToString(res);
return myRiCtx.newJsonParser().parseResource(theClass, encoded);
}
@Override
public boolean isCodeSystemSupported(FhirContext theCtx, String theSystem) {
return false;
}
@Override
public CodeValidationResult validateCode(FhirContext theCtx, String theCodeSystem, String theCode, String theDisplay) {
return null;
}
}

View File

@ -0,0 +1,660 @@
package ca.uhn.fhir.jpa.dao;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isBlank;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.measure.quantity.Quantity;
import javax.measure.unit.NonSI;
import javax.measure.unit.Unit;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.entity.BaseResourceIndexedSearchParam;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IPrimitiveDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.model.base.composite.BaseHumanNameDt;
import ca.uhn.fhir.model.dstu21.composite.AddressDt;
import ca.uhn.fhir.model.dstu21.composite.BoundCodeableConceptDt;
import ca.uhn.fhir.model.dstu21.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
import ca.uhn.fhir.model.dstu21.composite.ContactPointDt;
import ca.uhn.fhir.model.dstu21.composite.DurationDt;
import ca.uhn.fhir.model.dstu21.composite.HumanNameDt;
import ca.uhn.fhir.model.dstu21.composite.IdentifierDt;
import ca.uhn.fhir.model.dstu21.composite.PeriodDt;
import ca.uhn.fhir.model.dstu21.composite.QuantityDt;
import ca.uhn.fhir.model.dstu21.resource.Conformance.RestSecurity;
import ca.uhn.fhir.model.dstu21.resource.Location;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.dstu21.resource.Patient.Communication;
import ca.uhn.fhir.model.dstu21.resource.Questionnaire;
import ca.uhn.fhir.model.dstu21.resource.ValueSet;
import ca.uhn.fhir.model.dstu21.valueset.RestfulSecurityServiceEnum;
import ca.uhn.fhir.model.primitive.BaseDateTimeDt;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
public class SearchParamExtractorDstu21 extends BaseSearchParamExtractor implements ISearchParamExtractor {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchParamExtractorDstu21.class);
public SearchParamExtractorDstu21(FhirContext theContext) {
super(theContext);
}
private void addSearchTerm(ResourceTable theEntity, Set<ResourceIndexedSearchParamString> retVal, String resourceName, String searchTerm) {
if (isBlank(searchTerm)) {
return;
}
if (searchTerm.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
searchTerm = searchTerm.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
}
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(resourceName, BaseHapiFhirDao.normalizeString(searchTerm), searchTerm);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
private void addStringParam(ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> retVal, RuntimeSearchParam nextSpDef, String value) {
if (value.length() > ResourceIndexedSearchParamString.MAX_LENGTH) {
value = value.substring(0, ResourceIndexedSearchParamString.MAX_LENGTH);
}
ResourceIndexedSearchParamString nextEntity = new ResourceIndexedSearchParamString(nextSpDef.getName(), BaseHapiFhirDao.normalizeString(value), value);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
@Override
public Set<ResourceIndexedSearchParamCoords> extractSearchParamCoords(ResourceTable theEntity, IResource theResource) {
// TODO: implement
return Collections.emptySet();
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamDates(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
*/
@Override
public Set<ResourceIndexedSearchParamDate> extractSearchParamDates(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamDate> retVal = new HashSet<ResourceIndexedSearchParamDate>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.DATE) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null) {
continue;
}
ResourceIndexedSearchParamDate nextEntity;
if (nextObject instanceof BaseDateTimeDt) {
BaseDateTimeDt nextValue = (BaseDateTimeDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), nextValue.getValue(), nextValue.getValue());
} else if (nextObject instanceof PeriodDt) {
PeriodDt nextValue = (PeriodDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
nextEntity = new ResourceIndexedSearchParamDate(nextSpDef.getName(), nextValue.getStart(), nextValue.getEnd());
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
if (nextEntity != null) {
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
}
}
return retVal;
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamNumber(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
*/
@Override
public HashSet<ResourceIndexedSearchParamNumber> extractSearchParamNumber(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamNumber> retVal = new HashSet<ResourceIndexedSearchParamNumber>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.NUMBER) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IDatatype) nextObject).isEmpty()) {
continue;
}
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof DurationDt) {
DurationDt nextValue = (DurationDt) nextObject;
if (nextValue.getValueElement().isEmpty()) {
continue;
}
if (new UriDt(BaseHapiFhirDao.UCUM_NS).equals(nextValue.getSystemElement())) {
if (isNotBlank(nextValue.getCode())) {
Unit<? extends Quantity> unit = Unit.valueOf(nextValue.getCode());
javax.measure.converter.UnitConverter dayConverter = unit.getConverterTo(NonSI.DAY);
double dayValue = dayConverter.convert(nextValue.getValue().doubleValue());
DurationDt newValue = new DurationDt();
newValue.setSystem(BaseHapiFhirDao.UCUM_NS);
newValue.setCode(NonSI.DAY.toString());
newValue.setValue(dayValue);
nextValue = newValue;
/*
* @SuppressWarnings("unchecked") PhysicsUnit<? extends
* org.unitsofmeasurement.quantity.Quantity<?>> unit = (PhysicsUnit<? extends
* org.unitsofmeasurement.quantity.Quantity<?>>)
* UCUMFormat.getCaseInsensitiveInstance().parse(nextValue.getCode().getValue(), null); if
* (unit.isCompatible(UCUM.DAY)) {
*
* @SuppressWarnings("unchecked") PhysicsUnit<org.unitsofmeasurement.quantity.Time> timeUnit =
* (PhysicsUnit<Time>) unit; UnitConverter conv = timeUnit.getConverterTo(UCUM.DAY); double
* dayValue = conv.convert(nextValue.getValue().getValue().doubleValue()); DurationDt newValue =
* new DurationDt(); newValue.setSystem(UCUM_NS); newValue.setCode(UCUM.DAY.getSymbol());
* newValue.setValue(dayValue); nextValue=newValue; }
*/
}
}
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else if (nextObject instanceof QuantityDt) {
QuantityDt nextValue = (QuantityDt) nextObject;
if (nextValue.getValueElement().isEmpty()) {
continue;
}
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, nextValue.getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else if (nextObject instanceof IntegerDt) {
IntegerDt nextValue = (IntegerDt) nextObject;
if (nextValue.getValue() == null) {
continue;
}
ResourceIndexedSearchParamNumber nextEntity = new ResourceIndexedSearchParamNumber(resourceName, new BigDecimal(nextValue.getValue()));
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
}
return retVal;
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamQuantity(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
*/
@Override
public Set<ResourceIndexedSearchParamQuantity> extractSearchParamQuantity(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamQuantity> retVal = new HashSet<ResourceIndexedSearchParamQuantity>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.QUANTITY) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IDatatype) nextObject).isEmpty()) {
continue;
}
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof QuantityDt) {
QuantityDt nextValue = (QuantityDt) nextObject;
if (nextValue.getValueElement().isEmpty()) {
continue;
}
ResourceIndexedSearchParamQuantity nextEntity = new ResourceIndexedSearchParamQuantity(resourceName, nextValue.getValueElement().getValue(), nextValue.getSystemElement().getValueAsString(), nextValue.getCode());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
}
return retVal;
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamStrings(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
*/
@Override
public Set<ResourceIndexedSearchParamString> extractSearchParamStrings(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamString> retVal = new HashSet<ResourceIndexedSearchParamString>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.STRING) {
continue;
}
String nextPath = nextSpDef.getPath();
String resourceName = nextSpDef.getName();
if (isBlank(nextPath)) {
// TODO: implement phonetic, and any others that have no path
if ("Questionnaire".equals(def.getName()) && nextSpDef.getName().equals("title")) {
Questionnaire q = (Questionnaire) theResource;
String title = "";//q.getGroup().getTitle();
addSearchTerm(theEntity, retVal, resourceName, title);
}
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IDatatype) nextObject).isEmpty()) {
continue;
}
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
String searchTerm = nextValue.getValueAsString();
addSearchTerm(theEntity, retVal, resourceName, searchTerm);
} else {
if (nextObject instanceof BaseHumanNameDt) {
ArrayList<StringDt> allNames = new ArrayList<StringDt>();
HumanNameDt nextHumanName = (HumanNameDt) nextObject;
allNames.addAll(nextHumanName.getFamily());
allNames.addAll(nextHumanName.getGiven());
for (StringDt nextName : allNames) {
addSearchTerm(theEntity, retVal, resourceName, nextName.getValue());
}
} else if (nextObject instanceof AddressDt) {
ArrayList<StringDt> allNames = new ArrayList<StringDt>();
AddressDt nextAddress = (AddressDt) nextObject;
allNames.addAll(nextAddress.getLine());
allNames.add(nextAddress.getCityElement());
allNames.add(nextAddress.getStateElement());
allNames.add(nextAddress.getCountryElement());
allNames.add(nextAddress.getPostalCodeElement());
for (StringDt nextName : allNames) {
addSearchTerm(theEntity, retVal, resourceName, nextName.getValue());
}
} else if (nextObject instanceof ContactPointDt) {
ContactPointDt nextContact = (ContactPointDt) nextObject;
if (nextContact.getValueElement().isEmpty() == false) {
addSearchTerm(theEntity, retVal, resourceName, nextContact.getValue());
}
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
}
}
}
}
}
return retVal;
}
/*
* (non-Javadoc)
*
* @see ca.uhn.fhir.jpa.dao.ISearchParamExtractor#extractSearchParamTokens(ca.uhn.fhir.jpa.entity.ResourceTable,
* ca.uhn.fhir.model.api.IResource)
*/
@Override
public Set<BaseResourceIndexedSearchParam> extractSearchParamTokens(ResourceTable theEntity, IResource theResource) {
HashSet<BaseResourceIndexedSearchParam> retVal = new HashSet<BaseResourceIndexedSearchParam>();
String useSystem = null;
if (theResource instanceof ValueSet) {
ValueSet vs = (ValueSet) theResource;
useSystem = vs.getCodeSystem().getSystem();
}
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.TOKEN) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
List<String> systems = new ArrayList<String>();
List<String> codes = new ArrayList<String>();
String needContactPointSystem = null;
if (nextPath.endsWith("(system=phone)")) {
nextPath = nextPath.substring(0, nextPath.length() - "(system=phone)".length());
needContactPointSystem = "phone";
}
if (nextPath.endsWith("(system=email)")) {
nextPath = nextPath.substring(0, nextPath.length() - "(system=email)".length());
needContactPointSystem = "email";
}
for (Object nextObject : extractValues(nextPath, theResource)) {
// Patient:language
if (nextObject instanceof Patient.Communication) {
Communication nextValue = (Patient.Communication) nextObject;
nextObject = nextValue.getLanguage();
}
if (nextObject instanceof IdentifierDt) {
IdentifierDt nextValue = (IdentifierDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
String system = StringUtils.defaultIfBlank(nextValue.getSystemElement().getValueAsString(), null);
String value = nextValue.getValueElement().getValue();
if (isNotBlank(value)) {
systems.add(system);
codes.add(value);
}
if (isNotBlank(nextValue.getType().getText())) {
addStringParam(theEntity, retVal, nextSpDef, nextValue.getType().getText());
}
} else if (nextObject instanceof ContactPointDt) {
ContactPointDt nextValue = (ContactPointDt) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if (isNotBlank(needContactPointSystem)) {
if (!needContactPointSystem.equals(nextValue.getSystemElement().getValueAsString())) {
continue;
}
}
systems.add(nextValue.getSystemElement().getValueAsString());
codes.add(nextValue.getValueElement().getValue());
} else if (nextObject instanceof BoundCodeDt) {
BoundCodeDt<?> obj = (BoundCodeDt<?>) nextObject;
String system = extractSystem(obj);
String code = obj.getValue();
if (isNotBlank(code)) {
systems.add(system);
codes.add(code);
}
} else if (nextObject instanceof IPrimitiveDatatype<?>) {
IPrimitiveDatatype<?> nextValue = (IPrimitiveDatatype<?>) nextObject;
if (nextValue.isEmpty()) {
continue;
}
if ("ValueSet.codeSystem.concept.code".equals(nextPath)) {
systems.add(useSystem);
} else {
systems.add(null);
}
codes.add(nextValue.getValueAsString());
} else if (nextObject instanceof CodingDt) {
CodingDt nextValue = (CodingDt) nextObject;
extractTokensFromCoding(systems, codes, theEntity, retVal, nextSpDef, nextValue);
} else if (nextObject instanceof CodeableConceptDt) {
CodeableConceptDt nextCC = (CodeableConceptDt) nextObject;
if (!nextCC.getTextElement().isEmpty()) {
addStringParam(theEntity, retVal, nextSpDef, nextCC.getTextElement().getValue());
}
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
} else if (nextObject instanceof RestSecurity) {
// Conformance.security search param points to something kind of useless right now - This should probably
// be fixed.
RestSecurity sec = (RestSecurity) nextObject;
for (BoundCodeableConceptDt<RestfulSecurityServiceEnum> nextCC : sec.getService()) {
extractTokensFromCodeableConcept(systems, codes, nextCC, theEntity, retVal, nextSpDef);
}
} else if (nextObject instanceof Location.Position) {
ourLog.warn("Position search not currently supported, not indexing location");
continue;
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + nextSpDef.getName() + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
assert systems.size() == codes.size() : "Systems contains " + systems + ", codes contains: " + codes;
Set<Pair<String, String>> haveValues = new HashSet<Pair<String, String>>();
for (int i = 0; i < systems.size(); i++) {
String system = systems.get(i);
String code = codes.get(i);
if (isBlank(system) && isBlank(code)) {
continue;
}
if (system != null && system.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
system = system.substring(0, ResourceIndexedSearchParamToken.MAX_LENGTH);
}
if (code != null && code.length() > ResourceIndexedSearchParamToken.MAX_LENGTH) {
code = code.substring(0, ResourceIndexedSearchParamToken.MAX_LENGTH);
}
Pair<String, String> nextPair = Pair.of(system, code);
if (haveValues.contains(nextPair)) {
continue;
}
haveValues.add(nextPair);
ResourceIndexedSearchParamToken nextEntity;
nextEntity = new ResourceIndexedSearchParamToken(nextSpDef.getName(), system, code);
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
}
}
return retVal;
}
@Override
public Set<ResourceIndexedSearchParamUri> extractSearchParamUri(ResourceTable theEntity, IResource theResource) {
HashSet<ResourceIndexedSearchParamUri> retVal = new HashSet<ResourceIndexedSearchParamUri>();
RuntimeResourceDefinition def = getContext().getResourceDefinition(theResource);
for (RuntimeSearchParam nextSpDef : def.getSearchParams()) {
if (nextSpDef.getParamType() != RestSearchParameterTypeEnum.URI) {
continue;
}
String nextPath = nextSpDef.getPath();
if (isBlank(nextPath)) {
continue;
}
for (Object nextObject : extractValues(nextPath, theResource)) {
if (nextObject == null || ((IDatatype) nextObject).isEmpty()) {
continue;
}
String resourceName = nextSpDef.getName();
boolean multiType = false;
if (nextPath.endsWith("[x]")) {
multiType = true;
}
if (nextObject instanceof UriDt) {
UriDt nextValue = (UriDt) nextObject;
if (isBlank(nextValue.getValue())) {
continue;
}
ourLog.trace("Adding param: {}, {}", resourceName, nextValue.getValue());
ResourceIndexedSearchParamUri nextEntity = new ResourceIndexedSearchParamUri(resourceName, nextValue.getValue());
nextEntity.setResource(theEntity);
retVal.add(nextEntity);
} else {
if (!multiType) {
throw new ConfigurationException("Search param " + resourceName + " is of unexpected datatype: " + nextObject.getClass());
} else {
continue;
}
}
}
}
return retVal;
}
private void extractTokensFromCodeableConcept(List<String> theSystems, List<String> theCodes, CodeableConceptDt theCodeableConcept, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef) {
for (CodingDt nextCoding : theCodeableConcept.getCoding()) {
extractTokensFromCoding(theSystems, theCodes, theEntity, theListToPopulate, theParameterDef, nextCoding);
}
}
private void extractTokensFromCoding(List<String> theSystems, List<String> theCodes, ResourceTable theEntity, Set<BaseResourceIndexedSearchParam> theListToPopulate, RuntimeSearchParam theParameterDef, CodingDt nextCoding) {
if (nextCoding != null && !nextCoding.isEmpty()) {
String nextSystem = nextCoding.getSystemElement().getValueAsString();
String nextCode = nextCoding.getCodeElement().getValue();
if (isNotBlank(nextSystem) || isNotBlank(nextCode)) {
theSystems.add(nextSystem);
theCodes.add(nextCode);
}
if (!nextCoding.getDisplayElement().isEmpty()) {
addStringParam(theEntity, theListToPopulate, theParameterDef, nextCoding.getDisplayElement().getValue());
}
}
}
private static <T extends Enum<?>> String extractSystem(BoundCodeDt<T> theBoundCode) {
if (theBoundCode.getValueAsEnum() != null) {
IValueSetEnumBinder<T> binder = theBoundCode.getBinder();
return binder.toSystemString(theBoundCode.getValueAsEnum());
}
return null;
}
}

View File

@ -29,7 +29,6 @@ import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
public interface ISubscriptionTableDao extends JpaRepository<SubscriptionTable, Long> {
@ -48,5 +47,5 @@ public interface ISubscriptionTableDao extends JpaRepository<SubscriptionTable,
public Collection<SubscriptionTable> findInactiveBeforeCutoff(@Param("cutoff") Date theCutoff);
@Query("SELECT t.myId FROM SubscriptionTable t WHERE t.myStatus = :status AND t.myNextCheck <= :next_check")
public Collection<Long> finsSubscriptionsWhichNeedToBeChecked(@Param("status") SubscriptionStatusEnum theStatus, @Param("next_check") Date theNextCheck);
public Collection<Long> findSubscriptionsWhichNeedToBeChecked(@Param("status") String theStatus, @Param("next_check") Date theNextCheck);
}

View File

@ -51,7 +51,7 @@ public abstract class BaseHasResource {
@Enumerated(EnumType.STRING)
private ResourceEncodingEnum myEncoding;
@Column(name = "RES_VERSION", nullable = true, length = 5)
@Column(name = "RES_VERSION", nullable = true, length = 7)
@Enumerated(EnumType.STRING)
private FhirVersionEnum myFhirVersion;

View File

@ -25,8 +25,6 @@ import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.ForeignKey;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
@ -42,8 +40,6 @@ import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.UniqueConstraint;
import ca.uhn.fhir.model.dstu2.valueset.SubscriptionStatusEnum;
//@formatter:off
@Entity
@Table(name = "HFJ_SUBSCRIPTION", uniqueConstraints= {
@ -89,8 +85,7 @@ public class SubscriptionTable {
private Long myResId;
@Column(name = "SUBSCRIPTION_STATUS", nullable = false, length = 20)
@Enumerated(EnumType.STRING)
private SubscriptionStatusEnum myStatus;
private String myStatus;
//@formatter:off
@OneToOne()
@ -124,7 +119,7 @@ public class SubscriptionTable {
return myNextCheck;
}
public SubscriptionStatusEnum getStatus() {
public String getStatus() {
return myStatus;
}
@ -152,7 +147,7 @@ public class SubscriptionTable {
myNextCheck = theNextCheck;
}
public void setStatus(SubscriptionStatusEnum theStatus) {
public void setStatus(String theStatus) {
myStatus = theStatus;
}

View File

@ -26,18 +26,18 @@ import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
public class BaseJpaPlainProvider extends BaseJpaProvider {
private IFhirSystemDao<?> myDao;
private IFhirSystemDao<?,?> myDao;
public BaseJpaPlainProvider() {
// nothing
}
@Required
public void setDao(IFhirSystemDao<?> theDao) {
public void setDao(IFhirSystemDao<?,?> theDao) {
myDao = theDao;
}
public IFhirSystemDao<?> getDao() {
public IFhirSystemDao<?,?> getDao() {
return myDao;
}

View File

@ -0,0 +1,99 @@
package ca.uhn.fhir.jpa.provider;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoEncounter;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.dstu21.resource.Encounter;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Sort;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.server.Constants;
public class BaseJpaResourceProviderEncounterDstu21 extends JpaResourceProviderDstu21<Encounter> {
/**
* Encounter/123/$everything
*/
//@formatter:off
@Operation(name = "everything", idempotent = true)
public ca.uhn.fhir.rest.server.IBundleProvider EncounterInstanceEverything(
javax.servlet.http.HttpServletRequest theServletRequest,
@IdParam
ca.uhn.fhir.model.primitive.IdDt theId,
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
@OperationParam(name = Constants.PARAM_COUNT)
ca.uhn.fhir.model.primitive.UnsignedIntDt theCount,
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
DateRangeParam theLastUpdated,
@Sort
SortSpec theSortSpec
) {
//@formatter:on
startRequest(theServletRequest);
try {
return ((IFhirResourceDaoEncounter<Encounter>)getDao()).encounterInstanceEverything(theServletRequest, theId, theCount, theLastUpdated, theSortSpec);
} finally {
endRequest(theServletRequest);
}}
/**
* /Encounter/$everything
*/
//@formatter:off
@Operation(name = "everything", idempotent = true)
public ca.uhn.fhir.rest.server.IBundleProvider EncounterTypeEverything(
javax.servlet.http.HttpServletRequest theServletRequest,
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
@OperationParam(name = Constants.PARAM_COUNT)
ca.uhn.fhir.model.primitive.UnsignedIntDt theCount,
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
DateRangeParam theLastUpdated,
@Sort
SortSpec theSortSpec
) {
//@formatter:on
startRequest(theServletRequest);
try {
return ((IFhirResourceDaoEncounter<Encounter>)getDao()).encounterTypeEverything(theServletRequest, theCount, theLastUpdated, theSortSpec);
} finally {
endRequest(theServletRequest);
}
}
}

View File

@ -0,0 +1,139 @@
package ca.uhn.fhir.jpa.provider;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.util.List;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Sort;
import ca.uhn.fhir.rest.api.SortSpec;
import ca.uhn.fhir.rest.param.DateRangeParam;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.Constants;
public class BaseJpaResourceProviderPatientDstu21 extends JpaResourceProviderDstu21<Patient> {
/**
* Patient/123/$everything
*/
//@formatter:off
@Operation(name = "everything", idempotent = true)
public ca.uhn.fhir.rest.server.IBundleProvider patientInstanceEverything(
javax.servlet.http.HttpServletRequest theServletRequest,
@IdParam
ca.uhn.fhir.model.primitive.IdDt theId,
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
@OperationParam(name = Constants.PARAM_COUNT)
ca.uhn.fhir.model.primitive.UnsignedIntDt theCount,
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
DateRangeParam theLastUpdated,
@Description(shortDefinition="Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
@OperationParam(name = Constants.PARAM_CONTENT, min=0, max=OperationParam.MAX_UNLIMITED)
List<StringDt> theContent,
@Description(shortDefinition="Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
@OperationParam(name = Constants.PARAM_TEXT, min=0, max=OperationParam.MAX_UNLIMITED)
List<StringDt> theNarrative,
@Sort
SortSpec theSortSpec
) {
//@formatter:on
startRequest(theServletRequest);
try {
return ((IFhirResourceDaoPatient<Patient>) getDao()).patientInstanceEverything(theServletRequest, theId, theCount, theLastUpdated, theSortSpec, toStringAndList(theContent), toStringAndList(theNarrative));
} finally {
endRequest(theServletRequest);
}
}
/**
* /Patient/$everything
*/
//@formatter:off
@Operation(name = "everything", idempotent = true)
public ca.uhn.fhir.rest.server.IBundleProvider patientTypeEverything(
javax.servlet.http.HttpServletRequest theServletRequest,
@Description(formalDefinition="Results from this method are returned across multiple pages. This parameter controls the size of those pages.")
@OperationParam(name = Constants.PARAM_COUNT)
ca.uhn.fhir.model.primitive.UnsignedIntDt theCount,
@Description(shortDefinition="Only return resources which were last updated as specified by the given range")
@OperationParam(name = Constants.PARAM_LASTUPDATED, min=0, max=1)
DateRangeParam theLastUpdated,
@Description(shortDefinition="Filter the resources to return only resources matching the given _content filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
@OperationParam(name = Constants.PARAM_CONTENT, min=0, max=OperationParam.MAX_UNLIMITED)
List<StringDt> theContent,
@Description(shortDefinition="Filter the resources to return only resources matching the given _text filter (note that this filter is applied only to results which link to the given patient, not to the patient itself or to supporting resources linked to by the matched resources)")
@OperationParam(name = Constants.PARAM_TEXT, min=0, max=OperationParam.MAX_UNLIMITED)
List<StringDt> theNarrative,
@Sort
SortSpec theSortSpec
) {
//@formatter:on
startRequest(theServletRequest);
try {
return ((IFhirResourceDaoPatient<Patient>) getDao()).patientTypeEverything(theServletRequest, theCount, theLastUpdated, theSortSpec, toStringAndList(theContent), toStringAndList(theNarrative));
} finally {
endRequest(theServletRequest);
}
}
private StringAndListParam toStringAndList(List<StringDt> theNarrative) {
StringAndListParam retVal = new StringAndListParam();
if (theNarrative != null) {
for (StringDt next : theNarrative) {
if (isNotBlank(next.getValue())) {
retVal.addAnd(new StringOrListParam().addOr(new StringParam(next.getValue())));
}
}
}
if (retVal.getValuesAsQueryTokens().isEmpty()) {
return null;
}
return retVal;
}
}

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.jpa.provider;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import ca.uhn.fhir.model.dstu2.resource.QuestionnaireResponse;
public class BaseJpaResourceProviderQuestionnaireResponseDstu21 extends JpaResourceProviderDstu2<QuestionnaireResponse> {
// nothing yet
}

View File

@ -70,7 +70,7 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet> dao = (IFhirResourceDaoValueSet<ValueSet>) getDao();
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
if (haveId) {
return dao.expand(theId, toFilterString(theFilter));
} else if (haveIdentifier) {
@ -121,7 +121,7 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet> dao = (IFhirResourceDaoValueSet<ValueSet>) getDao();
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding);
if (result.isFound()==false) {
throw new ResourceNotFoundException("Unable to find code[" + result.getSearchedForCode() + "] in system[" + result.getSearchedForSystem() + "]");
@ -160,7 +160,7 @@ public class BaseJpaResourceProviderValueSetDstu2 extends JpaResourceProviderDst
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet> dao = (IFhirResourceDaoValueSet<ValueSet>) getDao();
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
ValidateCodeResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept);
Parameters retVal = new Parameters();
retVal.addParameter().setName("result").setValue(new BooleanDt(result.isResult()));

View File

@ -0,0 +1,180 @@
package ca.uhn.fhir.jpa.provider;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.BooleanUtils;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.LookupCodeResult;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
import ca.uhn.fhir.model.dstu21.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
import ca.uhn.fhir.model.dstu21.resource.Parameters;
import ca.uhn.fhir.model.dstu21.resource.ValueSet;
import ca.uhn.fhir.model.primitive.BooleanDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
public class BaseJpaResourceProviderValueSetDstu21 extends JpaResourceProviderDstu2<ValueSet> {
//@formatter:off
@Operation(name = "$expand", idempotent = true)
public ValueSet expand(
HttpServletRequest theServletRequest,
@IdParam(optional=true) IdDt theId,
@OperationParam(name="valueSet", min=0, max=1) ValueSet theValueSet,
@OperationParam(name="identifier", min=0, max=1) UriDt theIdentifier,
@OperationParam(name = "filter", min=0, max=1) StringDt theFilter) {
//@formatter:on
boolean haveId = theId != null && theId.hasIdPart();
boolean haveIdentifier = theIdentifier != null && isNotBlank(theIdentifier.getValue());
boolean haveValueSet = theValueSet != null && theValueSet.isEmpty() == false;
if (!haveId && !haveIdentifier && !haveValueSet) {
throw new InvalidRequestException("$expand operation at the type level (no ID specified) requires an identifier or a valueSet as a part of the request");
}
if (moreThanOneTrue(haveId, haveIdentifier, haveValueSet)) {
throw new InvalidRequestException("$expand must EITHER be invoked at the type level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.");
}
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
if (haveId) {
return dao.expand(theId, toFilterString(theFilter));
} else if (haveIdentifier) {
return dao.expandByIdentifier(theIdentifier.getValue(), toFilterString(theFilter));
} else {
return dao.expand(theValueSet, toFilterString(theFilter));
}
} finally {
endRequest(theServletRequest);
}
}
private static boolean moreThanOneTrue(boolean... theBooleans) {
boolean haveOne = false;
for (boolean next : theBooleans) {
if (next) {
if (haveOne) {
return true;
} else {
haveOne = true;
}
}
}
return false;
}
private String toFilterString(StringDt theFilter) {
return theFilter != null ? theFilter.getValue() : null;
}
//@formatter:off
@Operation(name = "$lookup", idempotent = true, returnParameters= {
@OperationParam(name="name", type=StringDt.class, min=1),
@OperationParam(name="version", type=StringDt.class, min=0),
@OperationParam(name="display", type=StringDt.class, min=1),
@OperationParam(name="abstract", type=BooleanDt.class, min=1),
})
public Parameters lookup(
HttpServletRequest theServletRequest,
@OperationParam(name="code", min=0, max=1) CodeDt theCode,
@OperationParam(name="system", min=0, max=1) UriDt theSystem,
@OperationParam(name="coding", min=0, max=1) CodingDt theCoding
) {
//@formatter:on
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
LookupCodeResult result = dao.lookupCode(theCode, theSystem, theCoding);
if (result.isFound()==false) {
throw new ResourceNotFoundException("Unable to find code[" + result.getSearchedForCode() + "] in system[" + result.getSearchedForSystem() + "]");
}
Parameters retVal = new Parameters();
retVal.addParameter().setName("name").setValue(new StringDt(result.getCodeSystemDisplayName()));
if (isNotBlank(result.getCodeSystemVersion())) {
retVal.addParameter().setName("version").setValue(new StringDt(result.getCodeSystemVersion()));
}
retVal.addParameter().setName("display").setValue(new StringDt(result.getCodeDisplay()));
retVal.addParameter().setName("abstract").setValue(new BooleanDt(result.isCodeIsAbstract()));
return retVal;
} finally {
endRequest(theServletRequest);
}
}
//@formatter:off
@Operation(name = "$validate-code", idempotent = true, returnParameters= {
@OperationParam(name="result", type=BooleanDt.class, min=1),
@OperationParam(name="message", type=StringDt.class),
@OperationParam(name="display", type=StringDt.class)
})
public Parameters validateCode(
HttpServletRequest theServletRequest,
@IdParam(optional=true) IdDt theId,
@OperationParam(name="identifier", min=0, max=1) UriDt theValueSetIdentifier,
@OperationParam(name="code", min=0, max=1) CodeDt theCode,
@OperationParam(name="system", min=0, max=1) UriDt theSystem,
@OperationParam(name="display", min=0, max=1) StringDt theDisplay,
@OperationParam(name="coding", min=0, max=1) CodingDt theCoding,
@OperationParam(name="codeableConcept", min=0, max=1) CodeableConceptDt theCodeableConcept
) {
//@formatter:on
startRequest(theServletRequest);
try {
IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> dao = (IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt>) getDao();
ValidateCodeResult result = dao.validateCode(theValueSetIdentifier, theId, theCode, theSystem, theDisplay, theCoding, theCodeableConcept);
Parameters retVal = new Parameters();
retVal.addParameter().setName("result").setValue(new BooleanDt(result.isResult()));
if (isNotBlank(result.getMessage())) {
retVal.addParameter().setName("message").setValue(new StringDt(result.getMessage()));
}
if (isNotBlank(result.getDisplay())) {
retVal.addParameter().setName("display").setValue(new StringDt(result.getDisplay()));
}
return retVal;
} finally {
endRequest(theServletRequest);
}
}
}

View File

@ -33,16 +33,16 @@ import ca.uhn.fhir.rest.annotation.History;
import ca.uhn.fhir.rest.annotation.Since;
import ca.uhn.fhir.rest.server.IBundleProvider;
public class BaseJpaSystemProvider<T> extends BaseJpaProvider {
public class BaseJpaSystemProvider<T, MT> extends BaseJpaProvider {
private IFhirSystemDao<T> myDao;
private IFhirSystemDao<T, MT> myDao;
public BaseJpaSystemProvider() {
// nothing
}
@Required
public void setDao(IFhirSystemDao<T> theDao) {
public void setDao(IFhirSystemDao<T, MT> theDao) {
myDao = theDao;
}
@ -56,7 +56,7 @@ public class BaseJpaSystemProvider<T> extends BaseJpaProvider {
}
}
protected IFhirSystemDao<T> getDao() {
protected IFhirSystemDao<T, MT> getDao() {
return myDao;
}

View File

@ -36,6 +36,7 @@ import ca.uhn.fhir.model.dstu.resource.Conformance.RestResource;
import ca.uhn.fhir.model.dstu.resource.Conformance.RestResourceSearchParam;
import ca.uhn.fhir.model.dstu.valueset.ResourceTypeEnum;
import ca.uhn.fhir.model.dstu.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.rest.server.RestfulServer;
@ -48,7 +49,7 @@ public class JpaConformanceProviderDstu1 extends ServerConformanceProvider {
private volatile Conformance myCachedValue;
private String myImplementationDescription;
private RestfulServer myRestfulServer;
private IFhirSystemDao<List<IResource>> mySystemDao;
private IFhirSystemDao<List<IResource>, ca.uhn.fhir.model.dstu2.composite.MetaDt> mySystemDao;
/**
* Constructor
@ -62,7 +63,7 @@ public class JpaConformanceProviderDstu1 extends ServerConformanceProvider {
/**
* Constructor
*/
public JpaConformanceProviderDstu1(RestfulServer theRestfulServer, IFhirSystemDao<List<IResource>> theSystemDao) {
public JpaConformanceProviderDstu1(RestfulServer theRestfulServer, IFhirSystemDao<List<IResource>, ca.uhn.fhir.model.dstu2.composite.MetaDt> theSystemDao) {
super(theRestfulServer);
myRestfulServer = theRestfulServer;
mySystemDao = theSystemDao;
@ -120,7 +121,7 @@ public class JpaConformanceProviderDstu1 extends ServerConformanceProvider {
}
@CoverageIgnore
public void setSystemDao(IFhirSystemDao<List<IResource>> mySystemDao) {
public void setSystemDao(IFhirSystemDao<List<IResource>, MetaDt> mySystemDao) {
this.mySystemDao = mySystemDao;
}

View File

@ -30,6 +30,7 @@ import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.Conformance.Rest;
@ -51,7 +52,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
private DaoConfig myDaoConfig;
private String myImplementationDescription;
private RestfulServer myRestfulServer;
private IFhirSystemDao<Bundle> mySystemDao;
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
/**
* Constructor
@ -65,7 +66,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
/**
* Constructor
*/
public JpaConformanceProviderDstu2(RestfulServer theRestfulServer, IFhirSystemDao<Bundle> theSystemDao, DaoConfig theDaoConfig) {
public JpaConformanceProviderDstu2(RestfulServer theRestfulServer, IFhirSystemDao<Bundle, MetaDt> theSystemDao, DaoConfig theDaoConfig) {
super(theRestfulServer);
myRestfulServer = theRestfulServer;
mySystemDao = theSystemDao;
@ -134,7 +135,7 @@ public class JpaConformanceProviderDstu2 extends ServerConformanceProvider {
}
@CoverageIgnore
public void setSystemDao(IFhirSystemDao<Bundle> mySystemDao) {
public void setSystemDao(IFhirSystemDao<Bundle, MetaDt> mySystemDao) {
this.mySystemDao = mySystemDao;
}
}

View File

@ -0,0 +1,141 @@
package ca.uhn.fhir.jpa.provider;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.model.dstu21.composite.MetaDt;
import ca.uhn.fhir.model.dstu21.resource.Bundle;
import ca.uhn.fhir.model.dstu21.resource.Conformance;
import ca.uhn.fhir.model.dstu21.resource.Conformance.Rest;
import ca.uhn.fhir.model.dstu21.resource.Conformance.RestResource;
import ca.uhn.fhir.model.dstu21.resource.Conformance.RestResourceSearchParam;
import ca.uhn.fhir.model.dstu21.valueset.ConditionalDeleteStatusEnum;
import ca.uhn.fhir.model.dstu21.valueset.ResourceTypeEnum;
import ca.uhn.fhir.model.dstu21.valueset.SearchParamTypeEnum;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.provider.dstu21.ServerConformanceProvider;
import ca.uhn.fhir.util.ExtensionConstants;
import net.sourceforge.cobertura.CoverageIgnore;
public class JpaConformanceProviderDstu21 extends ServerConformanceProvider {
private volatile Conformance myCachedValue;
private DaoConfig myDaoConfig;
private String myImplementationDescription;
private RestfulServer myRestfulServer;
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
/**
* Constructor
*/
@CoverageIgnore
public JpaConformanceProviderDstu21(){
super();
super.setCache(false);
}
/**
* Constructor
*/
public JpaConformanceProviderDstu21(RestfulServer theRestfulServer, IFhirSystemDao<Bundle, MetaDt> theSystemDao, DaoConfig theDaoConfig) {
super(theRestfulServer);
myRestfulServer = theRestfulServer;
mySystemDao = theSystemDao;
myDaoConfig = theDaoConfig;
super.setCache(false);
}
@Override
public Conformance getServerConformance(HttpServletRequest theRequest) {
Conformance retVal = myCachedValue;
Map<String, Long> counts = mySystemDao.getResourceCounts();
FhirContext ctx = myRestfulServer.getFhirContext();
retVal = super.getServerConformance(theRequest);
for (Rest nextRest : retVal.getRest()) {
for (RestResource nextResource : nextRest.getResource()) {
ConditionalDeleteStatusEnum conditionalDelete = nextResource.getConditionalDeleteElement().getValueAsEnum();
if (conditionalDelete == ConditionalDeleteStatusEnum.MULTIPLE_DELETES_SUPPORTED && myDaoConfig.isAllowMultipleDelete() == false) {
nextResource.setConditionalDelete(ConditionalDeleteStatusEnum.SINGLE_DELETES_SUPPORTED);
}
// Add resource counts
Long count = counts.get(nextResource.getTypeElement().getValueAsString());
if (count != null) {
nextResource.addUndeclaredExtension(false, ExtensionConstants.CONF_RESOURCE_COUNT, new DecimalDt(count));
}
// Add chained params
for (RestResourceSearchParam nextParam : nextResource.getSearchParam()) {
if (nextParam.getTypeElement().getValueAsEnum() == SearchParamTypeEnum.REFERENCE) {
List<BoundCodeDt<ResourceTypeEnum>> targets = nextParam.getTarget();
for (BoundCodeDt<ResourceTypeEnum> next : targets) {
RuntimeResourceDefinition def = ctx.getResourceDefinition(next.getValue());
for (RuntimeSearchParam nextChainedParam : def.getSearchParams()) {
nextParam.addChain(nextChainedParam.getName());
}
}
}
}
}
}
retVal.getImplementation().setDescription(myImplementationDescription);
myCachedValue = retVal;
return retVal;
}
public void setDaoConfig(DaoConfig myDaoConfig) {
this.myDaoConfig = myDaoConfig;
}
@CoverageIgnore
public void setImplementationDescription(String theImplDesc) {
myImplementationDescription = theImplDesc;
}
@Override
public void setRestfulServer(RestfulServer theRestfulServer) {
this.myRestfulServer = theRestfulServer;
super.setRestfulServer(theRestfulServer);
}
@CoverageIgnore
public void setSystemDao(IFhirSystemDao<Bundle, MetaDt> mySystemDao) {
this.mySystemDao = mySystemDao;
}
}

View File

@ -90,7 +90,7 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
//@formatter:on
public Parameters meta() {
Parameters parameters = new Parameters();
MetaDt metaGetOperation = getDao().metaGetOperation();
MetaDt metaGetOperation = getDao().metaGetOperation(MetaDt.class);
parameters.addParameter().setName("return").setValue(metaGetOperation);
return parameters;
}
@ -102,7 +102,7 @@ public class JpaResourceProviderDstu2<T extends IResource> extends BaseJpaResour
//@formatter:on
public Parameters meta(@IdParam IdDt theId) {
Parameters parameters = new Parameters();
MetaDt metaGetOperation = getDao().metaGetOperation(theId);
MetaDt metaGetOperation = getDao().metaGetOperation(MetaDt.class, theId);
parameters.addParameter().setName("return").setValue(metaGetOperation);
return parameters;
}

View File

@ -0,0 +1,166 @@
package ca.uhn.fhir.jpa.provider;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.annotation.ConditionalUrlParam;
import ca.uhn.fhir.rest.annotation.Create;
import ca.uhn.fhir.rest.annotation.Delete;
import ca.uhn.fhir.rest.annotation.IdParam;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.ResourceParam;
import ca.uhn.fhir.rest.annotation.Update;
import ca.uhn.fhir.rest.annotation.Validate;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class JpaResourceProviderDstu21<T extends IResource> extends BaseJpaResourceProvider<T> {
public static final String OPERATION_NAME_META = "$meta";
public static final String OPERATION_NAME_META_DELETE = "$meta-delete";
public static final String OPERATION_NAME_META_ADD = "$meta-add";
public JpaResourceProviderDstu21() {
// nothing
}
public JpaResourceProviderDstu21(IFhirResourceDao<T> theDao) {
super(theDao);
}
@Create
public MethodOutcome create(HttpServletRequest theRequest, @ResourceParam T theResource, @ConditionalUrlParam String theConditional) {
startRequest(theRequest);
try {
if (theConditional != null) {
return getDao().create(theResource, theConditional);
} else {
return getDao().create(theResource);
}
} finally {
endRequest(theRequest);
}
}
@Delete()
public MethodOutcome delete(HttpServletRequest theRequest, @IdParam IdDt theResource, @ConditionalUrlParam(supportsMultiple=true) String theConditional) {
startRequest(theRequest);
try {
if (theConditional != null) {
return getDao().deleteByUrl(theConditional);
} else {
return getDao().delete(theResource);
}
} finally {
endRequest(theRequest);
}
}
//@formatter:off
@Operation(name=OPERATION_NAME_META, idempotent=true, returnParameters= {
@OperationParam(name="return", type=MetaDt.class)
})
//@formatter:on
public Parameters meta() {
Parameters parameters = new Parameters();
MetaDt metaGetOperation = getDao().metaGetOperation(MetaDt.class);
parameters.addParameter().setName("return").setValue(metaGetOperation);
return parameters;
}
//@formatter:off
@Operation(name=OPERATION_NAME_META, idempotent=true, returnParameters= {
@OperationParam(name="return", type=MetaDt.class)
})
//@formatter:on
public Parameters meta(@IdParam IdDt theId) {
Parameters parameters = new Parameters();
MetaDt metaGetOperation = getDao().metaGetOperation(MetaDt.class, theId);
parameters.addParameter().setName("return").setValue(metaGetOperation);
return parameters;
}
//@formatter:off
@Operation(name=OPERATION_NAME_META_ADD, idempotent=true, returnParameters= {
@OperationParam(name="return", type=MetaDt.class)
})
//@formatter:on
public Parameters metaAdd(@IdParam IdDt theId, @OperationParam(name = "meta") MetaDt theMeta) {
if (theMeta == null) {
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
}
Parameters parameters = new Parameters();
MetaDt metaAddOperation = getDao().metaAddOperation(theId, theMeta);
parameters.addParameter().setName("return").setValue(metaAddOperation);
return parameters;
}
//@formatter:off
@Operation(name=OPERATION_NAME_META_DELETE, idempotent=true, returnParameters= {
@OperationParam(name="return", type=MetaDt.class)
})
//@formatter:on
public Parameters metaDelete(@IdParam IdDt theId, @OperationParam(name = "meta") MetaDt theMeta) {
if (theMeta == null) {
throw new InvalidRequestException("Input contains no parameter with name 'meta'");
}
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(getDao().metaDeleteOperation(theId, theMeta));
return parameters;
}
@Update
public MethodOutcome update(HttpServletRequest theRequest, @ResourceParam T theResource, @IdParam IdDt theId, @ConditionalUrlParam String theConditional) {
startRequest(theRequest);
try {
if (theConditional != null) {
return getDao().update(theResource, theConditional);
} else {
theResource.setId(theId);
return getDao().update(theResource);
}
} finally {
endRequest(theRequest);
}
}
@Validate
public MethodOutcome validate(@ResourceParam T theResource, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
@Validate.Profile String theProfile) {
return validate(theResource, null, theRawResource, theEncoding, theMode, theProfile);
}
@Validate
public MethodOutcome validate(@ResourceParam T theResource, @IdParam IdDt theId, @ResourceParam String theRawResource, @ResourceParam EncodingEnum theEncoding, @Validate.Mode ValidationModeEnum theMode,
@Validate.Profile String theProfile) {
return getDao().validate(theResource, theId, theRawResource, theEncoding, theMode, theProfile);
}
}

View File

@ -23,12 +23,13 @@ package ca.uhn.fhir.jpa.provider;
import java.util.List;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class JpaSystemProviderDstu1 extends BaseJpaSystemProvider<List<IResource>> {
public class JpaSystemProviderDstu1 extends BaseJpaSystemProvider<List<IResource>, MetaDt> {
@Transaction
public List<IResource> transaction(RequestDetails theRequestDetails, @TransactionParam List<IResource> theResources) {

View File

@ -50,11 +50,11 @@ import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class JpaSystemProviderDstu2 extends BaseJpaSystemProvider<Bundle> {
public class JpaSystemProviderDstu2 extends BaseJpaSystemProvider<Bundle, MetaDt> {
@Autowired()
@Qualifier("mySystemDaoDstu2")
private IFhirSystemDao<Bundle> mySystemDao;
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
@Autowired
private ISearchDao mySearchDao;

View File

@ -0,0 +1,237 @@
package ca.uhn.fhir.jpa.provider;
import static org.apache.commons.lang3.StringUtils.isBlank;
import java.util.List;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.Map;
import java.util.Map.Entry;
import java.util.TreeMap;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.ISearchDao;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.dstu21.composite.MetaDt;
import ca.uhn.fhir.model.dstu21.resource.Bundle;
import ca.uhn.fhir.model.dstu21.resource.Parameters;
import ca.uhn.fhir.model.dstu21.resource.Parameters.Parameter;
import ca.uhn.fhir.model.primitive.DecimalDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.annotation.Operation;
import ca.uhn.fhir.rest.annotation.OperationParam;
import ca.uhn.fhir.rest.annotation.Transaction;
import ca.uhn.fhir.rest.annotation.TransactionParam;
import ca.uhn.fhir.rest.method.RequestDetails;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public class JpaSystemProviderDstu21 extends BaseJpaSystemProvider<Bundle, MetaDt> {
@Autowired()
@Qualifier("mySystemDaoDstu21")
private IFhirSystemDao<Bundle, MetaDt> mySystemDao;
@Autowired
private ISearchDao mySearchDao;
//@formatter:off
// This is generated by hand:
// ls hapi-fhir-structures-dstu2/target/generated-sources/tinder/ca/uhn/fhir/model/dstu2/resource/ | sort | sed "s/.java//" | sed "s/^/@OperationParam(name=\"/" | sed "s/$/\", type=IntegerDt.class, min=0, max=1),/"
@Operation(name="$get-resource-counts", idempotent=true, returnParameters= {
@OperationParam(name="AllergyIntolerance", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Appointment", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="AppointmentResponse", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="AuditEvent", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Basic", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Binary", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="BodySite", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Bundle", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="CarePlan", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="CarePlan2", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Claim", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ClaimResponse", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ClinicalImpression", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Communication", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="CommunicationRequest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Composition", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ConceptMap", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Condition", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Conformance", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Contract", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Contraindication", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Coverage", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DataElement", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Device", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DeviceComponent", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DeviceMetric", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DeviceUseRequest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DeviceUseStatement", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DiagnosticOrder", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DiagnosticReport", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DocumentManifest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="DocumentReference", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="EligibilityRequest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="EligibilityResponse", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Encounter", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="EnrollmentRequest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="EnrollmentResponse", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="EpisodeOfCare", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ExplanationOfBenefit", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="FamilyMemberHistory", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Flag", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Goal", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Group", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="HealthcareService", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ImagingObjectSelection", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ImagingStudy", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Immunization", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ImmunizationRecommendation", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ListResource", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Location", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Media", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Medication", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="MedicationAdministration", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="MedicationDispense", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="MedicationPrescription", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="MedicationStatement", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="MessageHeader", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="NamingSystem", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="NutritionOrder", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Observation", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="OperationDefinition", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="OperationOutcome", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Order", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="OrderResponse", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Organization", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Parameters", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Patient", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="PaymentNotice", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="PaymentReconciliation", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Person", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Practitioner", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Procedure", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ProcedureRequest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ProcessRequest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ProcessResponse", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Provenance", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Questionnaire", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="QuestionnaireAnswers", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ReferralRequest", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="RelatedPerson", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="RiskAssessment", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Schedule", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="SearchParameter", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Slot", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Specimen", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="StructureDefinition", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Subscription", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Substance", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="Supply", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="ValueSet", type=IntegerDt.class, min=0, max=1),
@OperationParam(name="VisionPrescription", type=IntegerDt.class, min=0, max=1)
})
@Description(shortDefinition="Provides the number of resources currently stored on the server, broken down by resource type")
//@formatter:on
public Parameters getResourceCounts() {
Parameters retVal = new Parameters();
Map<String, Long> counts = mySystemDao.getResourceCounts();
counts = new TreeMap<String, Long>(counts);
for (Entry<String, Long> nextEntry : counts.entrySet()) {
retVal.addParameter().setName(new StringDt(nextEntry.getKey())).setValue(new IntegerDt(nextEntry.getValue().intValue()));
}
return retVal;
}
//@formatter:off
@Operation(name="$mark-all-resources-for-reindexing", idempotent=true, returnParameters= {
@OperationParam(name="count", type=IntegerDt.class)
})
//@formatter:on
public Parameters markAllResourcesForReindexing() {
int count = mySystemDao.markAllResourcesForReindexing();
Parameters retVal = new Parameters();
retVal.addParameter().setName("count").setValue(new IntegerDt(count));
return retVal;
}
//@formatter:off
@Operation(name="$meta", idempotent=true, returnParameters= {
@OperationParam(name="return", type=MetaDt.class)
})
//@formatter:on
public Parameters meta() {
Parameters parameters = new Parameters();
parameters.addParameter().setName("return").setValue(getDao().metaGetOperation());
return parameters;
}
@Operation(name="$suggest-keywords", idempotent=true)
public Parameters suggestKeywords(
@OperationParam(name="context", min=1, max=1) String theContext,
@OperationParam(name="searchParam", min=1, max=1) String theSearchParam,
@OperationParam(name="text", min=1, max=1) String theText
) {
if (isBlank(theContext)) {
throw new InvalidRequestException("Parameter 'context' must be provided");
}
if (isBlank(theSearchParam)) {
throw new InvalidRequestException("Parameter 'searchParam' must be provided");
}
if (isBlank(theText)) {
throw new InvalidRequestException("Parameter 'text' must be provided");
}
List<Suggestion> keywords = mySearchDao.suggestKeywords(theContext, theSearchParam, theText);
Parameters retVal = new Parameters();
for (Suggestion next : keywords) {
//@formatter:off
retVal.addParameter()
.addPart(new Parameter().setName("keyword").setValue(new StringDt(next.getTerm())))
.addPart(new Parameter().setName("score").setValue(new DecimalDt(next.getScore())));
//@formatter:on
}
return retVal;
}
@Transaction
public Bundle transaction(RequestDetails theRequestDetails, @TransactionParam Bundle theResources) {
startRequest(((ServletRequestDetails) theRequestDetails).getServletRequest());
try {
return getDao().transaction(theRequestDetails, theResources);
} finally {
endRequest(((ServletRequestDetails) theRequestDetails).getServletRequest());
}
}
}

View File

@ -44,7 +44,7 @@ import net.sourceforge.cobertura.CoverageIgnore;
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
* {@link SubscriptionStatusEnum#REQUESTED} state and prevents clients from changing the status.
*/
public class SubscriptionsRequireManualActivationInterceptor extends InterceptorAdapter {
public class SubscriptionsRequireManualActivationInterceptorDstu2 extends InterceptorAdapter {
public static final ResourceMetadataKeyEnum<Object> ALLOW_STATUS_CHANGE = new ResourceMetadataKeyEnum<Object>(FhirResourceDaoSubscriptionDstu2.class.getName() + "_ALLOW_STATUS_CHANGE") {
private static final long serialVersionUID = 1;

View File

@ -0,0 +1,144 @@
package ca.uhn.fhir.jpa.util;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
/*
* #%L
* HAPI FHIR JPA Server
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import org.hl7.fhir.instance.model.api.IIdType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import ca.uhn.fhir.jpa.dao.FhirResourceDaoSubscriptionDstu2;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu21.resource.Subscription;
import ca.uhn.fhir.model.dstu21.valueset.SubscriptionChannelTypeEnum;
import ca.uhn.fhir.model.dstu21.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.InterceptorAdapter;
import net.sourceforge.cobertura.CoverageIgnore;
/**
* Interceptor which requires newly created {@link Subscription subscriptions} to be in
* {@link SubscriptionStatusEnum#REQUESTED} state and prevents clients from changing the status.
*/
public class SubscriptionsRequireManualActivationInterceptorDstu21 extends InterceptorAdapter {
public static final ResourceMetadataKeyEnum<Object> ALLOW_STATUS_CHANGE = new ResourceMetadataKeyEnum<Object>(FhirResourceDaoSubscriptionDstu2.class.getName() + "_ALLOW_STATUS_CHANGE") {
private static final long serialVersionUID = 1;
@CoverageIgnore
@Override
public Object get(IResource theResource) {
throw new UnsupportedOperationException();
}
@CoverageIgnore
@Override
public void put(IResource theResource, Object theObject) {
throw new UnsupportedOperationException();
}
};
@Autowired
@Qualifier("mySubscriptionDaoDstu21")
private IFhirResourceDao<Subscription> myDao;
@Override
public void incomingRequestPreHandled(RestOperationTypeEnum theOperation, ActionRequestDetails theProcessedRequest) {
switch (theOperation) {
case CREATE:
case UPDATE:
if (theProcessedRequest.getResourceType().equals("Subscription")) {
verifyStatusOk(theOperation, theProcessedRequest);
}
break;
default:
break;
}
}
public void setDao(IFhirResourceDao<Subscription> theDao) {
myDao = theDao;
}
private void verifyStatusOk(RestOperationTypeEnum theOperation, ActionRequestDetails theRequestDetails) {
Subscription subscription = (Subscription) theRequestDetails.getResource();
SubscriptionStatusEnum newStatus = subscription.getStatusElement().getValueAsEnum();
if (newStatus == SubscriptionStatusEnum.REQUESTED || newStatus == SubscriptionStatusEnum.OFF) {
return;
}
if (newStatus == null) {
String actualCode = subscription.getStatusElement().getValueAsString();
throw new UnprocessableEntityException("Can not " + theOperation.getCode() + " resource: Subscription.status must be populated" + ((isNotBlank(actualCode)) ? " (invalid value " + actualCode + ")" : ""));
}
IIdType requestId = theRequestDetails.getId();
if (requestId != null && requestId.hasIdPart()) {
Subscription existing;
try {
existing = myDao.read(requestId);
SubscriptionStatusEnum existingStatus = existing.getStatusElement().getValueAsEnum();
if (existingStatus != newStatus) {
verifyActiveStatus(subscription, newStatus, existingStatus);
}
} catch (ResourceNotFoundException e) {
verifyActiveStatus(subscription, newStatus, null);
}
} else {
verifyActiveStatus(subscription, newStatus, null);
}
}
private void verifyActiveStatus(Subscription theSubscription, SubscriptionStatusEnum newStatus, SubscriptionStatusEnum theExistingStatus) {
SubscriptionChannelTypeEnum channelType = theSubscription.getChannel().getTypeElement().getValueAsEnum();
if (channelType == null) {
throw new UnprocessableEntityException("Subscription.channel.type must be populated");
}
if (channelType == SubscriptionChannelTypeEnum.WEBSOCKET) {
return;
}
if (theExistingStatus != null) {
throw new UnprocessableEntityException("Subscription.status can not be changed from " + describeStatus(theExistingStatus) + " to " + describeStatus(newStatus));
}
throw new UnprocessableEntityException("Subscription.status must be '" + SubscriptionStatusEnum.OFF.getCode() + "' or '" + SubscriptionStatusEnum.REQUESTED.getCode() + "' on a newly created subscription");
}
private String describeStatus(SubscriptionStatusEnum existingStatus) {
String existingStatusString;
if (existingStatus != null) {
existingStatusString = '\'' + existingStatus.getCode() + '\'';
} else {
existingStatusString = "null";
}
return existingStatusString;
}
}

View File

@ -0,0 +1,68 @@
package ca.uhn.fhir.jpa.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.dao.DaoConfig;
@Configuration
@EnableTransactionManagement()
public class TestDstu21Config extends BaseJavaConfigDstu21 {
@Bean()
public DaoConfig daoConfig() {
return new DaoConfig();
}
@Bean()
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.EmbeddedDriver());
retVal.setUrl("jdbc:derby:memory:myUnitTestDB;create=true");
retVal.setUsername("");
retVal.setPassword("");
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu2");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
retVal.afterPropertiesSet();
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
extraProperties.put("hibernate.search.default.directory_provider" ,"filesystem");
extraProperties.put("hibernate.search.default.indexBase", "target/lucene_index_dstu21");
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");
return extraProperties;
}
}

View File

@ -61,6 +61,9 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.dialect", "org.hibernate.dialect.DerbyTenSevenDialect");
extraProperties.put("hibernate.search.default.directory_provider" ,"filesystem");
extraProperties.put("hibernate.search.default.indexBase", "target/lucene_index_dstu2");
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");
return extraProperties;
}

View File

@ -44,6 +44,9 @@ import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.model.dstu2.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.model.dstu2.resource.ConceptMap;
import ca.uhn.fhir.model.dstu2.resource.Device;
@ -152,7 +155,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
protected IFhirResourceDao<Substance> mySubstanceDao;
@Autowired
@Qualifier("mySystemDaoDstu2")
protected IFhirSystemDao<Bundle> mySystemDao;
protected IFhirSystemDao<Bundle, MetaDt> mySystemDao;
@Autowired
@Qualifier("mySystemProviderDstu2")
protected JpaSystemProviderDstu2 mySystemProvider;
@ -160,7 +163,7 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
protected PlatformTransactionManager myTxManager;
@Autowired
@Qualifier("myValueSetDaoDstu2")
protected IFhirResourceDaoValueSet<ValueSet> myValueSetDao;
protected IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> myValueSetDao;
@Before
public void beforeCreateInterceptor() {
@ -168,6 +171,13 @@ public abstract class BaseJpaDstu2Test extends BaseJpaTest {
myDaoConfig.setInterceptors(myInterceptor);
}
@Before
public void beforeResetConfig() {
myDaoConfig.setHardSearchLimit(1000);
myDaoConfig.setHardTagListLimit(1000);
myDaoConfig.setIncludeLimit(2000);
}
@Before
@Transactional
public void beforeFlushFT() {

View File

@ -128,13 +128,13 @@ public class FhirResourceDaoDstu2SubscriptionTest extends BaseJpaDstu2Test {
assertNotNull(table);
assertNotNull(table.getNextCheck());
assertEquals(table.getNextCheck(), table.getSubscriptionResource().getPublished().getValue());
assertEquals(SubscriptionStatusEnum.REQUESTED, myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED.getCode(), myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
mySubscriptionDao.update(subs);
assertEquals(SubscriptionStatusEnum.ACTIVE, myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.ACTIVE.getCode(), myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.ACTIVE, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
mySubscriptionDao.delete(id);
@ -152,7 +152,7 @@ public class FhirResourceDaoDstu2SubscriptionTest extends BaseJpaDstu2Test {
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
mySubscriptionDao.update(subs);
assertEquals(SubscriptionStatusEnum.REQUESTED, myEntityManager.createQuery("SELECT t FROM SubscriptionTable t WHERE t.myResId = " + id.getIdPart(), SubscriptionTable.class).getSingleResult().getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED.getCode(), myEntityManager.createQuery("SELECT t FROM SubscriptionTable t WHERE t.myResId = " + id.getIdPart(), SubscriptionTable.class).getSingleResult().getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
}

View File

@ -1094,6 +1094,14 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
public void testHistoryOverMultiplePages() throws Exception {
String methodName = "testHistoryOverMultiplePages";
/*
for (int i = 0; i < 1000; i++) {
Patient patient = new Patient();
patient.addName().addFamily(methodName + "__" + i);
myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
*/
Patient patient = new Patient();
patient.addName().addFamily(methodName);
IIdType id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
@ -1181,30 +1189,32 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
// By instance
history = myPatientDao.history(id, null);
assertEquals(fullSize + 1, history.size());
for (int i = 0; i < fullSize; i++) {
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
assertEquals(log(history), fullSize + 1, history.size());
// By type
history = myPatientDao.history(null);
assertEquals(fullSize + 1, history.size());
for (int i = 0; i < fullSize; i++) {
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
ourLog.info(log(history));
ourLog.info("Want {} but got {}", fullSize + 1, history.size());
assertEquals(log(history), fullSize + 1, history.size()); // fails?
// By server
history = mySystemDao.history(null);
assertEquals(fullSize + 1, history.size());
for (int i = 0; i < fullSize; i++) {
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
assertEquals(log(history), fullSize + 1, history.size());
/*
* With since date
@ -1212,33 +1222,41 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
// By instance
history = myPatientDao.history(id, middleDate);
assertEquals(halfSize, history.size());
for (int i = 0; i < halfSize; i++) {
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
assertEquals(halfSize, history.size());
// By type
history = myPatientDao.history(middleDate);
assertEquals(halfSize, history.size());
for (int i = 0; i < halfSize; i++) {
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
assertEquals(halfSize, history.size());
// By server
history = mySystemDao.history(middleDate);
assertEquals(halfSize, history.size());
for (int i = 0; i < halfSize; i++) {
String expected = id.withVersion(Integer.toString(fullSize + 1 - i)).getValue();
String actual = history.getResources(i, i + 1).get(0).getIdElement().getValue();
assertEquals(expected, actual);
}
assertEquals(halfSize, history.size());
}
private String log(IBundleProvider theHistory) {
StringBuilder b =new StringBuilder(theHistory.size() + " results: ");
for (IBaseResource next : theHistory.getResources(0, theHistory.size())) {
b.append("\n ").append(next.getIdElement().toUnqualified().getValue());
}
return b.toString();
}
@Test
public void testHistoryWithDeletedResource() throws Exception {
String methodName = "testHistoryWithDeletedResource";
@ -1399,7 +1417,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
* Meta Read on Version
*/
meta = myPatientDao.metaGetOperation(id.withVersion("1"));
meta = myPatientDao.metaGetOperation(MetaDt.class, id.withVersion("1"));
assertEquals(1, meta.getProfile().size());
assertEquals(1, meta.getSecurity().size());
assertEquals(1, meta.getTag().size());
@ -1410,7 +1428,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
/*
* Meta-read on Version 2
*/
meta = myPatientDao.metaGetOperation(id.withVersion("2"));
meta = myPatientDao.metaGetOperation(MetaDt.class, id.withVersion("2"));
assertEquals(2, meta.getProfile().size());
assertEquals(2, meta.getSecurity().size());
assertEquals(2, meta.getTag().size());
@ -1418,7 +1436,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
/*
* Meta-read on latest version
*/
meta = myPatientDao.metaGetOperation(id.toVersionless());
meta = myPatientDao.metaGetOperation(MetaDt.class, id.toVersionless());
assertEquals(2, meta.getProfile().size());
assertEquals(2, meta.getSecurity().size());
assertEquals(2, meta.getTag().size());
@ -1441,7 +1459,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
* Meta Read on Version
*/
meta = myPatientDao.metaGetOperation(id.withVersion("1"));
meta = myPatientDao.metaGetOperation(MetaDt.class, id.withVersion("1"));
assertEquals(2, meta.getProfile().size());
assertEquals(2, meta.getSecurity().size());
assertEquals(2, meta.getTag().size());
@ -1933,7 +1951,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
MetaDt meta;
meta = myPatientDao.metaGetOperation();
meta = myPatientDao.metaGetOperation(MetaDt.class);
List<CodingDt> published = meta.getTag();
assertEquals(2, published.size());
assertEquals(null, published.get(0).getSystem());
@ -1955,7 +1973,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("http://profile/1", profiles.get(0).getValue());
assertEquals("http://profile/2", profiles.get(1).getValue());
meta = myPatientDao.metaGetOperation(id2);
meta = myPatientDao.metaGetOperation(MetaDt.class, id2);
published = meta.getTag();
assertEquals(1, published.size());
assertEquals("http://foo", published.get(0).getSystem());
@ -1978,7 +1996,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
myPatientDao.metaDeleteOperation(id1, metaDel);
}
meta = myPatientDao.metaGetOperation();
meta = myPatientDao.metaGetOperation(MetaDt.class);
published = meta.getTag();
assertEquals(1, published.size());
assertEquals("http://foo", published.get(0).getSystem());
@ -2056,7 +2074,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
MetaDt meta;
meta = myPatientDao.metaGetOperation();
meta = myPatientDao.metaGetOperation(MetaDt.class);
List<CodingDt> published = meta.getTag();
assertEquals(2, published.size());
assertEquals(null, published.get(0).getSystem());
@ -2078,7 +2096,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
assertEquals("http://profile/1", profiles.get(0).getValue());
assertEquals("http://profile/2", profiles.get(1).getValue());
meta = myPatientDao.metaGetOperation(id2);
meta = myPatientDao.metaGetOperation(MetaDt.class, id2);
published = meta.getTag();
assertEquals(1, published.size());
assertEquals("http://foo", published.get(0).getSystem());
@ -2097,7 +2115,7 @@ public class FhirResourceDaoDstu2Test extends BaseJpaDstu2Test {
myPatientDao.removeTag(id1, TagTypeEnum.SECURITY_LABEL, "seclabel:sys:1", "seclabel:code:1");
myPatientDao.removeTag(id1, TagTypeEnum.PROFILE, BaseHapiFhirDao.NS_JPA_PROFILE, "http://profile/1");
meta = myPatientDao.metaGetOperation();
meta = myPatientDao.metaGetOperation(MetaDt.class);
published = meta.getTag();
assertEquals(1, published.size());
assertEquals("http://foo", published.get(0).getSystem());

View File

@ -40,6 +40,7 @@ import ca.uhn.fhir.model.dstu.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu.resource.Location;
import ca.uhn.fhir.model.dstu.resource.Observation;
import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.rest.method.RequestDetails;
@ -55,7 +56,7 @@ public class FhirSystemDaoDstu1Test extends BaseJpaTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirSystemDaoDstu1Test.class);
private static IFhirResourceDao<Observation> ourObservationDao;
private static IFhirResourceDao<Patient> ourPatientDao;
private static IFhirSystemDao<List<IResource>> ourSystemDao;
private static IFhirSystemDao<List<IResource>, MetaDt> ourSystemDao;
private RequestDetails myRequestDetails;
@Test

View File

@ -0,0 +1,44 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.Enumeration;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.junit.Before;
import ca.uhn.fhir.jpa.rp.dstu21.PatientResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
public abstract class BaseJpaDstu21SystemTest extends BaseJpaDstu21Test {
protected ServletRequestDetails myRequestDetails;
private RestfulServer myServer;
@SuppressWarnings("unchecked")
@Before
public void before() throws ServletException {
myRequestDetails = mock(ServletRequestDetails.class);
if (myServer == null) {
myServer = new RestfulServer(myFhirCtx);
PatientResourceProvider patientRp = new PatientResourceProvider();
patientRp.setDao(myPatientDao);
myServer.setResourceProviders(patientRp);
myServer.init(mock(ServletConfig.class));
}
when(myRequestDetails.getServer()).thenReturn(myServer);
HttpServletRequest servletRequest = mock(HttpServletRequest.class);
when(myRequestDetails.getServletRequest()).thenReturn(servletRequest);
when(myRequestDetails.getFhirServerBase()).thenReturn("http://example.com/base");
when(servletRequest.getHeaderNames()).thenReturn(mock(Enumeration.class));
when(servletRequest.getRequestURL()).thenReturn(new StringBuffer("/Patient"));
}
}

View File

@ -0,0 +1,266 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.junit.Assert.fail;
import static org.mockito.Mockito.mock;
import java.io.IOException;
import java.io.InputStream;
import javax.persistence.EntityManager;
import org.apache.commons.io.IOUtils;
import org.hibernate.search.jpa.FullTextEntityManager;
import org.hibernate.search.jpa.Search;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.junit.Before;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.PlatformTransactionManager;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.TestDstu21Config;
import ca.uhn.fhir.jpa.dao.BaseJpaTest;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.FhirResourceDaoDstu2SearchNoFtTest;
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoPatient;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoSubscription;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.dao.ISearchDao;
import ca.uhn.fhir.jpa.entity.ForcedId;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTable;
import ca.uhn.fhir.jpa.entity.ResourceHistoryTag;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamCoords;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamDate;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamNumber;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamQuantity;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamString;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamToken;
import ca.uhn.fhir.jpa.entity.ResourceIndexedSearchParamUri;
import ca.uhn.fhir.jpa.entity.ResourceLink;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.entity.ResourceTag;
import ca.uhn.fhir.jpa.entity.SubscriptionFlaggedResource;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.jpa.entity.TagDefinition;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21;
import ca.uhn.fhir.model.dstu21.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
import ca.uhn.fhir.model.dstu21.composite.MetaDt;
import ca.uhn.fhir.model.dstu21.resource.Bundle;
import ca.uhn.fhir.model.dstu21.resource.ConceptMap;
import ca.uhn.fhir.model.dstu21.resource.Device;
import ca.uhn.fhir.model.dstu21.resource.DiagnosticOrder;
import ca.uhn.fhir.model.dstu21.resource.DiagnosticReport;
import ca.uhn.fhir.model.dstu21.resource.Encounter;
import ca.uhn.fhir.model.dstu21.resource.Immunization;
import ca.uhn.fhir.model.dstu21.resource.Location;
import ca.uhn.fhir.model.dstu21.resource.Media;
import ca.uhn.fhir.model.dstu21.resource.Medication;
import ca.uhn.fhir.model.dstu21.resource.MedicationOrder;
import ca.uhn.fhir.model.dstu21.resource.Observation;
import ca.uhn.fhir.model.dstu21.resource.Organization;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.dstu21.resource.Practitioner;
import ca.uhn.fhir.model.dstu21.resource.Questionnaire;
import ca.uhn.fhir.model.dstu21.resource.QuestionnaireResponse;
import ca.uhn.fhir.model.dstu21.resource.StructureDefinition;
import ca.uhn.fhir.model.dstu21.resource.Subscription;
import ca.uhn.fhir.model.dstu21.resource.Substance;
import ca.uhn.fhir.model.dstu21.resource.ValueSet;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.rest.method.MethodUtil;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
//@formatter:off
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes= {TestDstu21Config.class, ca.uhn.fhir.jpa.config.WebsocketDstu2Config.class})
//@formatter:on
public abstract class BaseJpaDstu21Test extends BaseJpaTest {
@Autowired
protected ApplicationContext myAppCtx;
@Autowired
protected ISearchDao mySearchDao;
@Autowired
@Qualifier("myConceptMapDaoDstu21")
protected IFhirResourceDao<ConceptMap> myConceptMapDao;
@Autowired
@Qualifier("myMedicationDaoDstu21")
protected IFhirResourceDao<Medication> myMedicationDao;
@Autowired
@Qualifier("myMedicationOrderDaoDstu21")
protected IFhirResourceDao<MedicationOrder> myMedicationOrderDao;
@Autowired
protected DaoConfig myDaoConfig;
@Autowired
@Qualifier("myDeviceDaoDstu21")
protected IFhirResourceDao<Device> myDeviceDao;
@Autowired
@Qualifier("myDiagnosticOrderDaoDstu21")
protected IFhirResourceDao<DiagnosticOrder> myDiagnosticOrderDao;
@Autowired
@Qualifier("myDiagnosticReportDaoDstu21")
protected IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
@Autowired
@Qualifier("myEncounterDaoDstu21")
protected IFhirResourceDao<Encounter> myEncounterDao;
// @PersistenceContext()
@Autowired
protected EntityManager myEntityManager;
@Autowired
@Qualifier("myFhirContextDstu21")
protected FhirContext myFhirCtx;
@Autowired
@Qualifier("myImmunizationDaoDstu21")
protected IFhirResourceDao<Immunization> myImmunizationDao;
protected IServerInterceptor myInterceptor;
@Autowired
@Qualifier("myLocationDaoDstu21")
protected IFhirResourceDao<Location> myLocationDao;
@Autowired
@Qualifier("myObservationDaoDstu21")
protected IFhirResourceDao<Observation> myObservationDao;
@Autowired
@Qualifier("myOrganizationDaoDstu21")
protected IFhirResourceDao<Organization> myOrganizationDao;
@Autowired
@Qualifier("myPatientDaoDstu21")
protected IFhirResourceDaoPatient<Patient> myPatientDao;
@Autowired
@Qualifier("myMediaDaoDstu21")
protected IFhirResourceDao<Media> myMediaDao;
@Autowired
@Qualifier("myPractitionerDaoDstu21")
protected IFhirResourceDao<Practitioner> myPractitionerDao;
@Autowired
@Qualifier("myQuestionnaireDaoDstu21")
protected IFhirResourceDao<Questionnaire> myQuestionnaireDao;
@Autowired
@Qualifier("myQuestionnaireResponseDaoDstu21")
protected IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
@Autowired
@Qualifier("myResourceProvidersDstu21")
protected Object myResourceProviders;
@Autowired
@Qualifier("myStructureDefinitionDaoDstu21")
protected IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
@Autowired
@Qualifier("mySubscriptionDaoDstu21")
protected IFhirResourceDaoSubscription<Subscription> mySubscriptionDao;
@Autowired
@Qualifier("mySubstanceDaoDstu21")
protected IFhirResourceDao<Substance> mySubstanceDao;
@Autowired
@Qualifier("mySystemDaoDstu21")
protected IFhirSystemDao<Bundle, MetaDt> mySystemDao;
@Autowired
@Qualifier("mySystemProviderDstu21")
protected JpaSystemProviderDstu21 mySystemProvider;
@Autowired
protected PlatformTransactionManager myTxManager;
@Autowired
@Qualifier("myValueSetDaoDstu21")
protected IFhirResourceDaoValueSet<ValueSet, CodingDt, CodeableConceptDt> myValueSetDao;
@Before
public void beforeCreateInterceptor() {
myInterceptor = mock(IServerInterceptor.class);
myDaoConfig.setInterceptors(myInterceptor);
}
@Before
@Transactional
public void beforeFlushFT() {
FullTextEntityManager ftem = Search.getFullTextEntityManager(myEntityManager);
ftem.purgeAll(ResourceTable.class);
ftem.flushToIndexes();
myDaoConfig.setSchedulingDisabled(true);
}
@Before
public void beforeResetConfig() {
myDaoConfig.setHardSearchLimit(1000);
myDaoConfig.setHardTagListLimit(1000);
myDaoConfig.setIncludeLimit(2000);
}
@Before
@Transactional()
public void beforePurgeDatabase() {
final EntityManager entityManager = this.myEntityManager;
purgeDatabase(entityManager, myTxManager);
}
protected <T extends IBaseResource> T loadResourceFromClasspath(Class<T> type, String resourceName) throws IOException {
InputStream stream = FhirResourceDaoDstu2SearchNoFtTest.class.getResourceAsStream(resourceName);
if (stream == null) {
fail("Unable to load resource: " + resourceName);
}
String string = IOUtils.toString(stream, "UTF-8");
IParser newJsonParser = MethodUtil.detectEncodingNoDefault(string).newParser(myFhirCtx);
return newJsonParser.parseResource(type, string);
}
public TransactionTemplate newTxTemplate() {
TransactionTemplate retVal = new TransactionTemplate(myTxManager);
retVal.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRES_NEW);
retVal.afterPropertiesSet();
return retVal;
}
public static void purgeDatabase(final EntityManager entityManager, PlatformTransactionManager theTxManager) {
TransactionTemplate txTemplate = new TransactionTemplate(theTxManager);
txTemplate.setPropagationBehavior(TransactionTemplate.PROPAGATION_REQUIRED);
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
entityManager.createQuery("UPDATE " + ResourceHistoryTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
entityManager.createQuery("UPDATE " + ResourceTable.class.getSimpleName() + " d SET d.myForcedId = null").executeUpdate();
return null;
}
});
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
entityManager.createQuery("DELETE from " + SubscriptionFlaggedResource.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ForcedId.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamDate.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamNumber.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamQuantity.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamString.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamToken.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamUri.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceIndexedSearchParamCoords.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceLink.class.getSimpleName() + " d").executeUpdate();
return null;
}
});
txTemplate.execute(new TransactionCallback<Void>() {
@Override
public Void doInTransaction(TransactionStatus theStatus) {
entityManager.createQuery("DELETE from " + SubscriptionTable.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceHistoryTag.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceTag.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + TagDefinition.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceHistoryTable.class.getSimpleName() + " d").executeUpdate();
entityManager.createQuery("DELETE from " + ResourceTable.class.getSimpleName() + " d").executeUpdate();
return null;
}
});
}
}

View File

@ -0,0 +1,156 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import ca.uhn.fhir.jpa.entity.ResourceTable;
import ca.uhn.fhir.jpa.interceptor.IJpaServerInterceptor;
import ca.uhn.fhir.jpa.interceptor.JpaServerInterceptorAdapter;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
public class FhirResourceDaoDstu21InterceptorTest extends BaseJpaDstu21Test {
private IJpaServerInterceptor myJpaInterceptor;
private JpaServerInterceptorAdapter myJpaInterceptorAdapter = new JpaServerInterceptorAdapter();
@After
public void after() {
myDaoConfig.getInterceptors().remove(myJpaInterceptor);
myDaoConfig.getInterceptors().remove(myJpaInterceptorAdapter);
}
@Before
public void before() {
myJpaInterceptor = mock(IJpaServerInterceptor.class);
myDaoConfig.getInterceptors().add(myJpaInterceptor);
myDaoConfig.getInterceptors().add(myJpaInterceptorAdapter);
}
/*
* *****************************************************
* Note that non JPA specific operations get tested in individual
* operation test methods too
* *****************************************************
*/
@Test
public void testJpaCreate() {
Patient p = new Patient();
p.addName().addFamily("PATIENT");
Long id = myPatientDao.create(p).getId().getIdPartAsLong();
ArgumentCaptor<ActionRequestDetails> detailsCapt;
ArgumentCaptor<ResourceTable> tableCapt;
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
assertNotNull(tableCapt.getValue().getId());
assertEquals(id, tableCapt.getValue().getId());
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
/*
* Not do a conditional create
*/
p = new Patient();
p.addName().addFamily("PATIENT1");
Long id2 = myPatientDao.create(p, "Patient?family=PATIENT").getId().getIdPartAsLong();
assertEquals(id, id2);
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
verify(myJpaInterceptor, times(0)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
}
@Test
public void testJpaDelete() {
Patient p = new Patient();
p.addName().addFamily("PATIENT");
Long id = myPatientDao.create(p).getId().getIdPartAsLong();
myPatientDao.delete(new IdDt("Patient", id));
ArgumentCaptor<ActionRequestDetails> detailsCapt;
ArgumentCaptor<ResourceTable> tableCapt;
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
verify(myJpaInterceptor, times(1)).resourceDeleted(detailsCapt.capture(), tableCapt.capture());
assertNotNull(tableCapt.getValue().getId());
assertEquals(id, tableCapt.getValue().getId());
}
@Test
public void testJpaUpdate() {
Patient p = new Patient();
p.addName().addFamily("PATIENT");
Long id = myPatientDao.create(p).getId().getIdPartAsLong();
p = new Patient();
p.setId(new IdDt(id));
p.addName().addFamily("PATIENT1");
Long id2 = myPatientDao.update(p).getId().getIdPartAsLong();
assertEquals(id, id2);
ArgumentCaptor<ActionRequestDetails> detailsCapt;
ArgumentCaptor<ResourceTable> tableCapt;
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
verify(myJpaInterceptor, times(1)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
assertNotNull(tableCapt.getValue().getId());
assertEquals(id, tableCapt.getValue().getId());
/*
* Now do a conditional update
*/
p = new Patient();
p.setId(new IdDt(id));
p.addName().addFamily("PATIENT2");
id2 = myPatientDao.update(p, "Patient?family=PATIENT1").getId().getIdPartAsLong();
assertEquals(id, id2);
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
verify(myJpaInterceptor, times(1)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
assertEquals(id, tableCapt.getAllValues().get(2).getId());
/*
* Now do a conditional update where none will match (so this is actually a create)
*/
p = new Patient();
p.addName().addFamily("PATIENT3");
id2 = myPatientDao.update(p, "Patient?family=ZZZ").getId().getIdPartAsLong();
assertNotEquals(id, id2);
detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
tableCapt = ArgumentCaptor.forClass(ResourceTable.class);
verify(myJpaInterceptor, times(2)).resourceUpdated(detailsCapt.capture(), tableCapt.capture());
verify(myJpaInterceptor, times(2)).resourceCreated(detailsCapt.capture(), tableCapt.capture());
assertEquals(id2, tableCapt.getAllValues().get(3).getId());
}
}

View File

@ -0,0 +1,467 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertThat;
import static org.mockito.Mockito.mock;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Test;
import ca.uhn.fhir.jpa.dao.FhirSearchDao.Suggestion;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.model.dstu21.resource.Device;
import ca.uhn.fhir.model.dstu21.resource.Media;
import ca.uhn.fhir.model.dstu21.resource.Observation;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.primitive.Base64BinaryDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.Constants;
public class FhirResourceDaoDstu21SearchFtTest extends BaseJpaDstu21Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu21SearchFtTest.class);
@Test
public void testSuggestIgnoresBase64Content() {
Patient patient = new Patient();
patient.addName().addFamily("testSuggest");
IIdType ptId = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
Media med = new Media();
med.getSubject().setReference(ptId);
med.getSubtype().setText("Systolic Blood Pressure");
med.getContent().setContentType("LCws");
med.getContent().setData(new Base64BinaryDt(new byte[] {44,44,44,44,44,44,44,44}));
med.getContent().setTitle("bbbb syst");
myMediaDao.create(med);
ourLog.info(myFhirCtx.newJsonParser().encodeResourceToString(med));
List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "press");
ourLog.info("Found: " + output);
assertEquals(2, output.size());
assertEquals("Pressure", output.get(0).getTerm());
assertEquals("Systolic Blood Pressure", output.get(1).getTerm());
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "prezure");
ourLog.info("Found: " + output);
assertEquals(2, output.size());
assertEquals("Pressure", output.get(0).getTerm());
assertEquals("Systolic Blood Pressure", output.get(1).getTerm());
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "syst");
ourLog.info("Found: " + output);
assertEquals(4, output.size());
assertEquals("syst", output.get(0).getTerm());
assertEquals("bbbb syst", output.get(1).getTerm());
assertEquals("Systolic", output.get(2).getTerm());
assertEquals("Systolic Blood Pressure", output.get(3).getTerm());
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "LCws");
ourLog.info("Found: " + output);
assertEquals(0, output.size());
}
@Test
public void testSuggest() {
Patient patient = new Patient();
patient.addName().addFamily("testSuggest");
IIdType ptId = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
Observation obs = new Observation();
obs.getSubject().setReference(ptId);
obs.getCode().setText("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL");
myObservationDao.create(obs);
obs = new Observation();
obs.getSubject().setReference(ptId);
obs.getCode().setText("MNBVCXZ");
myObservationDao.create(obs);
obs = new Observation();
obs.getSubject().setReference(ptId);
obs.getCode().setText("ZXC HELLO");
obs.addComponent().getCode().setText("HHHHHHHHHH");
myObservationDao.create(obs);
/*
* These shouldn't match since they're for another patient
*/
patient = new Patient();
patient.addName().addFamily("testSuggest2");
IIdType ptId2 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.getSubject().setReference(ptId2);
obs2.getCode().setText("ZXCVBNMZZ");
myObservationDao.create(obs2);
List<Suggestion> output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZXCVBNM");
ourLog.info("Found: " + output);
assertEquals(4, output.size());
assertEquals("ZXCVBNM", output.get(0).getTerm());
assertEquals("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL", output.get(1).getTerm());
assertEquals("ZXC", output.get(2).getTerm());
assertEquals("ZXC HELLO", output.get(3).getTerm());
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZXC");
ourLog.info("Found: " + output);
assertEquals(4, output.size());
assertEquals("ZXC", output.get(0).getTerm());
assertEquals("ZXC HELLO", output.get(1).getTerm());
assertEquals("ZXCVBNM", output.get(2).getTerm());
assertEquals("ZXCVBNM ASDFGHJKL QWERTYUIOPASDFGHJKL", output.get(3).getTerm());
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "HELO");
ourLog.info("Found: " + output);
assertEquals(2, output.size());
assertEquals("HELLO", output.get(0).getTerm());
assertEquals("ZXC HELLO", output.get(1).getTerm());
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "Z");
ourLog.info("Found: " + output);
assertEquals(0, output.size());
output = mySearchDao.suggestKeywords("Patient/" + ptId.getIdPart() + "/$everything", "_content", "ZX");
ourLog.info("Found: " + output);
assertEquals(2, output.size());
assertEquals("ZXC", output.get(0).getTerm());
assertEquals("ZXC HELLO", output.get(1).getTerm());
}
@Test
public void testSearchAndReindex() {
Patient patient;
SearchParameterMap map;
patient = new Patient();
patient.getText().setDiv("<div>DIVAAA</div>");
patient.addName().addGiven("NAMEAAA");
IIdType pId1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
map = new SearchParameterMap();
map.add(Constants.PARAM_TEXT, new StringParam("DIVAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
/*
* Reindex
*/
patient = new Patient();
patient.setId(pId1);
patient.getText().setDiv("<div>DIVBBB</div>");
patient.addName().addGiven("NAMEBBB");
myPatientDao.update(patient);
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty());
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("NAMEBBB"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
map = new SearchParameterMap();
map.add(Constants.PARAM_TEXT, new StringParam("DIVBBB"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
}
@Test
public void testEverythingInstanceWithContentFilter() {
Patient pt1 = new Patient();
pt1.addName().addFamily("Everything").addGiven("Arthur");
IIdType ptId1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
Patient pt2 = new Patient();
pt2.addName().addFamily("Everything").addGiven("Arthur");
IIdType ptId2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
Device dev1 = new Device();
dev1.setManufacturer("Some Manufacturer");
IIdType devId1 = myDeviceDao.create(dev1).getId().toUnqualifiedVersionless();
Device dev2 = new Device();
dev2.setManufacturer("Some Manufacturer 2");
myDeviceDao.create(dev2).getId().toUnqualifiedVersionless();
Observation obs1 = new Observation();
obs1.getText().setDiv("<div>OBSTEXT1</div>");
obs1.getSubject().setReference(ptId1);
obs1.getCode().addCoding().setCode("CODE1");
obs1.setValue(new StringDt("obsvalue1"));
obs1.getDevice().setReference(devId1);
IIdType obsId1 = myObservationDao.create(obs1).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.getSubject().setReference(ptId1);
obs2.getCode().addCoding().setCode("CODE2");
obs2.setValue(new StringDt("obsvalue2"));
IIdType obsId2 = myObservationDao.create(obs2).getId().toUnqualifiedVersionless();
Observation obs3 = new Observation();
obs3.getSubject().setReference(ptId2);
obs3.getCode().addCoding().setCode("CODE3");
obs3.setValue(new StringDt("obsvalue3"));
IIdType obsId3 = myObservationDao.create(obs3).getId().toUnqualifiedVersionless();
HttpServletRequest request;
List<IIdType> actual;
request = mock(HttpServletRequest.class);
StringAndListParam param;
ourLog.info("Pt1:{} Pt2:{} Obs1:{} Obs2:{} Obs3:{}", new Object[] {ptId1.getIdPart(), ptId2.getIdPart(), obsId1.getIdPart(), obsId2.getIdPart(), obsId3.getIdPart()});
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId1, devId1));
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obstext1")));
actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, param));
assertThat(actual, containsInAnyOrder(ptId1, obsId1, devId1));
request = mock(HttpServletRequest.class);
actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, null, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId2, devId1));
/*
* Add another match
*/
Observation obs4 = new Observation();
obs4.getSubject().setReference(ptId1);
obs4.getCode().addCoding().setCode("CODE1");
obs4.setValue(new StringDt("obsvalue1"));
IIdType obsId4 = myObservationDao.create(obs4).getId().toUnqualifiedVersionless();
assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId4, devId1));
/*
* Make one previous match no longer match
*/
obs1 = new Observation();
obs1.setId(obsId1);
obs1.getSubject().setReference(ptId1);
obs1.getCode().addCoding().setCode("CODE2");
obs1.setValue(new StringDt("obsvalue2"));
myObservationDao.update(obs1);
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
actual = toUnqualifiedVersionlessIds(myPatientDao.patientInstanceEverything(request, ptId1, null, null, null, param, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId4));
}
@Test
public void testEverythingTypeWithContentFilter() {
Patient pt1 = new Patient();
pt1.addName().addFamily("Everything").addGiven("Arthur");
IIdType ptId1 = myPatientDao.create(pt1).getId().toUnqualifiedVersionless();
Patient pt2 = new Patient();
pt2.addName().addFamily("Everything").addGiven("Arthur");
IIdType ptId2 = myPatientDao.create(pt2).getId().toUnqualifiedVersionless();
Device dev1 = new Device();
dev1.setManufacturer("Some Manufacturer");
IIdType devId1 = myDeviceDao.create(dev1).getId().toUnqualifiedVersionless();
Device dev2 = new Device();
dev2.setManufacturer("Some Manufacturer 2");
IIdType devId2 = myDeviceDao.create(dev2).getId().toUnqualifiedVersionless();
Observation obs1 = new Observation();
obs1.getSubject().setReference(ptId1);
obs1.getCode().addCoding().setCode("CODE1");
obs1.setValue(new StringDt("obsvalue1"));
obs1.getDevice().setReference(devId1);
IIdType obsId1 = myObservationDao.create(obs1).getId().toUnqualifiedVersionless();
Observation obs2 = new Observation();
obs2.getSubject().setReference(ptId1);
obs2.getCode().addCoding().setCode("CODE2");
obs2.setValue(new StringDt("obsvalue2"));
IIdType obsId2 = myObservationDao.create(obs2).getId().toUnqualifiedVersionless();
Observation obs3 = new Observation();
obs3.getSubject().setReference(ptId2);
obs3.getCode().addCoding().setCode("CODE3");
obs3.setValue(new StringDt("obsvalue3"));
IIdType obsId3 = myObservationDao.create(obs3).getId().toUnqualifiedVersionless();
HttpServletRequest request;
List<IIdType> actual;
request = mock(HttpServletRequest.class);
StringAndListParam param;
ourLog.info("Pt1:{} Pt2:{} Obs1:{} Obs2:{} Obs3:{}", new Object[] {ptId1.getIdPart(), ptId2.getIdPart(), obsId1.getIdPart(), obsId2.getIdPart(), obsId3.getIdPart()});
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, param, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId1, devId1));
request = mock(HttpServletRequest.class);
actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, null, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId2, devId1, ptId2, obsId3));
/*
* Add another match
*/
Observation obs4 = new Observation();
obs4.getSubject().setReference(ptId1);
obs4.getCode().addCoding().setCode("CODE1");
obs4.setValue(new StringDt("obsvalue1"));
IIdType obsId4 = myObservationDao.create(obs4).getId().toUnqualifiedVersionless();
assertNotEquals(obsId1.getIdPart(), obsId4.getIdPart(), devId1);
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, param, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId1, obsId4, devId1));
/*
* Make one previous match no longer match
*/
obs1 = new Observation();
obs1.setId(obsId1);
obs1.getSubject().setReference(ptId1);
obs1.getCode().addCoding().setCode("CODE2");
obs1.setValue(new StringDt("obsvalue2"));
myObservationDao.update(obs1);
param = new StringAndListParam();
param.addAnd(new StringOrListParam().addOr(new StringParam("obsvalue1")));
actual = toUnqualifiedVersionlessIds(myPatientDao.patientTypeEverything(request, null, null, null, param, null));
assertThat(actual, containsInAnyOrder(ptId1, obsId4));
}
/**
* When processing transactions, we do two passes. Make sure we don't update the lucene index twice since that would
* be inefficient
*/
@Test
public void testSearchDontReindexForUpdateWithIndexDisabled() {
Patient patient;
SearchParameterMap map;
patient = new Patient();
patient.getText().setDiv("<div>DIVAAA</div>");
patient.addName().addGiven("NAMEAAA");
IIdType pId1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
map = new SearchParameterMap();
map.add(Constants.PARAM_TEXT, new StringParam("DIVAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
/*
* Update but don't reindex
*/
patient = new Patient();
patient.setId(pId1);
patient.getText().setDiv("<div>DIVBBB</div>");
patient.addName().addGiven("NAMEBBB");
myPatientDao.update(patient, null, false);
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), not(contains(pId1)));
myPatientDao.update(patient, null, true);
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEAAA"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), empty());
map = new SearchParameterMap();
map.add(Patient.SP_NAME, new StringParam("NAMEBBB"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
map = new SearchParameterMap();
map.add(Constants.PARAM_CONTENT, new StringParam("NAMEBBB"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
map = new SearchParameterMap();
map.add(Constants.PARAM_TEXT, new StringParam("DIVBBB"));
assertThat(toUnqualifiedVersionlessIds(myPatientDao.search(map)), contains(pId1));
}
@Test
public void testSearchWithChainedParams() {
String methodName = "testSearchWithChainedParams";
IIdType pId1;
{
Patient patient = new Patient();
patient.addName().addGiven(methodName);
patient.addAddress().addLine("My fulltext address");
pId1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
Observation obs = new Observation();
obs.getSubject().setReference(pId1);
obs.setValue(new StringDt("This is the FULLtext of the observation"));
IIdType oId1 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
obs = new Observation();
obs.getSubject().setReference(pId1);
obs.setValue(new StringDt("Another fullText"));
IIdType oId2 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
List<IIdType> patients;
SearchParameterMap params;
params = new SearchParameterMap();
params.add(Constants.PARAM_CONTENT, new StringParam("fulltext"));
patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
assertThat(patients, containsInAnyOrder(pId1));
params = new SearchParameterMap();
params.add(Constants.PARAM_CONTENT, new StringParam("FULLTEXT"));
patients = toUnqualifiedVersionlessIds(myObservationDao.search(params));
assertThat(patients, containsInAnyOrder(oId1, oId2));
}
}

View File

@ -0,0 +1,491 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.empty;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.Date;
import java.util.List;
import javax.persistence.TypedQuery;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.jpa.dao.data.ISubscriptionFlaggedResourceDataDao;
import ca.uhn.fhir.jpa.dao.data.ISubscriptionTableDao;
import ca.uhn.fhir.jpa.entity.SubscriptionTable;
import ca.uhn.fhir.model.dstu21.resource.Observation;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.dstu21.resource.Subscription;
import ca.uhn.fhir.model.dstu21.valueset.ObservationStatusEnum;
import ca.uhn.fhir.model.dstu21.valueset.SubscriptionChannelTypeEnum;
import ca.uhn.fhir.model.dstu21.valueset.SubscriptionStatusEnum;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
public class FhirResourceDaoDstu21SubscriptionTest extends BaseJpaDstu21Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu21SubscriptionTest.class);
@Autowired
private ISubscriptionFlaggedResourceDataDao mySubscriptionFlaggedResourceDataDao;
@Autowired
private ISubscriptionTableDao mySubscriptionTableDao;
@Before
public void beforeEnableSubscription() {
myDaoConfig.setSubscriptionEnabled(true);
myDaoConfig.setSubscriptionPurgeInactiveAfterSeconds(60);
}
@Test
public void testSubscriptionGetsPurgedIfItIsNeverActive() throws Exception {
myDaoConfig.setSubscriptionPurgeInactiveAfterSeconds(1);
Subscription subs = new Subscription();
subs.setCriteria("Observation?subject=Patient/123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
IIdType id = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
mySubscriptionDao.purgeInactiveSubscriptions();
mySubscriptionDao.read(id);
Thread.sleep(1500);
myDaoConfig.setSchedulingDisabled(false);
mySubscriptionDao.purgeInactiveSubscriptions();
try {
mySubscriptionDao.read(id);
fail();
} catch (ResourceGoneException e) {
// good
}
}
@Before
public void beforeDisableScheduling() {
myDaoConfig.setSchedulingDisabled(true);
}
@Test
public void testSubscriptionGetsPurgedIfItIsInactive() throws Exception {
myDaoConfig.setSubscriptionPurgeInactiveAfterSeconds(1);
Subscription subs = new Subscription();
subs.setCriteria("Observation?subject=Patient/123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
IIdType id = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
mySubscriptionDao.purgeInactiveSubscriptions();
mySubscriptionDao.read(id);
mySubscriptionDao.getUndeliveredResourcesAndPurge(mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(id));
Thread.sleep(1500);
myDaoConfig.setSchedulingDisabled(false);
mySubscriptionDao.purgeInactiveSubscriptions();
try {
mySubscriptionDao.read(id);
fail();
} catch (ResourceGoneException e) {
// good
}
}
@Test
public void testCreateSubscription() {
Subscription subs = new Subscription();
subs.setCriteria("Observation?subject=Patient/123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
IIdType id = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
TypedQuery<SubscriptionTable> q = myEntityManager.createQuery("SELECT t from SubscriptionTable t WHERE t.mySubscriptionResource.myId = :id", SubscriptionTable.class);
q.setParameter("id", id.getIdPartAsLong());
final SubscriptionTable table = q.getSingleResult();
assertNotNull(table);
assertNotNull(table.getNextCheck());
assertEquals(table.getNextCheck(), table.getSubscriptionResource().getPublished().getValue());
assertEquals(SubscriptionStatusEnum.REQUESTED.getCode(), myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
mySubscriptionDao.update(subs);
assertEquals(SubscriptionStatusEnum.ACTIVE.getCode(), myEntityManager.find(SubscriptionTable.class, table.getId()).getStatus());
assertEquals(SubscriptionStatusEnum.ACTIVE, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
mySubscriptionDao.delete(id);
assertNull(myEntityManager.find(SubscriptionTable.class, table.getId()));
/*
* Re-create again
*/
subs = new Subscription();
subs.setCriteria("Observation?subject=Patient/123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setId(id);
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
mySubscriptionDao.update(subs);
assertEquals(SubscriptionStatusEnum.REQUESTED.getCode(), myEntityManager.createQuery("SELECT t FROM SubscriptionTable t WHERE t.myResId = " + id.getIdPart(), SubscriptionTable.class).getSingleResult().getStatus());
assertEquals(SubscriptionStatusEnum.REQUESTED, mySubscriptionDao.read(id).getStatusElement().getValueAsEnum());
}
@Test
public void testCreateSubscriptionInvalidCriteria() {
Subscription subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("Observation");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.criteria must be in the form \"{Resource Type}?[params]\""));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("http://foo.com/Observation?AAA=BBB");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.criteria must be in the form \"{Resource Type}?[params]\""));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("ObservationZZZZ?a=b");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.criteria contains invalid/unsupported resource type: ObservationZZZZ"));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("Observation?identifier=123");
try {
mySubscriptionDao.create(subs);
fail();
} catch (UnprocessableEntityException e) {
assertThat(e.getMessage(), containsString("Subscription.channel.type must be populated on this server"));
}
subs = new Subscription();
subs.setStatus(SubscriptionStatusEnum.REQUESTED);
subs.setCriteria("Observation?identifier=123");
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
assertTrue(mySubscriptionDao.create(subs).getId().hasIdPart());
}
@Test
public void testDeleteSubscriptionWithFlaggedResources() throws Exception {
myDaoConfig.setSubscriptionPollDelay(0);
String methodName = "testDeleteSubscriptionWithFlaggedResources";
Patient p = new Patient();
p.addName().addFamily(methodName);
IIdType pId = myPatientDao.create(p).getId().toUnqualifiedVersionless();
Subscription subs;
/*
* Create 2 identical subscriptions
*/
subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
IIdType subsId = mySubscriptionDao.create(subs).getId().toUnqualifiedVersionless();
Long subsPid = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(subsId);
assertNull(mySubscriptionTableDao.findOne(subsPid).getLastClientPoll());
Thread.sleep(100);
ourLog.info("Before: {}", System.currentTimeMillis());
assertThat(mySubscriptionFlaggedResourceDataDao.count(), not(greaterThan(0L)));
assertThat(mySubscriptionTableDao.count(), equalTo(1L));
Observation obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
myObservationDao.create(obs).getId().toUnqualifiedVersionless();
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Thread.sleep(100);
ourLog.info("After: {}", System.currentTimeMillis());
mySubscriptionDao.pollForNewUndeliveredResources();
assertThat(mySubscriptionFlaggedResourceDataDao.count(), greaterThan(0L));
assertThat(mySubscriptionTableDao.count(), greaterThan(0L));
/*
* Delete the subscription
*/
mySubscriptionDao.delete(subsId);
assertThat(mySubscriptionFlaggedResourceDataDao.count(), not(greaterThan(0L)));
assertThat(mySubscriptionTableDao.count(), not(greaterThan(0L)));
/*
* Delete a second time just to make sure that works
*/
mySubscriptionDao.delete(subsId);
/*
* Re-create the subscription
*/
subs.setId(subsId);
mySubscriptionDao.update(subs).getId();
assertThat(mySubscriptionFlaggedResourceDataDao.count(), not(greaterThan(0L)));
assertThat(mySubscriptionTableDao.count(), (greaterThan(0L)));
/*
* Create another resource and make sure it gets flagged
*/
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Thread.sleep(100);
mySubscriptionDao.pollForNewUndeliveredResources();
assertThat(mySubscriptionFlaggedResourceDataDao.count(), greaterThan(0L));
assertThat(mySubscriptionTableDao.count(), greaterThan(0L));
}
@Test
public void testSubscriptionResourcesAppear() throws Exception {
myDaoConfig.setSubscriptionPollDelay(0);
String methodName = "testSubscriptionResourcesAppear";
Patient p = new Patient();
p.addName().addFamily(methodName);
IIdType pId = myPatientDao.create(p).getId().toUnqualifiedVersionless();
Observation obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Subscription subs;
/*
* Create 2 identical subscriptions
*/
subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
Long subsId1 = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(mySubscriptionDao.create(subs).getId());
subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
Long subsId2 = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(mySubscriptionDao.create(subs).getId());
assertNull(mySubscriptionTableDao.findOne(subsId1).getLastClientPoll());
Thread.sleep(100);
ourLog.info("Before: {}", System.currentTimeMillis());
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
IIdType afterId1 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
IIdType afterId2 = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Thread.sleep(100);
ourLog.info("After: {}", System.currentTimeMillis());
List<IBaseResource> results;
List<IIdType> resultIds;
assertEquals(4, mySubscriptionDao.pollForNewUndeliveredResources());
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId1);
resultIds = toUnqualifiedVersionlessIds(results);
assertThat(resultIds, contains(afterId1, afterId2));
Date lastClientPoll = mySubscriptionTableDao.findOne(subsId1).getLastClientPoll();
assertNotNull(lastClientPoll);
mySubscriptionDao.pollForNewUndeliveredResources();
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId2);
resultIds = toUnqualifiedVersionlessIds(results);
assertThat(resultIds, contains(afterId1, afterId2));
mySubscriptionDao.pollForNewUndeliveredResources();
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId1);
resultIds = toUnqualifiedVersionlessIds(results);
assertThat(resultIds, empty());
assertNotEquals(lastClientPoll, mySubscriptionTableDao.findOne(subsId1).getLastClientPoll());
mySubscriptionDao.pollForNewUndeliveredResources();
results = mySubscriptionDao.getUndeliveredResourcesAndPurge(subsId2);
resultIds = toUnqualifiedVersionlessIds(results);
assertThat(resultIds, empty());
/*
* Make sure that reindexing doesn't trigger
*/
mySystemDao.markAllResourcesForReindexing();
mySystemDao.performReindexingPass(100);
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
/*
* Update resources on disk
*/
IBundleProvider allObs = myObservationDao.search(new SearchParameterMap());
ourLog.info("Updating {} observations", allObs.size());
for (IBaseResource next : allObs.getResources(0, allObs.size())) {
ourLog.info("Updating observation");
Observation nextObs = (Observation) next;
nextObs.addPerformer().setDisplay("Some display");
myObservationDao.update(nextObs);
}
assertEquals(6, mySubscriptionDao.pollForNewUndeliveredResources());
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
}
@Test
public void testSubscriptionResourcesAppear2() throws Exception {
myDaoConfig.setSubscriptionPollDelay(0);
String methodName = "testSubscriptionResourcesAppear2";
Patient p = new Patient();
p.addName().addFamily(methodName);
IIdType pId = myPatientDao.create(p).getId().toUnqualifiedVersionless();
Observation obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
IIdType oId = myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Subscription subs;
/*
* Create 2 identical subscriptions
*/
subs = new Subscription();
subs.getChannel().setType(SubscriptionChannelTypeEnum.WEBSOCKET);
subs.setCriteria("Observation?subject=Patient/" + pId.getIdPart());
subs.setStatus(SubscriptionStatusEnum.ACTIVE);
Long subsId1 = mySubscriptionDao.getSubscriptionTablePidForSubscriptionResource(mySubscriptionDao.create(subs).getId());
assertNull(mySubscriptionTableDao.findOne(subsId1).getLastClientPoll());
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
ourLog.info("pId: {} - oId: {}", pId, oId);
myObservationDao.update(myObservationDao.read(oId));
assertEquals(1, mySubscriptionDao.pollForNewUndeliveredResources());
ourLog.info("Between passes");
assertEquals(0, mySubscriptionDao.pollForNewUndeliveredResources());
Thread.sleep(100);
ourLog.info("Before: {}", System.currentTimeMillis());
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
myObservationDao.create(obs).getId().toUnqualifiedVersionless();
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
myObservationDao.create(obs).getId().toUnqualifiedVersionless();
Thread.sleep(100);
ourLog.info("After: {}", System.currentTimeMillis());
assertEquals(2, mySubscriptionDao.pollForNewUndeliveredResources());
assertEquals(3, mySubscriptionFlaggedResourceDataDao.count());
Thread.sleep(100);
mySubscriptionDao.pollForNewUndeliveredResources();
assertEquals(3, mySubscriptionFlaggedResourceDataDao.count());
Thread.sleep(100);
mySubscriptionDao.pollForNewUndeliveredResources();
assertEquals(3, mySubscriptionFlaggedResourceDataDao.count());
Thread.sleep(100);
obs = new Observation();
obs.getSubject().setReference(pId);
obs.setStatus(ObservationStatusEnum.FINAL);
myObservationDao.create(obs).getId().toUnqualifiedVersionless();
mySubscriptionDao.pollForNewUndeliveredResources();
assertEquals(4, mySubscriptionFlaggedResourceDataDao.count());
Thread.sleep(100);
mySubscriptionDao.pollForNewUndeliveredResources();
assertEquals(4, mySubscriptionFlaggedResourceDataDao.count());
}
}

View File

@ -0,0 +1,421 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.endsWith;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Test;
import org.mockito.ArgumentCaptor;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.Tag;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
import ca.uhn.fhir.model.dstu21.resource.Organization;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.InstantDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
import ca.uhn.fhir.rest.server.IBundleProvider;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor.ActionRequestDetails;
public class FhirResourceDaoDstu21UpdateTest extends BaseJpaDstu21Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu21UpdateTest.class);
@Test
public void testUpdateAndGetHistoryResource() throws InterruptedException {
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addFamily("Tester").addGiven("Joe");
MethodOutcome outcome = myPatientDao.create(patient);
assertNotNull(outcome.getId());
assertFalse(outcome.getId().isEmpty());
assertEquals("1", outcome.getId().getVersionIdPart());
Date now = new Date();
Patient retrieved = myPatientDao.read(outcome.getId());
InstantDt published = (InstantDt) retrieved.getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED);
InstantDt updated = (InstantDt) retrieved.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
assertTrue(published.before(now));
assertTrue(updated.before(now));
Thread.sleep(1000);
reset(myInterceptor);
retrieved.getIdentifierFirstRep().setValue("002");
MethodOutcome outcome2 = myPatientDao.update(retrieved);
assertEquals(outcome.getId().getIdPart(), outcome2.getId().getIdPart());
assertNotEquals(outcome.getId().getVersionIdPart(), outcome2.getId().getVersionIdPart());
assertEquals("2", outcome2.getId().getVersionIdPart());
// Verify interceptor
ArgumentCaptor<ActionRequestDetails> detailsCapt = ArgumentCaptor.forClass(ActionRequestDetails.class);
verify(myInterceptor).incomingRequestPreHandled(eq(RestOperationTypeEnum.UPDATE), detailsCapt.capture());
ActionRequestDetails details = detailsCapt.getValue();
assertNotNull(details.getId());
assertEquals("Patient", details.getResourceType());
assertEquals(Patient.class, details.getResource().getClass());
Date now2 = new Date();
Patient retrieved2 = myPatientDao.read(outcome.getId().toVersionless());
assertEquals("2", retrieved2.getId().getVersionIdPart());
assertEquals("002", retrieved2.getIdentifierFirstRep().getValue());
InstantDt published2 = (InstantDt) retrieved2.getResourceMetadata().get(ResourceMetadataKeyEnum.PUBLISHED);
InstantDt updated2 = (InstantDt) retrieved2.getResourceMetadata().get(ResourceMetadataKeyEnum.UPDATED);
assertTrue(published2.before(now));
assertTrue(updated2.after(now));
assertTrue(updated2.before(now2));
Thread.sleep(2000);
/*
* Get history
*/
IBundleProvider historyBundle = myPatientDao.history(outcome.getId(), null);
assertEquals(2, historyBundle.size());
List<IBaseResource> history = historyBundle.getResources(0, 2);
assertEquals("1", history.get(1).getIdElement().getVersionIdPart());
assertEquals("2", history.get(0).getIdElement().getVersionIdPart());
assertEquals(published, ResourceMetadataKeyEnum.PUBLISHED.get((IResource) history.get(1)));
assertEquals(published, ResourceMetadataKeyEnum.PUBLISHED.get((IResource) history.get(1)));
assertEquals(updated, ResourceMetadataKeyEnum.UPDATED.get((IResource) history.get(1)));
assertEquals("001", ((Patient) history.get(1)).getIdentifierFirstRep().getValue());
assertEquals(published2, ResourceMetadataKeyEnum.PUBLISHED.get((IResource) history.get(0)));
assertEquals(updated2, ResourceMetadataKeyEnum.UPDATED.get((IResource) history.get(0)));
assertEquals("002", ((Patient) history.get(0)).getIdentifierFirstRep().getValue());
}
@Test
public void testUpdateByUrl() {
String methodName = "testUpdateByUrl";
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
IIdType id = myPatientDao.create(p).getId();
ourLog.info("Created patient, got it: {}", id);
p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
myPatientDao.update(p, "Patient?identifier=urn%3Asystem%7C" + methodName);
p = myPatientDao.read(id.toVersionless());
assertThat(p.getId().toVersionless().toString(), not(containsString("test")));
assertEquals(id.toVersionless(), p.getId().toVersionless());
assertNotEquals(id, p.getId());
assertThat(p.getId().toString(), endsWith("/_history/2"));
}
@Test
public void testUpdateCreatesTextualIdIfItDoesntAlreadyExist() {
Patient p = new Patient();
String methodName = "testUpdateCreatesTextualIdIfItDoesntAlreadyExist";
p.addIdentifier().setSystem("urn:system").setValue(methodName);
p.addName().addFamily("Hello");
p.setId("Patient/" + methodName);
IIdType id = myPatientDao.update(p).getId();
assertEquals("Patient/" + methodName, id.toUnqualifiedVersionless().getValue());
p = myPatientDao.read(id);
assertEquals(methodName, p.getIdentifierFirstRep().getValue());
}
@Test
public void testUpdateDoesntFailForUnknownIdWithNumberThenText() {
String methodName = "testUpdateFailsForUnknownIdWithNumberThenText";
Patient p = new Patient();
p.setId("0" + methodName);
p.addName().addFamily(methodName);
myPatientDao.update(p);
}
/**
* Per the spec, update should preserve tags and security labels but not profiles
*/
@Test
public void testUpdateMaintainsTagsAndSecurityLabels() throws InterruptedException {
String methodName = "testUpdateMaintainsTagsAndSecurityLabels";
IIdType p1id;
{
Patient p1 = new Patient();
p1.addName().addFamily(methodName);
TagList tagList = new TagList();
tagList.addTag("tag_scheme1", "tag_term1");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, tagList);
List<BaseCodingDt> secList = new ArrayList<BaseCodingDt>();
secList.add(new CodingDt("sec_scheme1", "sec_term1"));
ResourceMetadataKeyEnum.SECURITY_LABELS.put(p1, secList);
List<IdDt> profileList = new ArrayList<IdDt>();
profileList.add(new IdDt("http://foo1"));
ResourceMetadataKeyEnum.PROFILES.put(p1, profileList);
p1id = myPatientDao.create(p1).getId().toUnqualifiedVersionless();
}
{
Patient p1 = new Patient();
p1.setId(p1id);
p1.addName().addFamily(methodName);
TagList tagList = new TagList();
tagList.addTag("tag_scheme2", "tag_term2");
ResourceMetadataKeyEnum.TAG_LIST.put(p1, tagList);
List<BaseCodingDt> secList = new ArrayList<BaseCodingDt>();
secList.add(new CodingDt("sec_scheme2", "sec_term2"));
ResourceMetadataKeyEnum.SECURITY_LABELS.put(p1, secList);
List<IdDt> profileList = new ArrayList<IdDt>();
profileList.add(new IdDt("http://foo2"));
ResourceMetadataKeyEnum.PROFILES.put(p1, profileList);
myPatientDao.update(p1);
}
{
Patient p1 = myPatientDao.read(p1id);
TagList tagList = ResourceMetadataKeyEnum.TAG_LIST.get(p1);
assertThat(tagList, containsInAnyOrder(new Tag("tag_scheme1", "tag_term1"), new Tag("tag_scheme2", "tag_term2")));
List<BaseCodingDt> secList = ResourceMetadataKeyEnum.SECURITY_LABELS.get(p1);
Set<String> secListValues = new HashSet<String>();
for (BaseCodingDt next : secList) {
secListValues.add(next.getSystemElement().getValue() + "|" + next.getCodeElement().getValue());
}
assertThat(secListValues, containsInAnyOrder("sec_scheme1|sec_term1", "sec_scheme2|sec_term2"));
List<IdDt> profileList = ResourceMetadataKeyEnum.PROFILES.get(p1);
assertThat(profileList, contains(new IdDt("http://foo2"))); // no foo1
}
}
@Test
public void testUpdateMaintainsSearchParams() throws InterruptedException {
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsDstu2AAA");
p1.addName().addFamily("Tester").addGiven("testUpdateMaintainsSearchParamsDstu2AAA");
IIdType p1id = myPatientDao.create(p1).getId();
Patient p2 = new Patient();
p2.addIdentifier().setSystem("urn:system").setValue("testUpdateMaintainsSearchParamsDstu2BBB");
p2.addName().addFamily("Tester").addGiven("testUpdateMaintainsSearchParamsDstu2BBB");
myPatientDao.create(p2).getId();
Set<Long> ids = myPatientDao.searchForIds(Patient.SP_GIVEN, new StringDt("testUpdateMaintainsSearchParamsDstu2AAA"));
assertEquals(1, ids.size());
assertThat(ids, contains(p1id.getIdPartAsLong()));
// Update the name
p1.getNameFirstRep().getGivenFirstRep().setValue("testUpdateMaintainsSearchParamsDstu2BBB");
MethodOutcome update2 = myPatientDao.update(p1);
IIdType p1id2 = update2.getId();
ids = myPatientDao.searchForIds(Patient.SP_GIVEN, new StringDt("testUpdateMaintainsSearchParamsDstu2AAA"));
assertEquals(0, ids.size());
ids = myPatientDao.searchForIds(Patient.SP_GIVEN, new StringDt("testUpdateMaintainsSearchParamsDstu2BBB"));
assertEquals(2, ids.size());
// Make sure vreads work
p1 = myPatientDao.read(p1id);
assertEquals("testUpdateMaintainsSearchParamsDstu2AAA", p1.getNameFirstRep().getGivenAsSingleString());
p1 = myPatientDao.read(p1id2);
assertEquals("testUpdateMaintainsSearchParamsDstu2BBB", p1.getNameFirstRep().getGivenAsSingleString());
}
@Test
public void testUpdateRejectsInvalidTypes() throws InterruptedException {
Patient p1 = new Patient();
p1.addIdentifier().setSystem("urn:system").setValue("testUpdateRejectsInvalidTypes");
p1.addName().addFamily("Tester").addGiven("testUpdateRejectsInvalidTypes");
IIdType p1id = myPatientDao.create(p1).getId();
Organization p2 = new Organization();
p2.getNameElement().setValue("testUpdateRejectsInvalidTypes");
try {
p2.setId(new IdDt("Organization/" + p1id.getIdPart()));
myOrganizationDao.update(p2);
fail();
} catch (UnprocessableEntityException e) {
// good
}
try {
p2.setId(new IdDt("Patient/" + p1id.getIdPart()));
myOrganizationDao.update(p2);
fail();
} catch (UnprocessableEntityException e) {
ourLog.error("Good", e);
}
}
@Test
public void testDuplicateProfilesIgnored() {
String name = "testDuplicateProfilesIgnored";
IIdType id;
{
Patient patient = new Patient();
patient.addName().addFamily(name);
List<IdDt> tl = new ArrayList<IdDt>();
tl.add(new IdDt("http://foo/bar"));
tl.add(new IdDt("http://foo/bar"));
tl.add(new IdDt("http://foo/bar"));
ResourceMetadataKeyEnum.PROFILES.put(patient, tl);
id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
// Do a read
{
Patient patient = myPatientDao.read(id);
List<IdDt> tl = ResourceMetadataKeyEnum.PROFILES.get(patient);
assertEquals(1, tl.size());
assertEquals("http://foo/bar", tl.get(0).getValue());
}
}
@Test
public void testUpdateModifiesProfiles() {
String name = "testUpdateModifiesProfiles";
IIdType id;
{
Patient patient = new Patient();
patient.addName().addFamily(name);
List<IdDt> tl = new ArrayList<IdDt>();
tl.add(new IdDt("http://foo/bar"));
ResourceMetadataKeyEnum.PROFILES.put(patient, tl);
id = myPatientDao.create(patient).getId().toUnqualifiedVersionless();
}
// Do a read
{
Patient patient = myPatientDao.read(id);
List<IdDt> tl = ResourceMetadataKeyEnum.PROFILES.get(patient);
assertEquals(1, tl.size());
assertEquals("http://foo/bar", tl.get(0).getValue());
}
// Update
{
Patient patient = new Patient();
patient.setId(id);
patient.addName().addFamily(name);
List<IdDt> tl = new ArrayList<IdDt>();
tl.add(new IdDt("http://foo/baz"));
ResourceMetadataKeyEnum.PROFILES.put(patient, tl);
id = myPatientDao.update(patient).getId().toUnqualifiedVersionless();
}
// Do a read
{
Patient patient = myPatientDao.read(id);
List<IdDt> tl = ResourceMetadataKeyEnum.PROFILES.get(patient);
assertEquals(1, tl.size());
assertEquals("http://foo/baz", tl.get(0).getValue());
}
}
@Test
public void testUpdateUnknownNumericIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/9999999999999999");
try {
myPatientDao.update(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("Can not create resource with ID[9999999999999999], no resource with this ID exists and clients may only"));
}
}
@Test
public void testUpdateWithInvalidIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123:456");
try {
myPatientDao.update(p);
fail();
} catch (InvalidRequestException e) {
assertEquals("Can not process entity with ID[123:456], this is not a valid FHIR ID", e.getMessage());
}
}
@Test
public void testUpdateWithNumericIdFails() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123");
try {
myPatientDao.update(p);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("clients may only assign IDs which contain at least one non-numeric"));
}
}
@Test
public void testUpdateWithNumericThenTextIdSucceeds() {
Patient p = new Patient();
p.addIdentifier().setSystem("urn:system").setValue("testCreateNumericIdFails");
p.addName().addFamily("Hello");
p.setId("Patient/123abc");
IIdType id = myPatientDao.update(p).getId();
assertEquals("123abc", id.getIdPart());
assertEquals("1", id.getVersionIdPart());
p = myPatientDao.read(id.toUnqualifiedVersionless());
assertEquals("Patient/123abc", p.getId().toUnqualifiedVersionless().getValue());
assertEquals("Hello", p.getName().get(0).getFamily().get(0).getValue());
}
}

View File

@ -0,0 +1,245 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.util.Arrays;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Test;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu21.resource.Bundle;
import ca.uhn.fhir.model.dstu21.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu21.resource.Observation;
import ca.uhn.fhir.model.dstu21.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu21.resource.Organization;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.model.dstu21.resource.StructureDefinition;
import ca.uhn.fhir.model.dstu21.resource.ValueSet;
import ca.uhn.fhir.model.dstu21.valueset.ObservationStatusEnum;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.api.MethodOutcome;
import ca.uhn.fhir.rest.api.ValidationModeEnum;
import ca.uhn.fhir.rest.server.EncodingEnum;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
public class FhirResourceDaoDstu21ValidateTest extends BaseJpaDstu21Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu21ValidateTest.class);
@Test
public void testValidateResourceContainingProfileDeclarationJson() throws Exception {
String methodName = "testValidateResourceContainingProfileDeclarationJson";
OperationOutcome outcome = doTestValidateResourceContainingProfileDeclaration(methodName, EncodingEnum.JSON);
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
ourLog.info(ooString);
assertThat(ooString, containsString("Element '.subject': minimum required = 1, but only found 0"));
assertThat(ooString, containsString("Element encounter @ : max allowed = 0, but found 1"));
assertThat(ooString, containsString("Element '.device': minimum required = 1, but only found 0"));
}
@Test
public void testValidateResourceContainingProfileDeclarationXml() throws Exception {
String methodName = "testValidateResourceContainingProfileDeclarationXml";
OperationOutcome outcome = doTestValidateResourceContainingProfileDeclaration(methodName, EncodingEnum.XML);
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
ourLog.info(ooString);
assertThat(ooString, containsString("Element '/f:Observation.subject': minimum required = 1, but only found 0"));
assertThat(ooString, containsString("Element encounter @ /f:Observation: max allowed = 0, but found 1"));
assertThat(ooString, containsString("Element '/f:Observation.device': minimum required = 1, but only found 0"));
}
private OperationOutcome doTestValidateResourceContainingProfileDeclaration(String methodName, EncodingEnum enc) throws IOException {
Bundle vss = loadResourceFromClasspath(Bundle.class, "/org/hl7/fhir/instance/model/dstu21/valueset/valuesets.xml");
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-status"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-category"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-codes"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-methods"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-valueabsentreason"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-interpretation"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "body-site"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "referencerange-meaning"));
myValueSetDao.update((ValueSet) findResourceByIdInBundle(vss, "observation-relationshiptypes"));
StructureDefinition sd = loadResourceFromClasspath(StructureDefinition.class, "/org/hl7/fhir/instance/model/dstu21/profile/devicemetricobservation.profile.xml");
sd.setId(new IdDt());
sd.setUrl("http://example.com/foo/bar/" + methodName);
myStructureDefinitionDao.create(sd);
Observation input = new Observation();
ResourceMetadataKeyEnum.PROFILES.put(input, Arrays.asList(new IdDt(sd.getUrl())));
input.addIdentifier().setSystem("http://acme").setValue("12345");
input.getEncounter().setReference("http://foo.com/Encounter/9");
input.setStatus(ObservationStatusEnum.FINAL);
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
String encoded = null;
MethodOutcome outcome = null;
ValidationModeEnum mode = ValidationModeEnum.CREATE;
switch (enc) {
case JSON:
encoded = myFhirCtx.newJsonParser().encodeResourceToString(input);
try {
myObservationDao.validate(input, null, encoded, EncodingEnum.JSON, mode, null);
fail();
} catch (PreconditionFailedException e) {
return (OperationOutcome) e.getOperationOutcome();
}
case XML:
encoded = myFhirCtx.newXmlParser().encodeResourceToString(input);
try {
myObservationDao.validate(input, null, encoded, EncodingEnum.XML, mode, null);
fail();
} catch (PreconditionFailedException e) {
return (OperationOutcome) e.getOperationOutcome();
}
}
throw new IllegalStateException(); // shouldn't get here
}
@Test
public void testValidateResourceContainingProfileDeclarationInvalid() throws Exception {
String methodName = "testValidateResourceContainingProfileDeclarationInvalid";
Observation input = new Observation();
String profileUri = "http://example.com/" + methodName;
ResourceMetadataKeyEnum.PROFILES.put(input, Arrays.asList(new IdDt(profileUri)));
input.addIdentifier().setSystem("http://acme").setValue("12345");
input.getEncounter().setReference("http://foo.com/Encounter/9");
input.setStatus(ObservationStatusEnum.FINAL);
input.getCode().addCoding().setSystem("http://loinc.org").setCode("12345");
ValidationModeEnum mode = ValidationModeEnum.CREATE;
String encoded = myFhirCtx.newJsonParser().encodeResourceToString(input);
MethodOutcome outcome = myObservationDao.validate(input, null, encoded, EncodingEnum.JSON, mode, null);
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome.getOperationOutcome());
ourLog.info(ooString);
assertThat(ooString, containsString("StructureDefinition reference \\\"" + profileUri + "\\\" could not be resolved"));
}
@Test
public void testValidateForCreate() {
String methodName = "testValidateForCreate";
Patient pat = new Patient();
pat.setId("Patient/123");
pat.addName().addFamily(methodName);
try {
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.CREATE, null);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("ID must not be populated"));
}
pat.setId("");
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.CREATE, null);
}
@Test
public void testValidateForUpdate() {
String methodName = "testValidateForUpdate";
Patient pat = new Patient();
pat.setId("Patient/123");
pat.addName().addFamily(methodName);
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null);
pat.setId("");
try {
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("ID must be populated"));
}
}
@Test
public void testValidateForUpdateWithContained() {
String methodName = "testValidateForUpdate";
Organization org = new Organization();
org.setId("#123");
Patient pat = new Patient();
pat.setId("Patient/123");
pat.addName().addFamily(methodName);
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null);
pat.setId("");
try {
myPatientDao.validate(pat, null, null, null, ValidationModeEnum.UPDATE, null);
fail();
} catch (InvalidRequestException e) {
assertThat(e.getMessage(), containsString("ID must be populated"));
}
}
@Test
public void testValidateForDelete() {
String methodName = "testValidateForDelete";
Organization org = new Organization();
org.setName(methodName);
IIdType orgId = myOrganizationDao.create(org).getId().toUnqualifiedVersionless();
Patient pat = new Patient();
pat.addName().addFamily(methodName);
pat.getManagingOrganization().setReference(orgId);
IIdType patId = myPatientDao.create(pat).getId().toUnqualifiedVersionless();
OperationOutcome outcome = null;
try {
myOrganizationDao.validate(null, orgId, null, null, ValidationModeEnum.DELETE, null);
fail();
} catch (ResourceVersionConflictException e) {
outcome = (OperationOutcome) e.getOperationOutcome();
}
String ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
ourLog.info(ooString);
assertThat(ooString, containsString("Unable to delete Organization"));
pat.setId(patId);
pat.getManagingOrganization().setReference("");
myPatientDao.update(pat);
outcome = (OperationOutcome) myOrganizationDao.validate(null, orgId, null, null, ValidationModeEnum.DELETE, null).getOperationOutcome();
ooString = myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(outcome);
ourLog.info(ooString);
assertThat(ooString, containsString("Ok to delete"));
}
private IResource findResourceByIdInBundle(Bundle vss, String name) {
IResource retVal = null;
for (Entry next : vss.getEntry()) {
if (next.getResource().getId().getIdPart().equals(name)) {
retVal = next.getResource();
break;
}
}
if (retVal == null) {
fail("Can't find VS: " + name);
}
return retVal;
}
}

View File

@ -0,0 +1,220 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.stringContainsInOrder;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Before;
import org.junit.Test;
import org.springframework.transaction.annotation.Transactional;
import ca.uhn.fhir.jpa.dao.IFhirResourceDaoValueSet.ValidateCodeResult;
import ca.uhn.fhir.model.dstu21.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
import ca.uhn.fhir.model.dstu21.resource.ValueSet;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.model.primitive.UriDt;
public class FhirResourceDaoValueSetDstu21Test extends BaseJpaDstu21Test {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoValueSetDstu21Test.class);
private IIdType myExtensionalVsId;
@Before
@Transactional
public void before02() throws IOException {
ValueSet upload = loadResourceFromClasspath(ValueSet.class, "/extensional-case-2.xml");
upload.setId("");
myExtensionalVsId = myValueSetDao.create(upload).getId().toUnqualifiedVersionless();
}
@Test
public void testValidateCodeOperationByCodeAndSystemBad() {
UriDt valueSetIdentifier = null;
IdDt id = null;
CodeDt code = new CodeDt("8450-9-XXX");
UriDt system = new UriDt("http://loinc.org");
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
assertFalse(result.isResult());
}
@Test
public void testValidateCodeOperationByCodeAndSystemGood() {
UriDt valueSetIdentifier = null;
IdDt id = null;
CodeDt code = new CodeDt("8450-9");
UriDt system = new UriDt("http://loinc.org");
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure--expiration", result.getDisplay());
}
@Test
public void testValidateCodeOperationByIdentifierAndCodeAndSystem() {
UriDt valueSetIdentifier = new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
IdDt id = null;
CodeDt code = new CodeDt("11378-7");
UriDt system = new UriDt("http://loinc.org");
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@Test
public void testValidateCodeOperationByIdentifierAndCodeAndSystemAndBadDisplay() {
UriDt valueSetIdentifier = new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
IdDt id = null;
CodeDt code = new CodeDt("11378-7");
UriDt system = new UriDt("http://loinc.org");
StringDt display = new StringDt("Systolic blood pressure at First encounterXXXX");
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
assertFalse(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@Test
public void testValidateCodeOperationByIdentifierAndCodeAndSystemAndGoodDisplay() {
UriDt valueSetIdentifier = new UriDt("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
IdDt id = null;
CodeDt code = new CodeDt("11378-7");
UriDt system = new UriDt("http://loinc.org");
StringDt display = new StringDt("Systolic blood pressure at First encounter");
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@Test
public void testValidateCodeOperationByResourceIdAndCodeableConcept() {
UriDt valueSetIdentifier = null;
IIdType id = myExtensionalVsId;
CodeDt code = null;
UriDt system = null;
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = new CodeableConceptDt("http://loinc.org", "11378-7");
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@Test
public void testValidateCodeOperationByResourceIdAndCodeAndSystem() {
UriDt valueSetIdentifier = null;
IIdType id = myExtensionalVsId;
CodeDt code = new CodeDt("11378-7");
UriDt system = new UriDt("http://loinc.org");
StringDt display = null;
CodingDt coding = null;
CodeableConceptDt codeableConcept = null;
ValidateCodeResult result = myValueSetDao.validateCode(valueSetIdentifier, id, code, system, display, coding, codeableConcept);
assertTrue(result.isResult());
assertEquals("Systolic blood pressure at First encounter", result.getDisplay());
}
@Test
public void testExpandById() throws IOException {
String resp;
ValueSet expanded = myValueSetDao.expand(myExtensionalVsId, null);
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
// @formatter:off
assertThat(resp,
stringContainsInOrder("<ValueSet xmlns=\"http://hl7.org/fhir\">",
"<expansion>",
"<contains>",
"<system value=\"http://loinc.org\"/>",
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>",
"</contains>",
"<contains>",
"<system value=\"http://loinc.org\"/>",
"<code value=\"8450-9\"/>",
"<display value=\"Systolic blood pressure--expiration\"/>",
"</contains>",
"</expansion>"
));
//@formatter:on
/*
* Filter with display name
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("systolic"));
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
//@formatter:on
/*
* Filter with code
*/
expanded = myValueSetDao.expand(myExtensionalVsId, ("11378"));
resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
//@formatter:on
}
@Test
public void testExpandByIdentifier() {
ValueSet expanded = myValueSetDao.expandByIdentifier("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", "11378");
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
//@formatter:on
assertThat(resp, not(containsString("<code value=\"8450-9\"/>")));
}
@Test
public void testExpandByValueSet() throws IOException {
ValueSet toExpand = loadResourceFromClasspath(ValueSet.class, "/extensional-case-2.xml");
ValueSet expanded = myValueSetDao.expand(toExpand, "11378");
String resp = myFhirCtx.newXmlParser().setPrettyPrint(true).encodeResourceToString(expanded);
ourLog.info(resp);
//@formatter:off
assertThat(resp, stringContainsInOrder(
"<code value=\"11378-7\"/>",
"<display value=\"Systolic blood pressure at First encounter\"/>"));
//@formatter:on
assertThat(resp, not(containsString("<code value=\"8450-9\"/>")));
}
}

View File

@ -0,0 +1,173 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import static org.hamcrest.Matchers.containsInAnyOrder;
import static org.hamcrest.Matchers.empty;
import static org.junit.Assert.assertThat;
import java.util.List;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import ca.uhn.fhir.jpa.dao.ISearchDao;
import ca.uhn.fhir.jpa.dao.SearchParameterMap;
import ca.uhn.fhir.model.dstu21.resource.Organization;
import ca.uhn.fhir.model.dstu21.resource.Patient;
import ca.uhn.fhir.rest.param.StringAndListParam;
import ca.uhn.fhir.rest.param.StringOrListParam;
import ca.uhn.fhir.rest.param.StringParam;
import ca.uhn.fhir.rest.server.Constants;
public class FhirSearchDaoDstu21Test extends BaseJpaDstu21Test {
@Autowired
private ISearchDao mySearchDao;
@Test
public void testContentSearch() {
Long id1;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("001");
patient.addName().addGiven("testSearchStringParamWithNonNormalized_h\u00F6ra");
patient.addName().addFamily("AAAS");
patient.addName().addFamily("CCC");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless().getIdPartAsLong();
}
Long id2;
{
Patient patient = new Patient();
patient.addIdentifier().setSystem("urn:system").setValue("002");
patient.addName().addGiven("testSearchStringParamWithNonNormalized_HORA");
patient.addName().addFamily("AAAB");
patient.addName().addFamily("CCC");
id2 = myPatientDao.create(patient).getId().toUnqualifiedVersionless().getIdPartAsLong();
}
Long id3;
{
Organization org = new Organization();
org.setName("DDD");
id3 = myOrganizationDao.create(org).getId().toUnqualifiedVersionless().getIdPartAsLong();
}
SearchParameterMap map = new SearchParameterMap();
String resourceName = "Patient";
// One term
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
map.add(Constants.PARAM_CONTENT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1));
}
// OR
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")).addOr(new StringParam("AAAB")));
map.add(Constants.PARAM_CONTENT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1, id2));
}
// AND
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
map.add(Constants.PARAM_CONTENT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1));
}
// AND OR
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAB")).addOr(new StringParam("AAAS")));
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
map.add(Constants.PARAM_CONTENT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1, id2));
}
// All Resource Types
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")).addOr(new StringParam("DDD")));
map.add(Constants.PARAM_CONTENT, content);
List<Long> found = mySearchDao.search(null, map);
assertThat(found, containsInAnyOrder(id1, id2, id3));
}
}
@Test
public void testNarrativeSearch() {
Long id1;
{
Patient patient = new Patient();
patient.getText().setDiv("<div>AAAS<p>FOO</p> CCC </div>");
id1 = myPatientDao.create(patient).getId().toUnqualifiedVersionless().getIdPartAsLong();
}
Long id2;
{
Patient patient = new Patient();
patient.getText().setDiv("<div>AAAB<p>FOO</p> CCC </div>");
id2 = myPatientDao.create(patient).getId().toUnqualifiedVersionless().getIdPartAsLong();
}
SearchParameterMap map = new SearchParameterMap();
String resourceName = "Patient";
// One term
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
map.add(Constants.PARAM_TEXT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1));
}
// OR
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")).addOr(new StringParam("AAAB")));
map.add(Constants.PARAM_TEXT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1, id2));
}
// AND
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAS")));
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
map.add(Constants.PARAM_TEXT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1));
}
// AND OR
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("AAAB")).addOr(new StringParam("AAAS")));
content.addAnd(new StringOrListParam().addOr(new StringParam("CCC")));
map.add(Constants.PARAM_TEXT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, containsInAnyOrder(id1, id2));
}
// Tag Contents
{
StringAndListParam content = new StringAndListParam();
content.addAnd(new StringOrListParam().addOr(new StringParam("div")));
map.add(Constants.PARAM_TEXT, content);
List<Long> found = mySearchDao.search(resourceName, map);
assertThat(found, empty());
}
}
}

View File

@ -0,0 +1,43 @@
package ca.uhn.fhir.jpa.dao.dstu21;
import org.junit.Test;
public class FhirSystemDaoDstu21SearchTest extends BaseJpaDstu21SystemTest {
@Test
public void testSearchByParans() {
// code to come.. just here to prevent a failure
}
/*//@formatter:off
* [ERROR] Search parameter action has conflicting types token and reference
* [ERROR] Search parameter source has conflicting types token and reference
* [ERROR] Search parameter plan has conflicting types reference and token
* [ERROR] Search parameter version has conflicting types token and string
* [ERROR] Search parameter source has conflicting types reference and uri
* [ERROR] Search parameter location has conflicting types reference and uri
* [ERROR] Search parameter title has conflicting types string and token
* [ERROR] Search parameter manufacturer has conflicting types string and reference
* [ERROR] Search parameter address has conflicting types token and string
* [ERROR] Search parameter source has conflicting types reference and string
* [ERROR] Search parameter destination has conflicting types reference and string
* [ERROR] Search parameter responsible has conflicting types reference and string
* [ERROR] Search parameter value has conflicting types token and string
* [ERROR] Search parameter address has conflicting types token and string
* [ERROR] Search parameter address has conflicting types token and string
* [ERROR] Search parameter address has conflicting types token and string
* [ERROR] Search parameter address has conflicting types token and string
* [ERROR] Search parameter action has conflicting types reference and token
* [ERROR] Search parameter version has conflicting types token and string
* [ERROR] Search parameter address has conflicting types token and string
* [ERROR] Search parameter base has conflicting types reference and token
* [ERROR] Search parameter target has conflicting types reference and token
* [ERROR] Search parameter base has conflicting types reference and uri
* [ERROR] Search parameter contact has conflicting types string and token
* [ERROR] Search parameter substance has conflicting types token and reference
* [ERROR] Search parameter provider has conflicting types reference and token
* [ERROR] Search parameter system has conflicting types token and uri
* [ERROR] Search parameter reference has conflicting types reference and uri
* //@formatter:off
*/
}

View File

@ -50,6 +50,7 @@ import ca.uhn.fhir.model.dstu.resource.Patient;
import ca.uhn.fhir.model.dstu.valueset.EncounterClassEnum;
import ca.uhn.fhir.model.dstu.valueset.EncounterStateEnum;
import ca.uhn.fhir.model.dstu.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.api.MethodOutcome;
@ -544,7 +545,7 @@ public class ResourceProviderDstu1Test extends BaseJpaTest {
restServer.setPagingProvider(new FifoMemoryPagingProvider(10));
IFhirSystemDao<List<IResource>> systemDao = ourAppCtx.getBean(IFhirSystemDao.class);
IFhirSystemDao<List<IResource>, MetaDt> systemDao = ourAppCtx.getBean(IFhirSystemDao.class);
JpaConformanceProviderDstu1 confProvider = new JpaConformanceProviderDstu1(restServer, systemDao);
confProvider.setImplementationDescription("THIS IS THE DESC");
restServer.setServerConformanceProvider(confProvider);

View File

@ -20,7 +20,7 @@ import org.hl7.fhir.instance.model.api.IIdType;
import org.junit.Before;
import org.junit.Test;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.Patient;
@ -53,7 +53,7 @@ public class SubscriptionsDstu2Test extends BaseResourceProviderDstu2Test {
public void beforeCreateInterceptor() {
super.beforeCreateInterceptor();
SubscriptionsRequireManualActivationInterceptor interceptor = new SubscriptionsRequireManualActivationInterceptor();
SubscriptionsRequireManualActivationInterceptorDstu2 interceptor = new SubscriptionsRequireManualActivationInterceptorDstu2();
interceptor.setDao(mySubscriptionDao);
myDaoConfig.getInterceptors().add(interceptor);
}

View File

@ -17,7 +17,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.LoggingInterceptor;
@ -98,7 +98,8 @@ public class FhirServerConfig extends BaseJavaConfigDstu2 {
@Bean(autowire = Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
return new SubscriptionsRequireManualActivationInterceptor();
SubscriptionsRequireManualActivationInterceptorDstu2 retVal = new SubscriptionsRequireManualActivationInterceptorDstu2();
return retVal;
}
@Bean()

View File

@ -17,6 +17,7 @@ import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
@ -76,12 +77,12 @@ public class JpaServerDemo extends RestfulServer {
* is a nice addition.
*/
if (fhirVersion == FhirVersionEnum.DSTU1) {
IFhirSystemDao<List<IResource>> systemDao = myAppCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class);
IFhirSystemDao<List<IResource>, MetaDt> systemDao = myAppCtx.getBean("mySystemDaoDstu1", IFhirSystemDao.class);
JpaConformanceProviderDstu1 confProvider = new JpaConformanceProviderDstu1(this, systemDao);
confProvider.setImplementationDescription("Example Server");
setServerConformanceProvider(confProvider);
} else {
IFhirSystemDao<Bundle> systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
IFhirSystemDao<Bundle, MetaDt> systemDao = myAppCtx.getBean("mySystemDaoDstu2", IFhirSystemDao.class);
JpaConformanceProviderDstu2 confProvider = new JpaConformanceProviderDstu2(this, systemDao, myAppCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription("Example Server");
setServerConformanceProvider(confProvider);

View File

@ -33,5 +33,9 @@
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry combineaccessrules="false" kind="src" path="/hapi-fhir-jpaserver-base"/>
<classpathentry combineaccessrules="false" kind="src" path="/hapi-fhir-structures-dstu"/>
<classpathentry combineaccessrules="false" kind="src" path="/hapi-fhir-structures-dstu2"/>
<classpathentry combineaccessrules="false" kind="src" path="/hapi-fhir-structures-dstu2.1"/>
<classpathentry kind="output" path="target/classes"/>
</classpath>

View File

@ -9,18 +9,21 @@ import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.web.context.ContextLoaderListener;
import org.springframework.web.context.WebApplicationContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.jpa.config.WebsocketDstu21Config;
import ca.uhn.fhir.jpa.config.WebsocketDstu2Config;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu1;
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu2;
import ca.uhn.fhir.jpa.provider.JpaConformanceProviderDstu21;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu1;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu2;
import ca.uhn.fhir.jpa.provider.JpaSystemProviderDstu21;
import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
import ca.uhn.fhir.rest.server.ETagSupportEnum;
import ca.uhn.fhir.rest.server.EncodingEnum;
@ -30,6 +33,8 @@ import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
import ca.uhn.fhirtest.config.TestDstu21Config;
import ca.uhn.fhirtest.config.TestDstu2Config;
public class TestRestfulServer extends RestfulServer {
@ -37,7 +42,7 @@ public class TestRestfulServer extends RestfulServer {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(TestRestfulServer.class);
private ApplicationContext myAppCtx;
private AnnotationConfigApplicationContext myAppCtx;
@SuppressWarnings("unchecked")
@Override
@ -60,6 +65,7 @@ public class TestRestfulServer extends RestfulServer {
List<IResourceProvider> beans;
JpaSystemProviderDstu1 systemProviderDstu1 = null;
JpaSystemProviderDstu2 systemProviderDstu2 = null;
JpaSystemProviderDstu21 systemProviderDstu21 = null;
@SuppressWarnings("rawtypes")
IFhirSystemDao systemDao;
ETagSupportEnum etagSupport;
@ -79,7 +85,10 @@ public class TestRestfulServer extends RestfulServer {
break;
}
case "DSTU2": {
myAppCtx = parentAppCtx;
myAppCtx = new AnnotationConfigApplicationContext();
myAppCtx.setParent(parentAppCtx);
myAppCtx.register(TestDstu2Config.class, WebsocketDstu2Config.class);
myAppCtx.refresh();
setFhirContext(FhirContext.forDstu2());
beans = myAppCtx.getBean("myResourceProvidersDstu2", List.class);
systemProviderDstu2 = myAppCtx.getBean("mySystemProviderDstu2", JpaSystemProviderDstu2.class);
@ -91,6 +100,22 @@ public class TestRestfulServer extends RestfulServer {
baseUrlProperty = "fhir.baseurl.dstu2";
break;
}
case "DSTU21": {
myAppCtx = new AnnotationConfigApplicationContext();
myAppCtx.setParent(parentAppCtx);
myAppCtx.register(TestDstu21Config.class, WebsocketDstu21Config.class);
myAppCtx.refresh();
setFhirContext(FhirContext.forDstu2_1());
beans = myAppCtx.getBean("myResourceProvidersDstu21", List.class);
systemProviderDstu21 = myAppCtx.getBean("mySystemProviderDstu21", JpaSystemProviderDstu21.class);
systemDao = myAppCtx.getBean("mySystemDaoDstu21", IFhirSystemDao.class);
etagSupport = ETagSupportEnum.ENABLED;
JpaConformanceProviderDstu21 confProvider = new JpaConformanceProviderDstu21(this, systemDao, myAppCtx.getBean(DaoConfig.class));
confProvider.setImplementationDescription(implDesc);
setServerConformanceProvider(confProvider);
baseUrlProperty = "fhir.baseurl.dstu21";
break;
}
default:
throw new ServletException("Unknown FHIR version specified in init-param[FhirVersion]: " + fhirVersionParam);
}
@ -117,10 +142,15 @@ public class TestRestfulServer extends RestfulServer {
setResourceProviders(beans);
List<Object> provList = new ArrayList<Object>();
if (systemProviderDstu1 != null)
if (systemProviderDstu1 != null) {
provList.add(systemProviderDstu1);
if (systemProviderDstu2 != null)
}
if (systemProviderDstu2 != null) {
provList.add(systemProviderDstu2);
}
if (systemProviderDstu21 != null) {
provList.add(systemProviderDstu21);
}
setPlainProviders(provList);
/*

View File

@ -0,0 +1,109 @@
package ca.uhn.fhirtest.config;
import java.util.Properties;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import org.apache.commons.dbcp2.BasicDataSource;
import org.apache.commons.lang3.time.DateUtils;
import org.hibernate.jpa.HibernatePersistenceProvider;
import org.springframework.beans.factory.annotation.Autowire;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu21;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu21;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
@Configuration
@Import(CommonConfig.class)
@EnableTransactionManagement()
public class TestDstu21Config extends BaseJavaConfigDstu21 {
@Value("${fhir.db.location.dstu21}")
private String myFhirDbLocation;
@Value("${fhir.lucene.location.dstu21}")
private String myFhirLuceneLocation;
/**
* This lets the "@Value" fields reference properties from the properties file
*/
@Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
@Bean()
public DaoConfig daoConfig() {
DaoConfig retVal = new DaoConfig();
retVal.setSubscriptionEnabled(true);
retVal.setSubscriptionPollDelay(5000);
retVal.setSubscriptionPurgeInactiveAfterMillis(DateUtils.MILLIS_PER_HOUR);
retVal.setAllowMultipleDelete(true);
return retVal;
}
@Bean(name = "myPersistenceDataSourceDstu21", destroyMethod = "close")
@DependsOn("dbServer")
public DataSource dataSource() {
BasicDataSource retVal = new BasicDataSource();
retVal.setDriver(new org.apache.derby.jdbc.ClientDriver());
// retVal.setUrl("jdbc:derby:directory:" + myFhirDbLocation + ";create=true");
retVal.setUrl("jdbc:derby://localhost:1527/" + myFhirDbLocation + ";create=true");
retVal.setUsername("SA");
retVal.setPassword("SA");
return retVal;
}
@Bean()
public JpaTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
JpaTransactionManager retVal = new JpaTransactionManager();
retVal.setEntityManagerFactory(entityManagerFactory);
return retVal;
}
@Bean()
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
LocalContainerEntityManagerFactoryBean retVal = new LocalContainerEntityManagerFactoryBean();
retVal.setPersistenceUnitName("PU_HapiFhirJpaDstu21");
retVal.setDataSource(dataSource());
retVal.setPackagesToScan("ca.uhn.fhir.jpa.entity");
retVal.setPersistenceProvider(new HibernatePersistenceProvider());
retVal.setJpaProperties(jpaProperties());
retVal.afterPropertiesSet();
return retVal;
}
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.jdbc.batch_size", "20");
extraProperties.put("hibernate.cache.use_query_cache", "false");
extraProperties.put("hibernate.cache.use_second_level_cache", "false");
extraProperties.put("hibernate.cache.use_structured_entries", "false");
extraProperties.put("hibernate.cache.use_minimal_puts", "false");
extraProperties.put("hibernate.search.default.directory_provider" ,"filesystem");
extraProperties.put("hibernate.search.default.indexBase", myFhirLuceneLocation);
extraProperties.put("hibernate.search.lucene_version","LUCENE_CURRENT");
return extraProperties;
}
@Bean(autowire=Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
return new SubscriptionsRequireManualActivationInterceptorDstu21();
}
}

View File

@ -14,7 +14,6 @@ import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySources;
import org.springframework.context.support.PropertySourcesPlaceholderConfigurer;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
@ -22,7 +21,7 @@ import org.springframework.transaction.annotation.EnableTransactionManagement;
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu2;
import ca.uhn.fhir.jpa.dao.DaoConfig;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptor;
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu2;
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
@Configuration
@ -87,7 +86,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
private Properties jpaProperties() {
Properties extraProperties = new Properties();
extraProperties.put("hibernate.format_sql", "true");
extraProperties.put("hibernate.format_sql", "false");
extraProperties.put("hibernate.show_sql", "false");
extraProperties.put("hibernate.hbm2ddl.auto", "update");
extraProperties.put("hibernate.jdbc.batch_size", "20");
@ -103,7 +102,7 @@ public class TestDstu2Config extends BaseJavaConfigDstu2 {
@Bean(autowire=Autowire.BY_TYPE)
public IServerInterceptor subscriptionSecurityInterceptor() {
return new SubscriptionsRequireManualActivationInterceptor();
return new SubscriptionsRequireManualActivationInterceptorDstu2();
}

View File

@ -13,6 +13,7 @@
<property name="servers">
<list>
<value>home_dev , DSTU2 , UHN/HAPI Server (DSTU2 FHIR) , http://fhirtest.uhn.ca/baseDstu2</value>
<value>home_21 , DSTU2 , UHN/HAPI Server (DSTU2.1 FHIR) , http://fhirtest.uhn.ca/baseDstu2.1</value>
<value>home , DSTU1 , UHN/HAPI Server (DSTU1 FHIR) , http://fhirtest.uhn.ca/baseDstu1</value>
<value>hidev , DSTU2 , Health Intersections (DSTU2 FHIR) , http://fhir-dev.healthintersections.com.au/open</value>
<value>hi , DSTU1 , Health Intersections (DSTU1 FHIR) , http://fhir.healthintersections.com.au/open</value>

View File

@ -15,8 +15,6 @@
<param-name>contextConfigLocation</param-name>
<param-value>
ca.uhn.fhirtest.config.DbServerConfig
ca.uhn.fhirtest.config.TestDstu2Config
ca.uhn.fhir.jpa.config.WebsocketDstu2Config
</param-value>
</context-param>
@ -76,7 +74,7 @@
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>UHN Test Server (DSTU1 Resources)</param-value>
<param-value>UHN Test Server (DSTU 1 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
@ -90,7 +88,7 @@
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>UHN Test Server (DSTU2 Resources)</param-value>
<param-value>UHN Test Server (DSTU 2 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
@ -99,6 +97,20 @@
<load-on-startup>1</load-on-startup>
</servlet>
<servlet>
<servlet-name>fhirServletDstu21</servlet-name>
<servlet-class>ca.uhn.fhirtest.TestRestfulServer</servlet-class>
<init-param>
<param-name>ImplementationDescription</param-name>
<param-value>UHN Test Server (DSTU 2.1 Resources)</param-value>
</init-param>
<init-param>
<param-name>FhirVersion</param-name>
<param-value>DSTU21</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>fhirServletDstu1</servlet-name>
<url-pattern>/base/*</url-pattern>
@ -114,6 +126,11 @@
<url-pattern>/baseDstu2/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServletDstu21</servlet-name>
<url-pattern>/baseDstu2.1/*</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>fhirServletDstu2</servlet-name>
<url-pattern>/baseDev/*</url-pattern>

View File

@ -1,13 +1,9 @@
package ca.uhn.fhirtest;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.webapp.WebAppContext;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
import ca.uhn.fhir.model.dstu.resource.Organization;
@ -29,9 +25,12 @@ public class UhnFhirTestApp {
// new File("target/testdb").mkdirs();
System.setProperty("fhir.db.location", "./target/testdb");
System.setProperty("fhir.db.location.dstu2", "./target/testdb_dstu2");
System.setProperty("fhir.db.location.dstu21", "./target/testdb_dstu21");
System.setProperty("fhir.lucene.location.dstu2", "./target/testlucene_dstu2");
System.setProperty("fhir.lucene.location.dstu21", "./target/testlucene_dstu21");
System.setProperty("fhir.baseurl.dstu1", base.replace("Dstu2", "Dstu1"));
System.setProperty("fhir.baseurl.dstu2", base);
System.setProperty("fhir.baseurl.dstu21", base.replace("Dstu2", "Dstu21"));
Server server = new Server(myPort);

147
hapi-fhir-structures-dstu2.1/.gitignore vendored Normal file
View File

@ -0,0 +1,147 @@
/bin
/target
*.log
*.log*
/.settings/
.classpath
.project
/target/
/target/
/target/
/target/
/target/
/target/
# Created by https://www.gitignore.io
### Java ###
*.class
# Mobile Tools for Java (J2ME)
.mtj.tmp/
# Package Files #
*.jar
*.war
*.ear
# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
hs_err_pid*
### Maven ###
target/
pom.xml.tag
pom.xml.releaseBackup
pom.xml.versionsBackup
pom.xml.next
release.properties
dependency-reduced-pom.xml
buildNumber.properties
### Vim ###
[._]*.s[a-w][a-z]
[._]s[a-w][a-z]
*.un~
Session.vim
.netrwhist
*~
### Intellij ###
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm
*.iml
## Directory-based project format:
.idea/
# if you remove the above rule, at least ignore the following:
# User-specific stuff:
# .idea/workspace.xml
# .idea/tasks.xml
# .idea/dictionaries
# Sensitive or high-churn files:
# .idea/dataSources.ids
# .idea/dataSources.xml
# .idea/sqlDataSources.xml
# .idea/dynamic.xml
# .idea/uiDesigner.xml
# Gradle:
# .idea/gradle.xml
# .idea/libraries
# Mongo Explorer plugin:
# .idea/mongoSettings.xml
## File-based project format:
*.ipr
*.iws
## Plugin-specific files:
# IntelliJ
/out/
# mpeltonen/sbt-idea plugin
.idea_modules/
# JIRA plugin
atlassian-ide-plugin.xml
# Crashlytics plugin (for Android Studio and IntelliJ)
com_crashlytics_export_strings.xml
crashlytics.properties
crashlytics-build.properties
### Eclipse ###
*.pydevproject
.metadata
.gradle
bin/
tmp/
*.tmp
*.bak
*.swp
*~.nib
local.properties
.settings/
.loadpath
# Eclipse Core
.project
# External tool builders
.externalToolBuilders/
# Locally stored "Eclipse launch configurations"
*.launch
# CDT-specific
.cproject
# JDT-specific (Eclipse Java Development Tools)
.classpath
# PDT-specific
.buildpath
# sbteclipse plugin
.target
# TeXlipse plugin
.texlipse
/target/
/target/
/target/
/target/
/target/
/target/
/target/
/target/

View File

@ -0,0 +1 @@
cat tmp.yxy | sort | sed "s/=.*//" | sed "s/^/<baseResourceName>/" | sed "s/\$/<\/baseResourceName>/"

View File

@ -0,0 +1,322 @@
<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">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-deployable-pom</artifactId>
<version>1.4-SNAPSHOT</version>
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
</parent>
<artifactId>hapi-fhir-structures-dstu2.1</artifactId>
<packaging>jar</packaging>
<name>HAPI FHIR Structures - DSTU2.1 (FHIR v1.1.x)</name>
<dependencies>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.4-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-validation-resources-dstu2.1</artifactId>
<version>1.4-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<scope>provided</scope>
</dependency>
<!-- Testing -->
<!-- <dependency> <groupId>ca.uhn.hapi.fhir</groupId> <artifactId>hapi-fhir-structures-dstu</artifactId> <version>0.8</version> <scope>test</scope> </dependency> -->
<dependency>
<groupId>xmlunit</groupId>
<artifactId>xmlunit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlets</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-servlet</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-util</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-webapp</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.eclipse.jetty</groupId>
<artifactId>jetty-http</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<optional>true</optional>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.ebaysf.web</groupId>
<artifactId>cors-filter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-schematron</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.phloc</groupId>
<artifactId>phloc-commons</artifactId>
<scope>test</scope>
</dependency>
<!-- UNIT TEST DEPENDENCIES -->
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15</classifier>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>net.sf.json-lib</groupId>
<artifactId>json-lib</artifactId>
<version>2.4</version>
<classifier>jdk15-sources</classifier>
<scope>test</scope>
</dependency>
<dependency>
<groupId>directory-naming</groupId>
<artifactId>naming-java</artifactId>
<version>0.8</version>
<scope>test</scope>
<exclusions>
<exclusion>
<artifactId>commons-logging</artifactId>
<groupId>commons-logging</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-tinder-plugin</artifactId>
<version>1.4-SNAPSHOT</version>
<executions>
<execution>
<id>generate</id>
<goals>
<goal>generate-structures</goal>
</goals>
<configuration>
<baseResourceNames>
<baseResourceName>supportingdocumentation</baseResourceName>
<baseResourceName>account</baseResourceName>
<baseResourceName>allergyintolerance</baseResourceName>
<baseResourceName>appointment</baseResourceName>
<baseResourceName>appointmentresponse</baseResourceName>
<baseResourceName>auditevent</baseResourceName>
<baseResourceName>basic</baseResourceName>
<baseResourceName>binary</baseResourceName>
<baseResourceName>bodysite</baseResourceName>
<baseResourceName>bundle</baseResourceName>
<baseResourceName>careplan</baseResourceName>
<baseResourceName>claim</baseResourceName>
<baseResourceName>claimresponse</baseResourceName>
<baseResourceName>clinicalimpression</baseResourceName>
<baseResourceName>communication</baseResourceName>
<baseResourceName>communicationrequest</baseResourceName>
<baseResourceName>composition</baseResourceName>
<baseResourceName>conceptmap</baseResourceName>
<baseResourceName>condition</baseResourceName>
<baseResourceName>condition</baseResourceName>
<baseResourceName>conformance</baseResourceName>
<baseResourceName>contract</baseResourceName>
<baseResourceName>coverage</baseResourceName>
<baseResourceName>dataelement</baseResourceName>
<baseResourceName>decisionsupportrule</baseResourceName>
<baseResourceName>decisionsupportservicemodule</baseResourceName>
<baseResourceName>detectedissue</baseResourceName>
<baseResourceName>device</baseResourceName>
<baseResourceName>devicecomponent</baseResourceName>
<baseResourceName>devicemetric</baseResourceName>
<baseResourceName>deviceuserequest</baseResourceName>
<baseResourceName>deviceusestatement</baseResourceName>
<baseResourceName>diagnosticorder</baseResourceName>
<baseResourceName>diagnosticreport</baseResourceName>
<baseResourceName>documentmanifest</baseResourceName>
<baseResourceName>documentreference</baseResourceName>
<baseResourceName>eligibilityrequest</baseResourceName>
<baseResourceName>eligibilityresponse</baseResourceName>
<baseResourceName>encounter</baseResourceName>
<baseResourceName>enrollmentrequest</baseResourceName>
<baseResourceName>enrollmentresponse</baseResourceName>
<baseResourceName>episodeofcare</baseResourceName>
<baseResourceName>expansionprofile</baseResourceName>
<baseResourceName>explanationofbenefit</baseResourceName>
<baseResourceName>familymemberhistory</baseResourceName>
<baseResourceName>flag</baseResourceName>
<baseResourceName>goal</baseResourceName>
<baseResourceName>group</baseResourceName>
<baseResourceName>guidancerequest</baseResourceName>
<baseResourceName>guidanceresponse</baseResourceName>
<baseResourceName>healthcareservice</baseResourceName>
<baseResourceName>imagingobjectselection</baseResourceName>
<baseResourceName>imagingstudy</baseResourceName>
<baseResourceName>immunization</baseResourceName>
<baseResourceName>immunizationrecommendation</baseResourceName>
<baseResourceName>implementationguide</baseResourceName>
<baseResourceName>library</baseResourceName>
<baseResourceName>list</baseResourceName>
<baseResourceName>location</baseResourceName>
<baseResourceName>measure</baseResourceName>
<baseResourceName>media</baseResourceName>
<baseResourceName>medication</baseResourceName>
<baseResourceName>medicationadministration</baseResourceName>
<baseResourceName>medicationdispense</baseResourceName>
<baseResourceName>medicationorder</baseResourceName>
<baseResourceName>medicationstatement</baseResourceName>
<baseResourceName>messageheader</baseResourceName>
<baseResourceName>moduledefinition</baseResourceName>
<baseResourceName>modulemetadata</baseResourceName>
<baseResourceName>namingsystem</baseResourceName>
<baseResourceName>nutritionorder</baseResourceName>
<baseResourceName>observation</baseResourceName>
<baseResourceName>operationdefinition</baseResourceName>
<baseResourceName>operationoutcome</baseResourceName>
<baseResourceName>order</baseResourceName>
<baseResourceName>orderresponse</baseResourceName>
<baseResourceName>orderset</baseResourceName>
<baseResourceName>organization</baseResourceName>
<baseResourceName>patient</baseResourceName>
<baseResourceName>paymentnotice</baseResourceName>
<baseResourceName>paymentreconciliation</baseResourceName>
<baseResourceName>person</baseResourceName>
<baseResourceName>practitioner</baseResourceName>
<baseResourceName>procedure</baseResourceName>
<baseResourceName>procedurerequest</baseResourceName>
<baseResourceName>processrequest</baseResourceName>
<baseResourceName>processresponse</baseResourceName>
<baseResourceName>provenance</baseResourceName>
<baseResourceName>questionnaire</baseResourceName>
<baseResourceName>questionnaireresponse</baseResourceName>
<baseResourceName>referralrequest</baseResourceName>
<baseResourceName>relatedperson</baseResourceName>
<baseResourceName>riskassessment</baseResourceName>
<baseResourceName>schedule</baseResourceName>
<baseResourceName>searchparameter</baseResourceName>
<baseResourceName>slot</baseResourceName>
<baseResourceName>specimen</baseResourceName>
<baseResourceName>structuredefinition</baseResourceName>
<baseResourceName>subscription</baseResourceName>
<baseResourceName>substance</baseResourceName>
<baseResourceName>supplydelivery</baseResourceName>
<baseResourceName>supplyrequest</baseResourceName>
<baseResourceName>testscript</baseResourceName>
<baseResourceName>valueset</baseResourceName>
<baseResourceName>visionprescription</baseResourceName>
<baseResourceName>parameters</baseResourceName>
</baseResourceNames>
<package>ca.uhn.fhir.model.dstu21</package>
<version>dstu21</version>
<buildDatatypes>true</buildDatatypes>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
<pluginManagement>
<plugins>
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-tinder-plugin</artifactId>
<versionRange>[0.4-SNAPSHOT,)</versionRange>
<goals>
<goal>generate-structures</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore></ignore>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
</resource>
<resource>
<directory>${basedir}/target/generated-resources/tinder</directory>
</resource>
</resources>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>${maven_javadoc_plugin_version}</version>
<configuration>
</configuration>
</plugin>
</plugins>
</reporting>
</project>

View File

@ -0,0 +1,128 @@
package ca.uhn.fhir.model.dstu21;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.io.InputStream;
import java.util.Date;
import org.apache.commons.lang3.StringUtils;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.IPrimitiveType;
import ca.uhn.fhir.context.ConfigurationException;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.model.api.IFhirVersion;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
import ca.uhn.fhir.model.dstu21.composite.ContainedDt;
import ca.uhn.fhir.model.dstu21.composite.ResourceReferenceDt;
import ca.uhn.fhir.model.dstu21.resource.StructureDefinition;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.IVersionSpecificBundleFactory;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.provider.dstu21.Dstu21BundleFactory;
import ca.uhn.fhir.rest.server.provider.dstu21.ServerConformanceProvider;
import ca.uhn.fhir.rest.server.provider.dstu21.ServerProfileProvider;
public class FhirDstu21 implements IFhirVersion {
private String myId;
@Override
public ServerConformanceProvider createServerConformanceProvider(RestfulServer theServer) {
return new ServerConformanceProvider(theServer);
}
@Override
public IResourceProvider createServerProfilesProvider(RestfulServer theRestfulServer) {
return new ServerProfileProvider(theRestfulServer);
}
@Override
public IResource generateProfile(RuntimeResourceDefinition theRuntimeResourceDefinition, String theServerBase) {
StructureDefinition retVal = new StructureDefinition();
RuntimeResourceDefinition def = theRuntimeResourceDefinition;
myId = def.getId();
if (StringUtils.isBlank(myId)) {
myId = theRuntimeResourceDefinition.getName().toLowerCase();
}
retVal.setId(new IdDt(myId));
return retVal;
}
@Override
public Class<? extends BaseContainedDt> getContainedType() {
return ContainedDt.class;
}
@Override
public InputStream getFhirVersionPropertiesFile() {
InputStream str = FhirDstu21.class.getResourceAsStream("/ca/uhn/fhir/model/dstu21/fhirversion.properties");
if (str == null) {
str = FhirDstu21.class.getResourceAsStream("ca/uhn/fhir/model/dstu21/fhirversion.properties");
}
if (str == null) {
throw new ConfigurationException("Can not find model property file on classpath: " + "/ca/uhn/fhir/model/dstu21/fhirversion.properties");
}
return str;
}
@Override
public IPrimitiveType<Date> getLastUpdated(IBaseResource theResource) {
return ResourceMetadataKeyEnum.UPDATED.get((IResource) theResource);
}
@Override
public String getPathToSchemaDefinitions() {
return "/org/hl7/fhir/instance/model/dstu21/schema";
}
@Override
public Class<? extends BaseResourceReferenceDt> getResourceReferenceType() {
return ResourceReferenceDt.class;
}
@Override
public FhirVersionEnum getVersion() {
return FhirVersionEnum.DSTU2_1;
}
@Override
public IVersionSpecificBundleFactory newBundleFactory(FhirContext theContext) {
return new Dstu21BundleFactory(theContext);
}
@Override
public BaseCodingDt newCodingDt() {
return new CodingDt();
}
}

View File

@ -0,0 +1,30 @@
package ca.uhn.fhir.model.dstu21.composite;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.dstu21.composite.QuantityDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
@DatatypeDef(name="AgeDt", profileOf=QuantityDt.class)
public class AgeDt extends QuantityDt {
}

View File

@ -0,0 +1,141 @@
package ca.uhn.fhir.model.dstu21.composite;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.defaultString;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.apache.commons.lang3.Validate;
import ca.uhn.fhir.model.api.IBoundCodeableConcept;
import ca.uhn.fhir.model.api.IValueSetEnumBinder;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.dstu21.composite.CodeableConceptDt;
import ca.uhn.fhir.model.dstu21.composite.CodingDt;
@DatatypeDef(name = "CodeableConcept", isSpecialization = true)
public class BoundCodeableConceptDt<T extends Enum<?>> extends CodeableConceptDt implements IBoundCodeableConcept {
private IValueSetEnumBinder<T> myBinder;
/**
* @deprecated This constructor is provided only for serialization support. Do not call it directly!
*/
@Deprecated
public BoundCodeableConceptDt() {
// nothing
}
/**
* Constructor
*/
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder) {
Validate.notNull(theBinder, "theBinder must not be null");
myBinder = theBinder;
}
/**
* Constructor
*/
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder, T theValue) {
Validate.notNull(theBinder, "theBinder must not be null");
myBinder = theBinder;
setValueAsEnum(theValue);
}
/**
* Constructor
*/
public BoundCodeableConceptDt(IValueSetEnumBinder<T> theBinder, Collection<T> theValues) {
Validate.notNull(theBinder, "theBinder must not be null");
myBinder = theBinder;
setValueAsEnum(theValues);
}
/**
* Sets the {@link #getCoding()} to contain a coding with the code and
* system defined by the given enumerated types, AND clearing any existing
* codings first. If theValue is null, existing codings are cleared and no
* codings are added.
*
* @param theValues
* The value to add, or <code>null</code>
*/
public void setValueAsEnum(Collection<T> theValues) {
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!");
getCoding().clear();
if (theValues != null) {
for (T next : theValues) {
getCoding().add(new CodingDt(myBinder.toSystemString(next), myBinder.toCodeString(next)));
}
}
}
/**
* Sets the {@link #getCoding()} to contain a coding with the code and
* system defined by the given enumerated type, AND clearing any existing
* codings first. If theValue is null, existing codings are cleared and no
* codings are added.
*
* @param theValue
* The value to add, or <code>null</code>
*/
public void setValueAsEnum(T theValue) {
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!");
getCoding().clear();
if (theValue == null) {
return;
}
getCoding().add(new CodingDt(myBinder.toSystemString(theValue), myBinder.toCodeString(theValue)));
}
/**
* Loops through the {@link #getCoding() codings} in this codeable concept
* and returns the first bound enumerated type that matches. <b>Use
* caution</b> using this method, see the return description for more
* information.
*
* @return Returns the bound enumerated type, or <code>null</code> if none
* are found. Note that a null return value doesn't neccesarily
* imply that this Codeable Concept has no codes, only that it has
* no codes that match the enum.
*/
public Set<T> getValueAsEnum() {
Validate.notNull(myBinder, "This object does not have a binder. Constructor BoundCodeableConceptDt() should not be called!");
Set<T> retVal = new HashSet<T>();
for (CodingDt next : getCoding()) {
if (next == null) {
continue;
}
T nextT = myBinder.fromCodeString(defaultString(next.getCodeElement().getValue()), defaultString(next.getSystemElement().getValueAsString()));
if (nextT != null) {
retVal.add(nextT);
} else {
// TODO: throw special exception type?
}
}
return retVal;
}
}

View File

@ -0,0 +1,54 @@
package ca.uhn.fhir.model.dstu21.composite;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.ArrayList;
import java.util.List;
import ca.uhn.fhir.model.api.IDatatype;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.base.composite.BaseContainedDt;
@DatatypeDef(name = "contained")
public class ContainedDt extends BaseContainedDt {
@Child(name = "resource", type = IResource.class, order = 0, min = 0, max = Child.MAX_UNLIMITED)
private List<IResource> myContainedResources;
public List<IResource> getContainedResources() {
if (myContainedResources == null) {
myContainedResources = new ArrayList<IResource>();
}
return myContainedResources;
}
public void setContainedResources(List<IResource> theContainedResources) {
myContainedResources = theContainedResources;
}
@Override
public boolean isEmpty() {
return myContainedResources == null || myContainedResources.size() == 0;
}
}

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.model.dstu21.composite;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.dstu21.composite.QuantityDt;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
@DatatypeDef(name="CountDt", profileOf=QuantityDt.class)
public class CountDt extends QuantityDt {
}

View File

@ -0,0 +1,30 @@
package ca.uhn.fhir.model.dstu21.composite;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.dstu21.composite.QuantityDt;
import ca.uhn.fhir.model.primitive.IntegerDt;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
@DatatypeDef(name="DistanceDt", profileOf=QuantityDt.class)
public class DistanceDt extends QuantityDt {
}

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.model.dstu21.composite;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.dstu21.composite.QuantityDt;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
@DatatypeDef(name="DurationDt", profileOf=QuantityDt.class)
public class DurationDt extends QuantityDt {
}

View File

@ -0,0 +1,29 @@
package ca.uhn.fhir.model.dstu21.composite;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.dstu21.composite.QuantityDt;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
@DatatypeDef(name="Money", profileOf=QuantityDt.class)
public class MoneyDt extends QuantityDt {
}

View File

@ -0,0 +1,203 @@
package ca.uhn.fhir.model.dstu21.composite;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.base.composite.BaseNarrativeDt;
import ca.uhn.fhir.model.dstu21.valueset.NarrativeStatusEnum;
import ca.uhn.fhir.model.primitive.BoundCodeDt;
import ca.uhn.fhir.model.primitive.CodeDt;
import ca.uhn.fhir.model.primitive.XhtmlDt;
/**
* HAPI/FHIR <b>Narrative</b> Datatype
* (A human-readable formatted text, including images)
*
* <p>
* <b>Definition:</b>
* A human-readable formatted text, including images
* </p>
*
* <p>
* <b>Requirements:</b>
*
* </p>
*/
@DatatypeDef(name="Narrative")
public class NarrativeDt extends BaseNarrativeDt {
@Child(name="status", type=CodeDt.class, order=0, min=1, max=1)
private BoundCodeDt<NarrativeStatusEnum> myStatus;
@Child(name="div", type=XhtmlDt.class, order=1, min=1, max=1)
private XhtmlDt myDiv;
public NarrativeDt() {
// nothing
}
public NarrativeDt(XhtmlDt theDiv, NarrativeStatusEnum theStatus) {
setDiv(theDiv);
setStatus(theStatus);
}
@Override
public boolean isEmpty() {
return ca.uhn.fhir.util.ElementUtil.isEmpty( myStatus, myDiv );
}
@Override
public <T extends IElement> List<T> getAllPopulatedChildElementsOfType(Class<T> theType) {
return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements( theType, myStatus, myDiv );
}
/**
* Gets the value(s) for <b>status</b> (generated | extensions | additional).
* creating it if it does
* not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b>
* The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data
* </p>
*/
public BoundCodeDt<NarrativeStatusEnum> getStatusElement() {
return getStatus();
}
/**
* Gets the value(s) for <b>status</b> (generated | extensions | additional).
* creating it if it does
* not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b>
* The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data
* </p>
*/
public BoundCodeDt<NarrativeStatusEnum> getStatus() {
if (myStatus == null) {
myStatus = new BoundCodeDt<NarrativeStatusEnum>(NarrativeStatusEnum.VALUESET_BINDER);
}
return myStatus;
}
/**
* Sets the value(s) for <b>status</b> (generated | extensions | additional)
*
* <p>
* <b>Definition:</b>
* The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data
* </p>
*/
public void setStatus(BoundCodeDt<NarrativeStatusEnum> theValue) {
myStatus = theValue;
}
/**
* Sets the value(s) for <b>status</b> (generated | extensions | additional)
*
* <p>
* <b>Definition:</b>
* The status of the narrative - whether it's entirely generated (from just the defined data or the extensions too), or whether a human authored it and it may contain additional data
* </p>
*/
public void setStatus(NarrativeStatusEnum theValue) {
getStatus().setValueAsEnum(theValue);
}
/**
* Gets the value(s) for <b>div</b> (Limited xhtml content).
* creating it if it does
* not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b>
* The actual narrative content, a stripped down version of XHTML
* </p>
*/
public XhtmlDt getDivElement() {
return getDiv();
}
/**
* Gets the value(s) for <b>div</b> (Limited xhtml content).
* creating it if it does
* not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b>
* The actual narrative content, a stripped down version of XHTML
* </p>
*/
public XhtmlDt getDiv() {
if (myDiv == null) {
myDiv = new XhtmlDt();
}
return myDiv;
}
/**
* Sets the value(s) for <b>div</b> (Limited xhtml content)
*
* <p>
* <b>Definition:</b>
* The actual narrative content, a stripped down version of XHTML
* </p>
*/
public void setDiv(XhtmlDt theValue) {
myDiv = theValue;
}
/**
* Sets the value using a textual DIV (or simple text block which will be
* converted to XHTML)
*/
public void setDiv(String theTextDiv) {
myDiv = new XhtmlDt(theTextDiv);
}
}

View File

@ -0,0 +1,256 @@
package ca.uhn.fhir.model.dstu21.composite;
/*
* #%L
* HAPI FHIR Structures - DSTU2 (FHIR v1.0.0)
* %%
* Copyright (C) 2014 - 2015 University Health Network
* %%
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* #L%
*/
import java.util.List;
import org.hl7.fhir.instance.model.api.IIdType;
import ca.uhn.fhir.model.api.ICompositeDatatype;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.DatatypeDef;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.SimpleSetter;
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
import ca.uhn.fhir.model.primitive.IdDt;
import ca.uhn.fhir.model.primitive.StringDt;
/**
* HAPI/FHIR <b>ResourceReferenceDt</b> Datatype
* (A reference from one resource to another)
*
* <p>
* <b>Definition:</b>
* A reference from one resource to another
* </p>
*
* <p>
* <b>Requirements:</b>
*
* </p>
*/
@DatatypeDef(name="ResourceReferenceDt")
public class ResourceReferenceDt
extends BaseResourceReferenceDt implements ICompositeDatatype
{
/**
* Constructor
*/
public ResourceReferenceDt() {
// nothing
}
/**
* Constructor which creates a resource reference containing the actual resource in question.
* <p>
* <b> When using this in a server:</b> Generally if this is serialized, it will be serialized as a contained
* resource, so this should not be used if the intent is not to actually supply the referenced resource. This is not
* a hard-and-fast rule however, as the server can be configured to not serialized this resource, or to load an ID
* and contain even if this constructor is not used.
* </p>
*
* @param theResource
* The resource instance
*/
@SimpleSetter()
public ResourceReferenceDt(IResource theResource) {
super(theResource);
}
/**
* Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute
* URL)
*
* @param theId
* The reference itself
*/
public ResourceReferenceDt(String theId) {
setReference(new IdDt(theId));
}
/**
* Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute
* URL)
*
* @param theResourceId
* The reference itself
*/
public ResourceReferenceDt(IdDt theResourceId) {
setReference(theResourceId);
}
/**
* Constructor which accepts a reference directly (this can be an ID, a partial/relative URL or a complete/absolute
* URL)
*
* @param theResourceId
* The reference itself
*/
public ResourceReferenceDt(IIdType theResourceId) {
setReference(theResourceId);
}
@Child(name="reference", type=IdDt.class, order=0, min=0, max=1)
@Description(
shortDefinition="Relative, internal or absolute URL reference",
formalDefinition="A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources"
)
private IdDt myReference;
@Child(name="display", type=StringDt.class, order=1, min=0, max=1)
@Description(
shortDefinition="Text alternative for the resource",
formalDefinition="Plain text narrative that identifies the resource in addition to the resource reference"
)
private StringDt myDisplay;
@Override
public boolean isEmpty() {
return super.isBaseEmpty() && ca.uhn.fhir.util.ElementUtil.isEmpty( myReference, myDisplay);
}
@Override
public <T extends IElement> List<T> getAllPopulatedChildElementsOfType(Class<T> theType) {
return ca.uhn.fhir.util.ElementUtil.allPopulatedChildElements(theType, myReference, myDisplay);
}
/**
* Gets the value(s) for <b>reference</b> (Relative, internal or absolute URL reference).
* creating it if it does
* not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b>
* A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources
* </p>
*/
public IdDt getReference() {
if (myReference == null) {
myReference = new IdDt();
}
return myReference;
}
@Override
public IdDt getReferenceElement() {
return getReference();
}
/**
* Sets the value(s) for <b>reference</b> (Relative, internal or absolute URL reference)
*
* <p>
* <b>Definition:</b>
* A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources
* </p>
*/
public ResourceReferenceDt setReference(IdDt theValue) {
myReference = theValue;
return this;
}
/**
* Sets the value for <b>reference</b> (Relative, internal or absolute URL reference)
*
* <p>
* <b>Definition:</b>
* A reference to a location at which the other resource is found. The reference may a relative reference, in which case it is relative to the service base URL, or an absolute URL that resolves to the location where the resource is found. The reference may be version specific or not. If the reference is not to a FHIR RESTful server, then it should be assumed to be version specific. Internal fragment references (start with '#') refer to contained resources
* </p>
*/
public ResourceReferenceDt setReference( String theId) {
myReference = new IdDt(theId);
return this;
}
/**
* Gets the value(s) for <b>display</b> (Text alternative for the resource).
* creating it if it does
* not exist. Will not return <code>null</code>.
*
* <p>
* <b>Definition:</b>
* Plain text narrative that identifies the resource in addition to the resource reference
* </p>
*/
public StringDt getDisplay() {
if (myDisplay == null) {
myDisplay = new StringDt();
}
return myDisplay;
}
/**
* Sets the value(s) for <b>display</b> (Text alternative for the resource)
*
* <p>
* <b>Definition:</b>
* Plain text narrative that identifies the resource in addition to the resource reference
* </p>
*/
public ResourceReferenceDt setDisplay(StringDt theValue) {
myDisplay = theValue;
return this;
}
/**
* Sets the value for <b>display</b> (Text alternative for the resource)
*
* <p>
* <b>Definition:</b>
* Plain text narrative that identifies the resource in addition to the resource reference
* </p>
*/
public ResourceReferenceDt setDisplay( String theString) {
myDisplay = new StringDt(theString);
return this;
}
@Override
public StringDt getDisplayElement() {
return getDisplay();
}
}

Some files were not shown because too many files have changed in this diff Show More