Merge remote-tracking branch 'remotes/origin/master' into ks-subscription-delivery-queue-configurable-name
This commit is contained in:
commit
a9f83a8c43
|
@ -25,8 +25,9 @@ public class IncludesExamples {
|
||||||
FhirContext ctx = FhirContext.forDstu2();
|
FhirContext ctx = FhirContext.forDstu2();
|
||||||
|
|
||||||
Dstu2BundleFactory bf = new Dstu2BundleFactory(ctx);
|
Dstu2BundleFactory bf = new Dstu2BundleFactory(ctx);
|
||||||
bf.initializeBundleFromResourceList(null, resources, "http://example.com/base", "http://example.com/base/Patient", 1, BundleTypeEnum.SEARCHSET);
|
bf.addRootPropertiesToBundle(null, null, null, null, null, resources.size(), BundleTypeEnum.SEARCHSET, null);
|
||||||
IBaseResource b = bf.getResourceBundle();
|
bf.addResourcesToBundle(new ArrayList<>(resources), BundleTypeEnum.SEARCHSET, null, null, null);
|
||||||
|
IBaseResource b = bf.getResourceBundle();
|
||||||
|
|
||||||
// Encode the bundle
|
// Encode the bundle
|
||||||
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
|
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
|
||||||
|
|
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IAnyResource;
|
import org.hl7.fhir.instance.model.api.IAnyResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
|
@ -237,6 +237,10 @@ public class Constants {
|
||||||
public static final int STATUS_HTTP_202_ACCEPTED = 202;
|
public static final int STATUS_HTTP_202_ACCEPTED = 202;
|
||||||
public static final String HEADER_X_PROGRESS = "X-Progress";
|
public static final String HEADER_X_PROGRESS = "X-Progress";
|
||||||
public static final String HEADER_RETRY_AFTER = "Retry-After";
|
public static final String HEADER_RETRY_AFTER = "Retry-After";
|
||||||
|
/**
|
||||||
|
* Operation name for the $lastn operation
|
||||||
|
*/
|
||||||
|
public static final String OPERATION_LASTN = "$lastn";
|
||||||
|
|
||||||
static {
|
static {
|
||||||
CHARSET_UTF8 = StandardCharsets.UTF_8;
|
CHARSET_UTF8 = StandardCharsets.UTF_8;
|
||||||
|
|
|
@ -19,14 +19,17 @@ package ca.uhn.fhir.rest.api;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This interface should be considered experimental and will likely change in future releases of HAPI. Use with caution!
|
* This interface should be considered experimental and will likely change in future releases of HAPI. Use with caution!
|
||||||
|
@ -39,7 +42,15 @@ public interface IVersionSpecificBundleFactory {
|
||||||
|
|
||||||
IBaseResource getResourceBundle();
|
IBaseResource getResourceBundle();
|
||||||
|
|
||||||
void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType);
|
/**
|
||||||
|
* @deprecated This was deprecated in HAPI FHIR 4.1.0 as it provides duplicate functionality to the {@link #addRootPropertiesToBundle(String, String, String, String, String, Integer, BundleTypeEnum, IPrimitiveType)}
|
||||||
|
* and {@link #addResourcesToBundle(List, BundleTypeEnum, String, BundleInclusionRule, Set)} methods
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
default void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResult, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType) {
|
||||||
|
addRootPropertiesToBundle(null, null, null, null, null, theResult.size(), theBundleType, null);
|
||||||
|
addResourcesToBundle(new ArrayList<>(theResult), theBundleType, null, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
void initializeWithBundleResource(IBaseResource theResource);
|
void initializeWithBundleResource(IBaseResource theResource);
|
||||||
|
|
||||||
|
|
|
@ -46,12 +46,14 @@ public class BundleUtil {
|
||||||
private final RequestTypeEnum myRequestType;
|
private final RequestTypeEnum myRequestType;
|
||||||
private final IBaseResource myResource;
|
private final IBaseResource myResource;
|
||||||
private final String myUrl;
|
private final String myUrl;
|
||||||
|
private final String myConditionalUrl;
|
||||||
|
|
||||||
BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource) {
|
BundleEntryParts(RequestTypeEnum theRequestType, String theUrl, IBaseResource theResource, String theConditionalUrl) {
|
||||||
super();
|
super();
|
||||||
myRequestType = theRequestType;
|
myRequestType = theRequestType;
|
||||||
myUrl = theUrl;
|
myUrl = theUrl;
|
||||||
myResource = theResource;
|
myResource = theResource;
|
||||||
|
myConditionalUrl = theConditionalUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
public RequestTypeEnum getRequestType() {
|
public RequestTypeEnum getRequestType() {
|
||||||
|
@ -62,6 +64,10 @@ public class BundleUtil {
|
||||||
return myResource;
|
return myResource;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getConditionalUrl() {
|
||||||
|
return myConditionalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public String getUrl() {
|
public String getUrl() {
|
||||||
return myUrl;
|
return myUrl;
|
||||||
}
|
}
|
||||||
|
@ -190,19 +196,21 @@ public class BundleUtil {
|
||||||
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
||||||
BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
|
BaseRuntimeChildDefinition requestChild = entryChildElem.getChildByName("request");
|
||||||
BaseRuntimeElementCompositeDefinition<?> requestElem = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
|
BaseRuntimeElementCompositeDefinition<?> requestElem = (BaseRuntimeElementCompositeDefinition<?>) requestChild.getChildByName("request");
|
||||||
BaseRuntimeChildDefinition urlChild = requestElem.getChildByName("url");
|
BaseRuntimeChildDefinition requestUrlChild = requestElem.getChildByName("url");
|
||||||
|
BaseRuntimeChildDefinition requestIfNoneExistChild = requestElem.getChildByName("ifNoneExist");
|
||||||
BaseRuntimeChildDefinition methodChild = requestElem.getChildByName("method");
|
BaseRuntimeChildDefinition methodChild = requestElem.getChildByName("method");
|
||||||
|
|
||||||
for (IBase nextEntry : entries) {
|
for (IBase nextEntry : entries) {
|
||||||
IBaseResource resource = null;
|
IBaseResource resource = null;
|
||||||
String url = null;
|
String url = null;
|
||||||
RequestTypeEnum requestType = null;
|
RequestTypeEnum requestType = null;
|
||||||
|
String conditionalUrl = null;
|
||||||
|
|
||||||
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
||||||
resource = (IBaseResource) next;
|
resource = (IBaseResource) next;
|
||||||
}
|
}
|
||||||
for (IBase nextRequest : requestChild.getAccessor().getValues(nextEntry)) {
|
for (IBase nextRequest : requestChild.getAccessor().getValues(nextEntry)) {
|
||||||
for (IBase nextUrl : urlChild.getAccessor().getValues(nextRequest)) {
|
for (IBase nextUrl : requestUrlChild.getAccessor().getValues(nextRequest)) {
|
||||||
url = ((IPrimitiveType<?>) nextUrl).getValueAsString();
|
url = ((IPrimitiveType<?>) nextUrl).getValueAsString();
|
||||||
}
|
}
|
||||||
for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
|
for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
|
||||||
|
@ -211,13 +219,29 @@ public class BundleUtil {
|
||||||
requestType = RequestTypeEnum.valueOf(methodString);
|
requestType = RequestTypeEnum.valueOf(methodString);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestType != null) {
|
||||||
|
//noinspection EnumSwitchStatementWhichMissesCases
|
||||||
|
switch (requestType) {
|
||||||
|
case PUT:
|
||||||
|
conditionalUrl = url != null && url.contains("?") ? url : null;
|
||||||
|
break;
|
||||||
|
case POST:
|
||||||
|
List<IBase> ifNoneExistReps = requestIfNoneExistChild.getAccessor().getValues(nextRequest);
|
||||||
|
if (ifNoneExistReps.size() > 0) {
|
||||||
|
IPrimitiveType<?> ifNoneExist = (IPrimitiveType<?>) ifNoneExistReps.get(0);
|
||||||
|
conditionalUrl = ifNoneExist.getValueAsString();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* All 3 might be null - That's ok because we still want to know the
|
* All 3 might be null - That's ok because we still want to know the
|
||||||
* order in the original bundle.
|
* order in the original bundle.
|
||||||
*/
|
*/
|
||||||
retVal.add(new BundleEntryParts(requestType, url, resource));
|
retVal.add(new BundleEntryParts(requestType, url, resource, conditionalUrl));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -715,7 +715,8 @@ public class ExampleDataUploader extends BaseCommand {
|
||||||
ourLog.info("About to upload {} examples in a transaction, {} remaining", subResourceList.size(), resources.size());
|
ourLog.info("About to upload {} examples in a transaction, {} remaining", subResourceList.size(), resources.size());
|
||||||
|
|
||||||
IVersionSpecificBundleFactory bundleFactory = ctx.newBundleFactory();
|
IVersionSpecificBundleFactory bundleFactory = ctx.newBundleFactory();
|
||||||
bundleFactory.initializeBundleFromResourceList(null, subResourceList, null, null, 0, BundleTypeEnum.TRANSACTION);
|
bundleFactory.addRootPropertiesToBundle(null, null, null, null, null, subResourceList.size(), BundleTypeEnum.TRANSACTION, null);
|
||||||
|
bundleFactory.addResourcesToBundle(new ArrayList<>(subResourceList), BundleTypeEnum.TRANSACTION, null, null, null);
|
||||||
IBaseResource subBundle = bundleFactory.getResourceBundle();
|
IBaseResource subBundle = bundleFactory.getResourceBundle();
|
||||||
|
|
||||||
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(subBundle);
|
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(subBundle);
|
||||||
|
|
|
@ -1540,53 +1540,6 @@ public class GenericOkHttpClientDstu2Test {
|
||||||
assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass());
|
assertEquals(Patient.class, response.getEntry().get(0).getResource().getClass());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testTransactionWithListOfResources() throws Exception {
|
|
||||||
ca.uhn.fhir.model.dstu2.resource.Bundle resp = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
|
||||||
resp.addEntry().getResponse().setLocation("Patient/1/_history/1");
|
|
||||||
resp.addEntry().getResponse().setLocation("Patient/2/_history/2");
|
|
||||||
String respString = ourCtx.newJsonParser().encodeResourceToString(resp);
|
|
||||||
|
|
||||||
ourResponseContentType = Constants.CT_FHIR_JSON + "; charset=UTF-8";
|
|
||||||
ourResponseBody = respString;
|
|
||||||
|
|
||||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://localhost:" + ourPort + "/fhir");
|
|
||||||
|
|
||||||
List<IBaseResource> input = new ArrayList<IBaseResource>();
|
|
||||||
|
|
||||||
Patient p1 = new Patient(); // No ID
|
|
||||||
p1.addName().addFamily("PATIENT1");
|
|
||||||
input.add(p1);
|
|
||||||
|
|
||||||
Patient p2 = new Patient(); // Yes ID
|
|
||||||
p2.addName().addFamily("PATIENT2");
|
|
||||||
p2.setId("Patient/2");
|
|
||||||
input.add(p2);
|
|
||||||
|
|
||||||
List<IBaseResource> response = client.transaction()
|
|
||||||
.withResources(input)
|
|
||||||
.encodedJson()
|
|
||||||
.execute();
|
|
||||||
|
|
||||||
assertEquals("http://localhost:" + ourPort + "/fhir", ourRequestUri);
|
|
||||||
assertEquals(2, response.size());
|
|
||||||
|
|
||||||
String requestString = ourRequestBodyString;
|
|
||||||
ca.uhn.fhir.model.dstu2.resource.Bundle requestBundle = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, requestString);
|
|
||||||
assertEquals(2, requestBundle.getEntry().size());
|
|
||||||
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod());
|
|
||||||
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod());
|
|
||||||
assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl());
|
|
||||||
|
|
||||||
p1 = (Patient) response.get(0);
|
|
||||||
assertEquals(new IdDt("Patient/1/_history/1"), p1.getId().toUnqualified());
|
|
||||||
// assertEquals("PATIENT1", p1.getName().get(0).getFamily().get(0).getValue());
|
|
||||||
|
|
||||||
p2 = (Patient) response.get(1);
|
|
||||||
assertEquals(new IdDt("Patient/2/_history/2"), p2.getId().toUnqualified());
|
|
||||||
// assertEquals("PATIENT2", p2.getName().get(0).getFamily().get(0).getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testTransactionWithString() throws Exception {
|
public void testTransactionWithString() throws Exception {
|
||||||
ca.uhn.fhir.model.dstu2.resource.Bundle req = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
ca.uhn.fhir.model.dstu2.resource.Bundle req = new ca.uhn.fhir.model.dstu2.resource.Bundle();
|
||||||
|
|
|
@ -22,11 +22,14 @@ package ca.uhn.fhir.rest.client.impl;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.*;
|
import ca.uhn.fhir.context.*;
|
||||||
import ca.uhn.fhir.model.api.IQueryParameterType;
|
import ca.uhn.fhir.model.api.IQueryParameterType;
|
||||||
|
import ca.uhn.fhir.model.api.IResource;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.model.primitive.UriDt;
|
import ca.uhn.fhir.model.primitive.UriDt;
|
||||||
|
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||||
import ca.uhn.fhir.parser.DataFormatException;
|
import ca.uhn.fhir.parser.DataFormatException;
|
||||||
import ca.uhn.fhir.parser.IParser;
|
import ca.uhn.fhir.parser.IParser;
|
||||||
import ca.uhn.fhir.rest.api.*;
|
import ca.uhn.fhir.rest.api.*;
|
||||||
|
@ -2046,7 +2049,35 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
||||||
@Override
|
@Override
|
||||||
public ITransactionTyped<List<IBaseResource>> withResources(List<? extends IBaseResource> theResources) {
|
public ITransactionTyped<List<IBaseResource>> withResources(List<? extends IBaseResource> theResources) {
|
||||||
Validate.notNull(theResources, "theResources must not be null");
|
Validate.notNull(theResources, "theResources must not be null");
|
||||||
return new TransactionExecutable<List<IBaseResource>>(theResources);
|
|
||||||
|
for (IBaseResource next : theResources) {
|
||||||
|
String entryMethod = null;
|
||||||
|
if (next instanceof IResource) {
|
||||||
|
BundleEntryTransactionMethodEnum entryMethodEnum = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IResource) next);
|
||||||
|
if (entryMethodEnum != null) {
|
||||||
|
entryMethod = entryMethodEnum.getCode();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
entryMethod = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get((IAnyResource) next);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isBlank(entryMethod)) {
|
||||||
|
if (isBlank(next.getIdElement().getValue())) {
|
||||||
|
entryMethod = "POST";
|
||||||
|
} else {
|
||||||
|
entryMethod = "PUT";
|
||||||
|
}
|
||||||
|
if (next instanceof IResource) {
|
||||||
|
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put((IResource) next, BundleEntryTransactionMethodEnum.valueOf(entryMethod));
|
||||||
|
} else {
|
||||||
|
ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.put((IAnyResource) next, entryMethod);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return new TransactionExecutable<>(theResources);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
@ -52,7 +53,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
||||||
private boolean myOmitResourceId = false;
|
private boolean myOmitResourceId = false;
|
||||||
private Map<String, List<String>> myParams;
|
private Map<String, List<String>> myParams;
|
||||||
private final IBaseResource myResource;
|
private final IBaseResource myResource;
|
||||||
private final List<? extends IBaseResource> myResources;
|
private final List<IBaseResource> myResources;
|
||||||
private final String myUrlPath;
|
private final String myUrlPath;
|
||||||
private IIdType myForceResourceId;
|
private IIdType myForceResourceId;
|
||||||
|
|
||||||
|
@ -70,7 +71,7 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
||||||
super(theContext);
|
super(theContext);
|
||||||
myResource = null;
|
myResource = null;
|
||||||
myUrlPath = null;
|
myUrlPath = null;
|
||||||
myResources = theResources;
|
myResources = new ArrayList<>(theResources);
|
||||||
myContents = null;
|
myContents = null;
|
||||||
myBundleType = theBundleType;
|
myBundleType = theBundleType;
|
||||||
}
|
}
|
||||||
|
@ -172,11 +173,8 @@ abstract class BaseHttpClientInvocationWithContents extends BaseHttpClientInvoca
|
||||||
parser.setOmitResourceId(myOmitResourceId);
|
parser.setOmitResourceId(myOmitResourceId);
|
||||||
if (myResources != null) {
|
if (myResources != null) {
|
||||||
IVersionSpecificBundleFactory bundleFactory = getContext().newBundleFactory();
|
IVersionSpecificBundleFactory bundleFactory = getContext().newBundleFactory();
|
||||||
bundleFactory.initializeBundleFromResourceList("", myResources, "", "", myResources.size(), myBundleType);
|
bundleFactory.addRootPropertiesToBundle(null, null, null, null, null, myResources.size(), myBundleType, null);
|
||||||
IBaseResource bundle = bundleFactory.getResourceBundle();
|
bundleFactory.addResourcesToBundle(myResources, myBundleType, null, null, null);
|
||||||
if (bundle != null) {
|
|
||||||
return parser.encodeResourceToString(bundle);
|
|
||||||
}
|
|
||||||
IBaseResource bundleRes = bundleFactory.getResourceBundle();
|
IBaseResource bundleRes = bundleFactory.getResourceBundle();
|
||||||
return parser.encodeResourceToString(bundleRes);
|
return parser.encodeResourceToString(bundleRes);
|
||||||
} else if (myContents != null) {
|
} else if (myContents != null) {
|
||||||
|
|
|
@ -44,8 +44,9 @@ public class IncludesExamples {
|
||||||
FhirContext ctx = FhirContext.forDstu2();
|
FhirContext ctx = FhirContext.forDstu2();
|
||||||
|
|
||||||
R4BundleFactory bf = new R4BundleFactory(ctx);
|
R4BundleFactory bf = new R4BundleFactory(ctx);
|
||||||
bf.initializeBundleFromResourceList(null, resources, "http://example.com/base", "http://example.com/base/Patient", 1, BundleTypeEnum.SEARCHSET);
|
bf.addRootPropertiesToBundle(null, null, null, null, null, resources.size(), BundleTypeEnum.SEARCHSET, null);
|
||||||
IBaseResource b = bf.getResourceBundle();
|
bf.addResourcesToBundle(new ArrayList<>(resources), BundleTypeEnum.SEARCHSET, null, null, null);
|
||||||
|
IBaseResource b = bf.getResourceBundle();
|
||||||
|
|
||||||
// Encode the bundle
|
// Encode the bundle
|
||||||
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
|
String encoded = ctx.newXmlParser().setPrettyPrint(true).encodeResourceToString(b);
|
||||||
|
|
|
@ -1722,7 +1722,7 @@ public class GenericJaxRsClientDstu2Test {
|
||||||
|
|
||||||
Patient p2 = new Patient(); // Yes ID
|
Patient p2 = new Patient(); // Yes ID
|
||||||
p2.addName().addFamily("PATIENT2");
|
p2.addName().addFamily("PATIENT2");
|
||||||
p2.setId("Patient/2");
|
p2.setId("http://example.com/Patient/2");
|
||||||
input.add(p2);
|
input.add(p2);
|
||||||
|
|
||||||
|
|
||||||
|
@ -1740,7 +1740,7 @@ public class GenericJaxRsClientDstu2Test {
|
||||||
assertEquals(2, requestBundle.getEntry().size());
|
assertEquals(2, requestBundle.getEntry().size());
|
||||||
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod());
|
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod());
|
||||||
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod());
|
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod());
|
||||||
assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl());
|
assertEquals("http://example.com/Patient/2", requestBundle.getEntry().get(1).getFullUrl());
|
||||||
|
|
||||||
p1 = (Patient) response.get(0);
|
p1 = (Patient) response.get(0);
|
||||||
assertEquals(new IdDt("Patient/1/_history/1"), p1.getId().toUnqualified());
|
assertEquals(new IdDt("Patient/1/_history/1"), p1.getId().toUnqualified());
|
||||||
|
|
|
@ -1758,7 +1758,7 @@ public class GenericJaxRsClientDstu3Test {
|
||||||
|
|
||||||
Patient p2 = new Patient(); // Yes ID
|
Patient p2 = new Patient(); // Yes ID
|
||||||
p2.addName().setFamily("PATIENT2");
|
p2.addName().setFamily("PATIENT2");
|
||||||
p2.setId("Patient/2");
|
p2.setId("http://example.com/Patient/2");
|
||||||
input.add(p2);
|
input.add(p2);
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
@ -1776,7 +1776,7 @@ public class GenericJaxRsClientDstu3Test {
|
||||||
assertEquals(2, requestBundle.getEntry().size());
|
assertEquals(2, requestBundle.getEntry().size());
|
||||||
assertEquals(HTTPVerb.POST, requestBundle.getEntry().get(0).getRequest().getMethod());
|
assertEquals(HTTPVerb.POST, requestBundle.getEntry().get(0).getRequest().getMethod());
|
||||||
assertEquals(HTTPVerb.PUT, requestBundle.getEntry().get(1).getRequest().getMethod());
|
assertEquals(HTTPVerb.PUT, requestBundle.getEntry().get(1).getRequest().getMethod());
|
||||||
assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl());
|
assertEquals("http://example.com/Patient/2", requestBundle.getEntry().get(1).getFullUrl());
|
||||||
|
|
||||||
p1 = (Patient) response.get(0);
|
p1 = (Patient) response.get(0);
|
||||||
assertEquals(new IdType("Patient/1/_history/1"), p1.getIdElement());
|
assertEquals(new IdType("Patient/1/_history/1"), p1.getIdElement());
|
||||||
|
|
|
@ -483,6 +483,8 @@
|
||||||
<groupId>org.glassfish</groupId>
|
<groupId>org.glassfish</groupId>
|
||||||
<artifactId>javax.el</artifactId>
|
<artifactId>javax.el</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Hibernate Search -->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.hibernate</groupId>
|
<groupId>org.hibernate</groupId>
|
||||||
<artifactId>hibernate-search-orm</artifactId>
|
<artifactId>hibernate-search-orm</artifactId>
|
||||||
|
@ -495,6 +497,10 @@
|
||||||
<groupId>org.apache.lucene</groupId>
|
<groupId>org.apache.lucene</groupId>
|
||||||
<artifactId>lucene-analyzers-phonetic</artifactId>
|
<artifactId>lucene-analyzers-phonetic</artifactId>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.hibernate</groupId>
|
||||||
|
<artifactId>hibernate-search-elasticsearch</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Misc -->
|
<!-- Misc -->
|
||||||
<dependency>
|
<dependency>
|
||||||
|
@ -568,6 +574,11 @@
|
||||||
<artifactId>greenmail-spring</artifactId>
|
<artifactId>greenmail-spring</artifactId>
|
||||||
<scope>test</scope>
|
<scope>test</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>pl.allegro.tech</groupId>
|
||||||
|
<artifactId>embedded-elasticsearch</artifactId>
|
||||||
|
<version>2.10.0</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||||
|
|
|
@ -9,7 +9,6 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||||
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
||||||
import ca.uhn.fhir.jpa.dao.dstu3.TransactionProcessorVersionAdapterDstu3;
|
import ca.uhn.fhir.jpa.dao.dstu3.TransactionProcessorVersionAdapterDstu3;
|
||||||
import ca.uhn.fhir.jpa.provider.GraphQLProvider;
|
import ca.uhn.fhir.jpa.provider.GraphQLProvider;
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.TerminologyUploaderProviderDstu3;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorDstu3;
|
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorDstu3;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryDstu3;
|
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryDstu3;
|
||||||
|
@ -21,6 +20,7 @@ import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainDstu3;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.hapi.validation.CachingValidationSupport;
|
import org.hl7.fhir.dstu3.hapi.validation.CachingValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.dstu3.hapi.validation.FhirInstanceValidator;
|
||||||
|
@ -99,6 +99,11 @@ public class BaseDstu3Config extends BaseConfig {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DefaultProfileValidationSupport defaultProfileValidationSupport() {
|
||||||
|
return new DefaultProfileValidationSupport();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JpaValidationSupportChainDstu3 jpaValidationSupportChain() {
|
public JpaValidationSupportChainDstu3 jpaValidationSupportChain() {
|
||||||
return new JpaValidationSupportChainDstu3();
|
return new JpaValidationSupportChainDstu3();
|
||||||
|
|
|
@ -8,7 +8,7 @@ import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||||
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
import ca.uhn.fhir.jpa.dao.TransactionProcessor;
|
||||||
import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4;
|
import ca.uhn.fhir.jpa.dao.r4.TransactionProcessorVersionAdapterR4;
|
||||||
import ca.uhn.fhir.jpa.graphql.JpaStorageServices;
|
import ca.uhn.fhir.jpa.provider.GraphQLProvider;
|
||||||
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
import ca.uhn.fhir.jpa.searchparam.extractor.SearchParamExtractorR4;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryR4;
|
import ca.uhn.fhir.jpa.searchparam.registry.SearchParamRegistryR4;
|
||||||
|
@ -20,14 +20,12 @@ import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR4;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
import ca.uhn.fhir.jpa.provider.GraphQLProvider;
|
|
||||||
import org.hl7.fhir.r4.hapi.validation.CachingValidationSupport;
|
import org.hl7.fhir.r4.hapi.validation.CachingValidationSupport;
|
||||||
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.r4.hapi.validation.FhirInstanceValidator;
|
||||||
import org.hl7.fhir.r4.model.Bundle;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.hl7.fhir.r4.utils.GraphQLEngine;
|
|
||||||
import org.hl7.fhir.r5.utils.IResourceValidator;
|
import org.hl7.fhir.r5.utils.IResourceValidator;
|
||||||
import org.hl7.fhir.utilities.graphql.IGraphQLStorageServices;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
import org.springframework.beans.factory.annotation.Autowire;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
@ -102,6 +100,11 @@ public class BaseR4Config extends BaseConfig {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DefaultProfileValidationSupport defaultProfileValidationSupport() {
|
||||||
|
return new DefaultProfileValidationSupport();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JpaValidationSupportChainR4 jpaValidationSupportChain() {
|
public JpaValidationSupportChainR4 jpaValidationSupportChain() {
|
||||||
return new JpaValidationSupportChainR4();
|
return new JpaValidationSupportChainR4();
|
||||||
|
|
|
@ -20,6 +20,7 @@ import ca.uhn.fhir.jpa.util.ResourceCountCache;
|
||||||
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR5;
|
import ca.uhn.fhir.jpa.validation.JpaValidationSupportChainR5;
|
||||||
import ca.uhn.fhir.validation.IValidatorModule;
|
import ca.uhn.fhir.validation.IValidatorModule;
|
||||||
import org.apache.commons.lang3.time.DateUtils;
|
import org.apache.commons.lang3.time.DateUtils;
|
||||||
|
import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.r5.hapi.validation.CachingValidationSupport;
|
import org.hl7.fhir.r5.hapi.validation.CachingValidationSupport;
|
||||||
import org.hl7.fhir.r5.hapi.validation.FhirInstanceValidator;
|
import org.hl7.fhir.r5.hapi.validation.FhirInstanceValidator;
|
||||||
|
@ -99,6 +100,11 @@ public class BaseR5Config extends BaseConfig {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public DefaultProfileValidationSupport defaultProfileValidationSupport() {
|
||||||
|
return new DefaultProfileValidationSupport();
|
||||||
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public JpaValidationSupportChainR5 jpaValidationSupportChain() {
|
public JpaValidationSupportChainR5 jpaValidationSupportChain() {
|
||||||
return new JpaValidationSupportChainR5();
|
return new JpaValidationSupportChainR5();
|
||||||
|
|
|
@ -112,7 +112,7 @@ import static org.apache.commons.lang3.StringUtils.*;
|
||||||
|
|
||||||
@SuppressWarnings("WeakerAccess")
|
@SuppressWarnings("WeakerAccess")
|
||||||
@Repository
|
@Repository
|
||||||
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao, ApplicationContextAware {
|
public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao, IJpaDao<T>, ApplicationContextAware {
|
||||||
|
|
||||||
public static final long INDEX_STATUS_INDEXED = 1L;
|
public static final long INDEX_STATUS_INDEXED = 1L;
|
||||||
public static final long INDEX_STATUS_INDEXING_FAILED = 2L;
|
public static final long INDEX_STATUS_INDEXING_FAILED = 2L;
|
||||||
|
@ -1017,7 +1017,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, final IBaseResource theResource, ResourceTable
|
@Override
|
||||||
|
public ResourceTable updateEntity(RequestDetails theRequest, final IBaseResource theResource, ResourceTable
|
||||||
theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
Validate.notNull(theEntity);
|
Validate.notNull(theEntity);
|
||||||
|
@ -1256,6 +1257,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> implements IDao,
|
||||||
return theEntity;
|
return theEntity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
public ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
||||||
ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) {
|
ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource) {
|
||||||
|
|
||||||
|
|
|
@ -149,21 +149,29 @@ public class DaoConfig {
|
||||||
private boolean myFilterParameterEnabled = false;
|
private boolean myFilterParameterEnabled = false;
|
||||||
private StoreMetaSourceInformationEnum myStoreMetaSourceInformation = StoreMetaSourceInformationEnum.SOURCE_URI_AND_REQUEST_ID;
|
private StoreMetaSourceInformationEnum myStoreMetaSourceInformation = StoreMetaSourceInformationEnum.SOURCE_URI_AND_REQUEST_ID;
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production! Do not change default of {@code false}!
|
* Do not change default of {@code true}!
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
private boolean myPreExpandValueSetsExperimental = false;
|
private boolean myPreExpandValueSets = true;
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production! Do not change default of {@code 0}!
|
* Do not change default of {@code 0}!
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
private int myPreExpandValueSetsDefaultOffsetExperimental = 0;
|
private int myPreExpandValueSetsDefaultOffset = 0;
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production! Do not change default of {@code 1000}!
|
* Do not change default of {@code 1000}!
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
private int myPreExpandValueSetsDefaultCountExperimental = 1000;
|
private int myPreExpandValueSetsDefaultCount = 1000;
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production! Do not change default of {@code 1000}!
|
* Do not change default of {@code 1000}!
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
private int myPreExpandValueSetsMaxCountExperimental = 1000;
|
private int myPreExpandValueSetsMaxCount = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -920,7 +928,7 @@ public class DaoConfig {
|
||||||
* <p>
|
* <p>
|
||||||
* Default is {@literal true} beginning in HAPI FHIR 2.4, since this
|
* Default is {@literal true} beginning in HAPI FHIR 2.4, since this
|
||||||
* feature is now specified in the FHIR specification. (Previously it
|
* feature is now specified in the FHIR specification. (Previously it
|
||||||
* was an experimental/rpposed feature)
|
* was an experimental/proposed feature)
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @since 1.5
|
* @since 1.5
|
||||||
|
@ -1621,34 +1629,6 @@ public class DaoConfig {
|
||||||
myModelConfig.setWebsocketContextPath(theWebsocketContextPath);
|
myModelConfig.setWebsocketContextPath(theWebsocketContextPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* EXPERIMENTAL - Do not use in production!
|
|
||||||
* <p>
|
|
||||||
* If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
|
|
||||||
* future optimization of the $expand operation on large ValueSets.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The default value for this setting is {@code false}.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public boolean isPreExpandValueSetsExperimental() {
|
|
||||||
return myPreExpandValueSetsExperimental;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* EXPERIMENTAL - Do not use in production!
|
|
||||||
* <p>
|
|
||||||
* If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
|
|
||||||
* future optimization of the $expand operation on large ValueSets.
|
|
||||||
* </p>
|
|
||||||
* <p>
|
|
||||||
* The default value for this setting is {@code false}.
|
|
||||||
* </p>
|
|
||||||
*/
|
|
||||||
public void setPreExpandValueSetsExperimental(boolean thePreExpandValueSetsExperimental) {
|
|
||||||
myPreExpandValueSetsExperimental = thePreExpandValueSetsExperimental;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If set to <code>true</code> the _filter search parameter will be enabled on this server. Note that _filter
|
* If set to <code>true</code> the _filter search parameter will be enabled on this server. Note that _filter
|
||||||
* is very powerful, but also potentially dangerous as it can allow a user to create a query for which there
|
* is very powerful, but also potentially dangerous as it can allow a user to create a query for which there
|
||||||
|
@ -1720,83 +1700,118 @@ public class DaoConfig {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production!
|
* <p>
|
||||||
|
* If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
|
||||||
|
* optimization of the $expand operation on large ValueSets.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The default value for this setting is {@code true}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*/
|
||||||
|
public boolean isPreExpandValueSets() {
|
||||||
|
return myPreExpandValueSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>
|
||||||
|
* If set to {@code true}, ValueSets and expansions are stored in terminology tables. This is to facilitate
|
||||||
|
* optimization of the $expand operation on large ValueSets.
|
||||||
|
* </p>
|
||||||
|
* <p>
|
||||||
|
* The default value for this setting is {@code true}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*/
|
||||||
|
public void setPreExpandValueSets(boolean thePreExpandValueSets) {
|
||||||
|
myPreExpandValueSets = thePreExpandValueSets;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
* This is the default value of {@code offset} parameter for the ValueSet {@code $expand} operation when
|
* This is the default value of {@code offset} parameter for the ValueSet {@code $expand} operation when
|
||||||
* {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}.
|
* {@link DaoConfig#isPreExpandValueSets()} returns {@code true}.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* The default value for this setting is {@code 0}.
|
* The default value for this setting is {@code 0}.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
public int getPreExpandValueSetsDefaultOffsetExperimental() {
|
public int getPreExpandValueSetsDefaultOffset() {
|
||||||
return myPreExpandValueSetsDefaultOffsetExperimental;
|
return myPreExpandValueSetsDefaultOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production!
|
|
||||||
* <p>
|
* <p>
|
||||||
* This is the default value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
* This is the default value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
||||||
* {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}.
|
* {@link DaoConfig#isPreExpandValueSets()} returns {@code true}.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* The default value for this setting is {@code 1000}.
|
* The default value for this setting is {@code 1000}.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
public int getPreExpandValueSetsDefaultCountExperimental() {
|
public int getPreExpandValueSetsDefaultCount() {
|
||||||
return myPreExpandValueSetsDefaultCountExperimental;
|
return myPreExpandValueSetsDefaultCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production!
|
|
||||||
* <p>
|
* <p>
|
||||||
* This is the default value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
* This is the default value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
||||||
* {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}.
|
* {@link DaoConfig#isPreExpandValueSets()} returns {@code true}.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* If {@code thePreExpandValueSetsDefaultCountExperimental} is greater than
|
* If {@code thePreExpandValueSetsDefaultCount} is greater than
|
||||||
* {@link DaoConfig#getPreExpandValueSetsMaxCountExperimental()}, the lesser value is used.
|
* {@link DaoConfig#getPreExpandValueSetsMaxCount()}, the lesser value is used.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* The default value for this setting is {@code 1000}.
|
* The default value for this setting is {@code 1000}.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
public void setPreExpandValueSetsDefaultCountExperimental(int thePreExpandValueSetsDefaultCountExperimental) {
|
public void setPreExpandValueSetsDefaultCount(int thePreExpandValueSetsDefaultCount) {
|
||||||
myPreExpandValueSetsDefaultCountExperimental = Math.min(thePreExpandValueSetsDefaultCountExperimental, getPreExpandValueSetsMaxCountExperimental());
|
myPreExpandValueSetsDefaultCount = Math.min(thePreExpandValueSetsDefaultCount, getPreExpandValueSetsMaxCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production!
|
|
||||||
* <p>
|
* <p>
|
||||||
* This is the max value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
* This is the max value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
||||||
* {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}.
|
* {@link DaoConfig#isPreExpandValueSets()} returns {@code true}.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* The default value for this setting is {@code 1000}.
|
* The default value for this setting is {@code 1000}.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
public int getPreExpandValueSetsMaxCountExperimental() {
|
public int getPreExpandValueSetsMaxCount() {
|
||||||
return myPreExpandValueSetsMaxCountExperimental;
|
return myPreExpandValueSetsMaxCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* EXPERIMENTAL - Do not use in production!
|
|
||||||
* <p>
|
* <p>
|
||||||
* This is the max value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
* This is the max value of {@code count} parameter for the ValueSet {@code $expand} operation when
|
||||||
* {@link DaoConfig#isPreExpandValueSetsExperimental()} returns {@code true}.
|
* {@link DaoConfig#isPreExpandValueSets()} returns {@code true}.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* If {@code thePreExpandValueSetsMaxCountExperimental} is lesser than
|
* If {@code thePreExpandValueSetsMaxCount} is lesser than
|
||||||
* {@link DaoConfig#getPreExpandValueSetsDefaultCountExperimental()}, the default {@code count} is lowered to the
|
* {@link DaoConfig#getPreExpandValueSetsDefaultCount()}, the default {@code count} is lowered to the
|
||||||
* new max {@code count}.
|
* new max {@code count}.
|
||||||
* </p>
|
* </p>
|
||||||
* <p>
|
* <p>
|
||||||
* The default value for this setting is {@code 1000}.
|
* The default value for this setting is {@code 1000}.
|
||||||
* </p>
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
*/
|
*/
|
||||||
public void setPreExpandValueSetsMaxCountExperimental(int thePreExpandValueSetsMaxCountExperimental) {
|
public void setPreExpandValueSetsMaxCount(int thePreExpandValueSetsMaxCount) {
|
||||||
myPreExpandValueSetsMaxCountExperimental = thePreExpandValueSetsMaxCountExperimental;
|
myPreExpandValueSetsMaxCount = thePreExpandValueSetsMaxCount;
|
||||||
setPreExpandValueSetsDefaultCountExperimental(Math.min(getPreExpandValueSetsDefaultCountExperimental(), getPreExpandValueSetsMaxCountExperimental()));
|
setPreExpandValueSetsDefaultCount(Math.min(getPreExpandValueSetsDefaultCount(), getPreExpandValueSetsMaxCount()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum IndexEnabledEnum {
|
public enum IndexEnabledEnum {
|
||||||
|
|
|
@ -73,8 +73,8 @@ public class FhirResourceDaoSubscriptionDstu2 extends FhirResourceDaoDstu2<Subsc
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (theDeletedTimestampOrNull != null) {
|
if (theDeletedTimestampOrNull != null) {
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
public interface IJpaDao<T extends IBaseResource> {
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable
|
||||||
|
theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry);
|
||||||
|
|
||||||
|
ResourceTable updateInternal(RequestDetails theRequestDetails, T theResource, boolean thePerformIndexing, boolean theForceUpdateVersion,
|
||||||
|
ResourceTable theEntity, IIdType theResourceId, IBaseResource theOldResource);
|
||||||
|
}
|
|
@ -42,14 +42,6 @@ public final class MetadataKeyCurrentlyReindexing extends ResourceMetadataKeySup
|
||||||
return (Boolean) theResource.getResourceMetadata().get(IDao.CURRENTLY_REINDEXING);
|
return (Boolean) theResource.getResourceMetadata().get(IDao.CURRENTLY_REINDEXING);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Boolean get(IBaseResource theResource) {
|
|
||||||
if (theResource instanceof IAnyResource) {
|
|
||||||
return get((IAnyResource) theResource);
|
|
||||||
} else {
|
|
||||||
return get((IResource) theResource);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void put(IAnyResource theResource, Boolean theObject) {
|
public void put(IAnyResource theResource, Boolean theObject) {
|
||||||
theResource.setUserData(IDao.CURRENTLY_REINDEXING.name(), theObject);
|
theResource.setUserData(IDao.CURRENTLY_REINDEXING.name(), theObject);
|
||||||
|
|
|
@ -909,10 +909,13 @@ public class TransactionProcessor<BUNDLE extends IBaseBundle, BUNDLEENTRY> {
|
||||||
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
IPrimitiveType<Date> deletedInstantOrNull = ResourceMetadataKeyEnum.DELETED_AT.get((IAnyResource) nextResource);
|
||||||
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
Date deletedTimestampOrNull = deletedInstantOrNull != null ? deletedInstantOrNull.getValue() : null;
|
||||||
|
|
||||||
|
IFhirResourceDao<? extends IBaseResource> dao = myDaoRegistry.getResourceDao(nextResource.getClass());
|
||||||
|
IJpaDao jpaDao = (IJpaDao) dao;
|
||||||
|
|
||||||
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
if (updatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
myDao.updateInternal(theRequest, nextResource, true, false, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
jpaDao.updateInternal(theRequest, nextResource, true, false, nextOutcome.getEntity(), nextResource.getIdElement(), nextOutcome.getPreviousResource());
|
||||||
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
} else if (!nonUpdatedEntities.contains(nextOutcome.getEntity())) {
|
||||||
myDao.updateEntity(theRequest, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
jpaDao.updateEntity(theRequest, nextResource, nextOutcome.getEntity(), deletedTimestampOrNull, true, false, theUpdateTime, false, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -125,8 +125,8 @@ public class FhirResourceDaoCodeSystemDstu3 extends FhirResourceDaoDstu3<CodeSys
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
CodeSystem csDstu3 = (CodeSystem) theResource;
|
CodeSystem csDstu3 = (CodeSystem) theResource;
|
||||||
|
|
|
@ -158,8 +158,8 @@ public class FhirResourceDaoConceptMapDstu3 extends FhirResourceDaoDstu3<Concept
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
|
|
|
@ -83,8 +83,8 @@ public class FhirResourceDaoSubscriptionDstu3 extends FhirResourceDaoDstu3<Subsc
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (theDeletedTimestampOrNull != null) {
|
if (theDeletedTimestampOrNull != null) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.util.ElementUtil;
|
import ca.uhn.fhir.util.ElementUtil;
|
||||||
import org.apache.commons.codec.binary.StringUtils;
|
import org.apache.commons.codec.binary.StringUtils;
|
||||||
import org.hl7.fhir.convertors.VersionConvertor_30_40;
|
import org.hl7.fhir.convertors.VersionConvertor_30_40;
|
||||||
|
import org.hl7.fhir.dstu3.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
|
import org.hl7.fhir.dstu3.hapi.ctx.HapiWorkerContext;
|
||||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.dstu3.model.*;
|
import org.hl7.fhir.dstu3.model.*;
|
||||||
|
@ -63,9 +64,13 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
||||||
@Autowired
|
@Autowired
|
||||||
private IHapiTerminologySvc myHapiTerminologySvc;
|
private IHapiTerminologySvc myHapiTerminologySvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myJpaValidationSupportChainDstu3")
|
@Qualifier("myJpaValidationSupportChainDstu3")
|
||||||
private IValidationSupport myValidationSupport;
|
private IValidationSupport myValidationSupport;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
|
private IFhirResourceDaoCodeSystem<CodeSystem, Coding, CodeableConcept> myCodeSystemDao;
|
||||||
|
|
||||||
|
@ -310,12 +315,18 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
||||||
|
|
||||||
boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false;
|
boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false;
|
||||||
ValueSet vs = null;
|
ValueSet vs = null;
|
||||||
|
boolean isBuiltInValueSet = false;
|
||||||
if (theId != null) {
|
if (theId != null) {
|
||||||
vs = read(theId, theRequestDetails);
|
vs = read(theId, theRequestDetails);
|
||||||
} else if (haveIdentifierParam) {
|
} else if (haveIdentifierParam) {
|
||||||
vs = myValidationSupport.fetchResource(getContext(), ValueSet.class, theValueSetIdentifier.getValue());
|
vs = myDefaultProfileValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue());
|
||||||
if (vs == null) {
|
if (vs == null) {
|
||||||
throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue());
|
vs = myValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue());
|
||||||
|
if (vs == null) {
|
||||||
|
throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isBuiltInValueSet = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (theCode == null || theCode.isEmpty()) {
|
if (theCode == null || theCode.isEmpty()) {
|
||||||
|
@ -332,7 +343,7 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
||||||
|
|
||||||
if (vs != null) {
|
if (vs != null) {
|
||||||
ValidateCodeResult result;
|
ValidateCodeResult result;
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
if (myDaoConfig.isPreExpandValueSets() && !isBuiltInValueSet && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
||||||
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
||||||
} else {
|
} else {
|
||||||
ValueSet expansion = doExpand(vs);
|
ValueSet expansion = doExpand(vs);
|
||||||
|
@ -395,11 +406,11 @@ public class FhirResourceDaoValueSetDstu3 extends FhirResourceDaoDstu3<ValueSet>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
if (myDaoConfig.isPreExpandValueSets()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
try {
|
try {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
|
|
|
@ -128,8 +128,8 @@ public class FhirResourceDaoCodeSystemR4 extends FhirResourceDaoR4<CodeSystem> i
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
CodeSystem cs = (CodeSystem) theResource;
|
CodeSystem cs = (CodeSystem) theResource;
|
||||||
|
|
|
@ -158,8 +158,8 @@ public class FhirResourceDaoConceptMapR4 extends FhirResourceDaoR4<ConceptMap> i
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
|
|
|
@ -75,8 +75,8 @@ public class FhirResourceDaoSubscriptionR4 extends FhirResourceDaoR4<Subscriptio
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (theDeletedTimestampOrNull != null) {
|
if (theDeletedTimestampOrNull != null) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.commons.codec.binary.StringUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
import org.hl7.fhir.r4.hapi.ctx.HapiWorkerContext;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
@ -57,6 +58,9 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
||||||
@Autowired
|
@Autowired
|
||||||
private IHapiTerminologySvc myHapiTerminologySvc;
|
private IHapiTerminologySvc myHapiTerminologySvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myJpaValidationSupportChainR4")
|
@Qualifier("myJpaValidationSupportChainR4")
|
||||||
private IValidationSupport myValidationSupport;
|
private IValidationSupport myValidationSupport;
|
||||||
|
@ -306,12 +310,18 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
||||||
|
|
||||||
boolean haveIdentifierParam = theValueSetIdentifier != null && !theValueSetIdentifier.isEmpty();
|
boolean haveIdentifierParam = theValueSetIdentifier != null && !theValueSetIdentifier.isEmpty();
|
||||||
ValueSet vs = null;
|
ValueSet vs = null;
|
||||||
|
boolean isBuiltInValueSet = false;
|
||||||
if (theId != null) {
|
if (theId != null) {
|
||||||
vs = read(theId, theRequestDetails);
|
vs = read(theId, theRequestDetails);
|
||||||
} else if (haveIdentifierParam) {
|
} else if (haveIdentifierParam) {
|
||||||
vs = myValidationSupport.fetchResource(getContext(), ValueSet.class, theValueSetIdentifier.getValue());
|
vs = myDefaultProfileValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue());
|
||||||
if (vs == null) {
|
if (vs == null) {
|
||||||
throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue());
|
vs = myValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue());
|
||||||
|
if (vs == null) {
|
||||||
|
throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isBuiltInValueSet = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (theCode == null || theCode.isEmpty()) {
|
if (theCode == null || theCode.isEmpty()) {
|
||||||
|
@ -328,7 +338,7 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
||||||
|
|
||||||
if (vs != null) {
|
if (vs != null) {
|
||||||
ValidateCodeResult result;
|
ValidateCodeResult result;
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
if (myDaoConfig.isPreExpandValueSets() && !isBuiltInValueSet && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
||||||
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
||||||
} else {
|
} else {
|
||||||
ValueSet expansion = doExpand(vs);
|
ValueSet expansion = doExpand(vs);
|
||||||
|
@ -391,11 +401,11 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
if (myDaoConfig.isPreExpandValueSets()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
myHapiTerminologySvc.storeTermValueSet(retVal, valueSet);
|
myHapiTerminologySvc.storeTermValueSet(retVal, valueSet);
|
||||||
|
@ -407,4 +417,5 @@ public class FhirResourceDaoValueSetR4 extends FhirResourceDaoR4<ValueSet> imple
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -128,8 +128,8 @@ public class FhirResourceDaoCodeSystemR5 extends FhirResourceDaoR5<CodeSystem> i
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
CodeSystem cs = (CodeSystem) theResource;
|
CodeSystem cs = (CodeSystem) theResource;
|
||||||
|
|
|
@ -157,7 +157,7 @@ public class FhirResourceDaoConceptMapR5 extends FhirResourceDaoR5<ConceptMap> i
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
|
|
|
@ -73,8 +73,8 @@ public class FhirResourceDaoSubscriptionR5 extends FhirResourceDaoR5<Subscriptio
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
public ResourceTable updateEntity(RequestDetails theRequest, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing, boolean theUpdateVersion,
|
||||||
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequest, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (theDeletedTimestampOrNull != null) {
|
if (theDeletedTimestampOrNull != null) {
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.apache.commons.codec.binary.StringUtils;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.hl7.fhir.r5.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
|
import org.hl7.fhir.r5.hapi.ctx.HapiWorkerContext;
|
||||||
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
import org.hl7.fhir.r5.hapi.ctx.IValidationSupport;
|
||||||
import org.hl7.fhir.r5.model.*;
|
import org.hl7.fhir.r5.model.*;
|
||||||
|
@ -57,6 +58,9 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5<ValueSet> imple
|
||||||
@Autowired
|
@Autowired
|
||||||
private IHapiTerminologySvc myHapiTerminologySvc;
|
private IHapiTerminologySvc myHapiTerminologySvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myJpaValidationSupportChainR5")
|
@Qualifier("myJpaValidationSupportChainR5")
|
||||||
private IValidationSupport myValidationSupport;
|
private IValidationSupport myValidationSupport;
|
||||||
|
@ -312,12 +316,18 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5<ValueSet> imple
|
||||||
|
|
||||||
boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false;
|
boolean haveIdentifierParam = theValueSetIdentifier != null && theValueSetIdentifier.isEmpty() == false;
|
||||||
ValueSet vs = null;
|
ValueSet vs = null;
|
||||||
|
boolean isBuiltInValueSet = false;
|
||||||
if (theId != null) {
|
if (theId != null) {
|
||||||
vs = read(theId, theRequestDetails);
|
vs = read(theId, theRequestDetails);
|
||||||
} else if (haveIdentifierParam) {
|
} else if (haveIdentifierParam) {
|
||||||
vs = myValidationSupport.fetchResource(getContext(), ValueSet.class, theValueSetIdentifier.getValue());
|
vs = myDefaultProfileValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue());
|
||||||
if (vs == null) {
|
if (vs == null) {
|
||||||
throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue());
|
vs = myValidationSupport.fetchValueSet(getContext(), theValueSetIdentifier.getValue());
|
||||||
|
if (vs == null) {
|
||||||
|
throw new InvalidRequestException("Unknown ValueSet identifier: " + theValueSetIdentifier.getValue());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
isBuiltInValueSet = true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (theCode == null || theCode.isEmpty()) {
|
if (theCode == null || theCode.isEmpty()) {
|
||||||
|
@ -334,7 +344,7 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5<ValueSet> imple
|
||||||
|
|
||||||
if (vs != null) {
|
if (vs != null) {
|
||||||
ValidateCodeResult result;
|
ValidateCodeResult result;
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental() && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
if (myDaoConfig.isPreExpandValueSets() && !isBuiltInValueSet && myTerminologySvc.isValueSetPreExpandedForCodeValidation(vs)) {
|
||||||
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
result = myTerminologySvc.validateCodeIsInPreExpandedValueSet(vs, toStringOrNull(theSystem), toStringOrNull(theCode), toStringOrNull(theDisplay), theCoding, theCodeableConcept);
|
||||||
} else {
|
} else {
|
||||||
ValueSet expansion = doExpand(vs);
|
ValueSet expansion = doExpand(vs);
|
||||||
|
@ -397,11 +407,11 @@ public class FhirResourceDaoValueSetR5 extends FhirResourceDaoR5<ValueSet> imple
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
public ResourceTable updateEntity(RequestDetails theRequestDetails, IBaseResource theResource, ResourceTable theEntity, Date theDeletedTimestampOrNull, boolean thePerformIndexing,
|
||||||
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
boolean theUpdateVersion, Date theUpdateTime, boolean theForceUpdate, boolean theCreateNewHistoryEntry) {
|
||||||
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
ResourceTable retVal = super.updateEntity(theRequestDetails, theResource, theEntity, theDeletedTimestampOrNull, thePerformIndexing, theUpdateVersion, theUpdateTime, theForceUpdate, theCreateNewHistoryEntry);
|
||||||
|
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
if (myDaoConfig.isPreExpandValueSets()) {
|
||||||
if (retVal.getDeleted() == null) {
|
if (retVal.getDeleted() == null) {
|
||||||
ValueSet valueSet = (ValueSet) theResource;
|
ValueSet valueSet = (ValueSet) theResource;
|
||||||
myHapiTerminologySvc.storeTermValueSet(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet));
|
myHapiTerminologySvc.storeTermValueSet(retVal, org.hl7.fhir.convertors.conv40_50.ValueSet.convertValueSet(valueSet));
|
||||||
|
|
|
@ -62,17 +62,13 @@ public class ResourceSearchView implements IBaseResourceEntity, Serializable {
|
||||||
@Id
|
@Id
|
||||||
@Column(name = "PID")
|
@Column(name = "PID")
|
||||||
private Long myId;
|
private Long myId;
|
||||||
|
|
||||||
@Column(name = "RES_ID")
|
@Column(name = "RES_ID")
|
||||||
private Long myResourceId;
|
private Long myResourceId;
|
||||||
|
|
||||||
@Column(name = "RES_TYPE", length = Constants.MAX_RESOURCE_NAME_LENGTH)
|
@Column(name = "RES_TYPE", length = Constants.MAX_RESOURCE_NAME_LENGTH)
|
||||||
private String myResourceType;
|
private String myResourceType;
|
||||||
|
|
||||||
@Column(name = "RES_VERSION")
|
@Column(name = "RES_VERSION")
|
||||||
@Enumerated(EnumType.STRING)
|
@Enumerated(EnumType.STRING)
|
||||||
private FhirVersionEnum myFhirVersion;
|
private FhirVersionEnum myFhirVersion;
|
||||||
|
|
||||||
@Column(name = "RES_VER")
|
@Column(name = "RES_VER")
|
||||||
private Long myResourceVersion;
|
private Long myResourceVersion;
|
||||||
@Column(name = "PROV_REQUEST_ID", length = Constants.REQUEST_ID_LENGTH)
|
@Column(name = "PROV_REQUEST_ID", length = Constants.REQUEST_ID_LENGTH)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import org.hibernate.validator.constraints.NotBlank;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import javax.persistence.*;
|
import javax.persistence.*;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.left;
|
import static org.apache.commons.lang3.StringUtils.left;
|
||||||
import static org.apache.commons.lang3.StringUtils.length;
|
import static org.apache.commons.lang3.StringUtils.length;
|
||||||
|
@ -62,9 +63,11 @@ public class TermConceptProperty implements Serializable {
|
||||||
@Column(name = "PROP_KEY", nullable = false, length = MAX_LENGTH)
|
@Column(name = "PROP_KEY", nullable = false, length = MAX_LENGTH)
|
||||||
@NotBlank
|
@NotBlank
|
||||||
private String myKey;
|
private String myKey;
|
||||||
// FIXME: DM 2019-09-13 - We presently truncate down to 500. The longest value for EXTERNAL_COPYRIGHT_NOTICE is 2,597 so we should use a LOB instead of a String.
|
|
||||||
@Column(name = "PROP_VAL", nullable = true, length = MAX_LENGTH)
|
@Column(name = "PROP_VAL", nullable = true, length = MAX_LENGTH)
|
||||||
private String myValue;
|
private String myValue;
|
||||||
|
@Column(name = "PROP_VAL_LOB")
|
||||||
|
@Lob()
|
||||||
|
private byte[] myValueLob;
|
||||||
@Column(name = "PROP_TYPE", nullable = false, length = MAX_PROPTYPE_ENUM_LENGTH)
|
@Column(name = "PROP_TYPE", nullable = false, length = MAX_PROPTYPE_ENUM_LENGTH)
|
||||||
private TermConceptPropertyTypeEnum myType;
|
private TermConceptPropertyTypeEnum myType;
|
||||||
|
|
||||||
|
@ -145,6 +148,9 @@ public class TermConceptProperty implements Serializable {
|
||||||
* property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
|
* property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
|
||||||
*/
|
*/
|
||||||
public String getValue() {
|
public String getValue() {
|
||||||
|
if (hasValueLob()) {
|
||||||
|
return getValueLobAsString();
|
||||||
|
}
|
||||||
return myValue;
|
return myValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,10 +159,40 @@ public class TermConceptProperty implements Serializable {
|
||||||
* property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
|
* property, and the code for a {@link TermConceptPropertyTypeEnum#CODING coding} property.
|
||||||
*/
|
*/
|
||||||
public TermConceptProperty setValue(String theValue) {
|
public TermConceptProperty setValue(String theValue) {
|
||||||
|
if (theValue.length() > MAX_LENGTH) {
|
||||||
|
setValueLob(theValue);
|
||||||
|
} else {
|
||||||
|
myValueLob = null;
|
||||||
|
}
|
||||||
myValue = left(theValue, MAX_LENGTH);
|
myValue = left(theValue, MAX_LENGTH);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean hasValueLob() {
|
||||||
|
if (myValueLob != null && myValueLob.length > 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public byte[] getValueLob() {
|
||||||
|
return myValueLob;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValueLobAsString() {
|
||||||
|
return new String(myValueLob, StandardCharsets.UTF_8);
|
||||||
|
}
|
||||||
|
|
||||||
|
public TermConceptProperty setValueLob(byte[] theValueLob) {
|
||||||
|
myValueLob = theValueLob;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TermConceptProperty setValueLob(String theValueLob) {
|
||||||
|
myValueLob = theValueLob.getBytes(StandardCharsets.UTF_8);
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public TermConceptProperty setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
|
public TermConceptProperty setCodeSystemVersion(TermCodeSystemVersion theCodeSystemVersion) {
|
||||||
myCodeSystemVersion = theCodeSystemVersion;
|
myCodeSystemVersion = theCodeSystemVersion;
|
||||||
return this;
|
return this;
|
||||||
|
@ -171,7 +207,7 @@ public class TermConceptProperty implements Serializable {
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
|
||||||
.append("key", myKey)
|
.append("key", myKey)
|
||||||
.append("value", myValue)
|
.append("value", getValue())
|
||||||
.toString();
|
.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
|
||||||
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.");
|
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have an identifier specified, or have a ValueSet specified. Can not combine these options.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental();
|
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffset();
|
||||||
if (theOffset != null && theOffset.hasValue()) {
|
if (theOffset != null && theOffset.hasValue()) {
|
||||||
if (theOffset.getValue() >= 0) {
|
if (theOffset.getValue() >= 0) {
|
||||||
offset = theOffset.getValue();
|
offset = theOffset.getValue();
|
||||||
|
@ -77,7 +77,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = myDaoConfig.getPreExpandValueSetsDefaultCountExperimental();
|
int count = myDaoConfig.getPreExpandValueSetsDefaultCount();
|
||||||
if (theCount != null && theCount.hasValue()) {
|
if (theCount != null && theCount.hasValue()) {
|
||||||
if (theCount.getValue() >= 0) {
|
if (theCount.getValue() >= 0) {
|
||||||
count = theCount.getValue();
|
count = theCount.getValue();
|
||||||
|
@ -85,7 +85,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
|
||||||
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
|
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int countMax = myDaoConfig.getPreExpandValueSetsMaxCountExperimental();
|
int countMax = myDaoConfig.getPreExpandValueSetsMaxCount();
|
||||||
if (count > countMax) {
|
if (count > countMax) {
|
||||||
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
|
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
|
||||||
count = countMax;
|
count = countMax;
|
||||||
|
@ -94,7 +94,7 @@ public class BaseJpaResourceProviderValueSetDstu3 extends JpaResourceProviderDst
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
if (myDaoConfig.isPreExpandValueSets()) {
|
||||||
if (haveId) {
|
if (haveId) {
|
||||||
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
|
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
|
||||||
} else if (haveIdentifier) {
|
} else if (haveIdentifier) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
|
||||||
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
|
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental();
|
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffset();
|
||||||
if (theOffset != null && theOffset.hasValue()) {
|
if (theOffset != null && theOffset.hasValue()) {
|
||||||
if (theOffset.getValue() >= 0) {
|
if (theOffset.getValue() >= 0) {
|
||||||
offset = theOffset.getValue();
|
offset = theOffset.getValue();
|
||||||
|
@ -69,7 +69,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = myDaoConfig.getPreExpandValueSetsDefaultCountExperimental();
|
int count = myDaoConfig.getPreExpandValueSetsDefaultCount();
|
||||||
if (theCount != null && theCount.hasValue()) {
|
if (theCount != null && theCount.hasValue()) {
|
||||||
if (theCount.getValue() >= 0) {
|
if (theCount.getValue() >= 0) {
|
||||||
count = theCount.getValue();
|
count = theCount.getValue();
|
||||||
|
@ -77,7 +77,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
|
||||||
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
|
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int countMax = myDaoConfig.getPreExpandValueSetsMaxCountExperimental();
|
int countMax = myDaoConfig.getPreExpandValueSetsMaxCount();
|
||||||
if (count > countMax) {
|
if (count > countMax) {
|
||||||
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
|
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
|
||||||
count = countMax;
|
count = countMax;
|
||||||
|
@ -86,7 +86,7 @@ public class BaseJpaResourceProviderValueSetR4 extends JpaResourceProviderR4<Val
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
if (myDaoConfig.isPreExpandValueSets()) {
|
||||||
if (haveId) {
|
if (haveId) {
|
||||||
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
|
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
|
||||||
} else if (haveIdentifier) {
|
} else if (haveIdentifier) {
|
||||||
|
|
|
@ -60,7 +60,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
|
||||||
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
|
throw new InvalidRequestException("$expand must EITHER be invoked at the instance level, or have a url specified, or have a ValueSet specified. Can not combine these options.");
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental();
|
int offset = myDaoConfig.getPreExpandValueSetsDefaultOffset();
|
||||||
if (theOffset != null && theOffset.hasValue()) {
|
if (theOffset != null && theOffset.hasValue()) {
|
||||||
if (theOffset.getValue() >= 0) {
|
if (theOffset.getValue() >= 0) {
|
||||||
offset = theOffset.getValue();
|
offset = theOffset.getValue();
|
||||||
|
@ -69,7 +69,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int count = myDaoConfig.getPreExpandValueSetsDefaultCountExperimental();
|
int count = myDaoConfig.getPreExpandValueSetsDefaultCount();
|
||||||
if (theCount != null && theCount.hasValue()) {
|
if (theCount != null && theCount.hasValue()) {
|
||||||
if (theCount.getValue() >= 0) {
|
if (theCount.getValue() >= 0) {
|
||||||
count = theCount.getValue();
|
count = theCount.getValue();
|
||||||
|
@ -77,7 +77,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
|
||||||
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
|
throw new InvalidRequestException("count parameter for $expand operation must be >= 0 when specified. count: " + theCount.getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
int countMax = myDaoConfig.getPreExpandValueSetsMaxCountExperimental();
|
int countMax = myDaoConfig.getPreExpandValueSetsMaxCount();
|
||||||
if (count > countMax) {
|
if (count > countMax) {
|
||||||
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
|
ourLog.warn("count parameter for $expand operation of {} exceeds maximum value of {}; using maximum value.", count, countMax);
|
||||||
count = countMax;
|
count = countMax;
|
||||||
|
@ -86,7 +86,7 @@ public class BaseJpaResourceProviderValueSetR5 extends JpaResourceProviderR5<Val
|
||||||
startRequest(theServletRequest);
|
startRequest(theServletRequest);
|
||||||
try {
|
try {
|
||||||
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> dao = (IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept>) getDao();
|
||||||
if (myDaoConfig.isPreExpandValueSetsExperimental()) {
|
if (myDaoConfig.isPreExpandValueSets()) {
|
||||||
if (haveId) {
|
if (haveId) {
|
||||||
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
|
return dao.expand(theId, toFilterString(theFilter), offset, count, theRequestDetails);
|
||||||
} else if (haveIdentifier) {
|
} else if (haveIdentifier) {
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
package ca.uhn.fhir.jpa.search.elastic;
|
||||||
|
|
||||||
|
import org.hibernate.search.cfg.Environment;
|
||||||
|
import org.hibernate.search.elasticsearch.cfg.ElasticsearchEnvironment;
|
||||||
|
import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus;
|
||||||
|
import org.hibernate.search.elasticsearch.cfg.IndexSchemaManagementStrategy;
|
||||||
|
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class is used to inject appropriate properties into a hibernate
|
||||||
|
* Properties object being used to create an entitymanager for a HAPI
|
||||||
|
* FHIR JPA server.
|
||||||
|
*/
|
||||||
|
public class ElasticsearchHibernatePropertiesBuilder {
|
||||||
|
|
||||||
|
private ElasticsearchIndexStatus myRequiredIndexStatus = ElasticsearchIndexStatus.YELLOW;
|
||||||
|
private String myRestUrl;
|
||||||
|
private String myUsername;
|
||||||
|
private String myPassword;
|
||||||
|
private IndexSchemaManagementStrategy myIndexSchemaManagementStrategy = IndexSchemaManagementStrategy.CREATE;
|
||||||
|
private long myIndexManagementWaitTimeoutMillis = 10000L;
|
||||||
|
private boolean myDebugRefreshAfterWrite = false;
|
||||||
|
private boolean myDebugPrettyPrintJsonLog = false;
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setUsername(String theUsername) {
|
||||||
|
myUsername = theUsername;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setPassword(String thePassword) {
|
||||||
|
myPassword = thePassword;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void apply(Properties theProperties) {
|
||||||
|
|
||||||
|
// Don't use the Lucene properties as they conflict
|
||||||
|
theProperties.remove("hibernate.search.model_mapping");
|
||||||
|
|
||||||
|
// the below properties are used for ElasticSearch integration
|
||||||
|
theProperties.put("hibernate.search.default." + Environment.INDEX_MANAGER_IMPL_NAME, "elasticsearch");
|
||||||
|
theProperties.put("hibernate.search." + ElasticsearchEnvironment.ANALYSIS_DEFINITION_PROVIDER, ElasticsearchMappingProvider.class.getName());
|
||||||
|
|
||||||
|
theProperties.put("hibernate.search.default.elasticsearch.host", myRestUrl);
|
||||||
|
theProperties.put("hibernate.search.default.elasticsearch.username", myUsername);
|
||||||
|
theProperties.put("hibernate.search.default.elasticsearch.password", myPassword);
|
||||||
|
|
||||||
|
theProperties.put("hibernate.search.default." + ElasticsearchEnvironment.INDEX_SCHEMA_MANAGEMENT_STRATEGY, myIndexSchemaManagementStrategy.getExternalName());
|
||||||
|
theProperties.put("hibernate.search.default." + ElasticsearchEnvironment.INDEX_MANAGEMENT_WAIT_TIMEOUT, Long.toString(myIndexManagementWaitTimeoutMillis));
|
||||||
|
theProperties.put("hibernate.search.default." + ElasticsearchEnvironment.REQUIRED_INDEX_STATUS, myRequiredIndexStatus.getElasticsearchString());
|
||||||
|
|
||||||
|
// Only for unit tests
|
||||||
|
theProperties.put("hibernate.search.default." + ElasticsearchEnvironment.REFRESH_AFTER_WRITE, Boolean.toString(myDebugRefreshAfterWrite));
|
||||||
|
theProperties.put("hibernate.search." + ElasticsearchEnvironment.LOG_JSON_PRETTY_PRINTING, Boolean.toString(myDebugPrettyPrintJsonLog));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setRequiredIndexStatus(ElasticsearchIndexStatus theRequiredIndexStatus) {
|
||||||
|
myRequiredIndexStatus = theRequiredIndexStatus;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setRestUrl(String theRestUrl) {
|
||||||
|
myRestUrl = theRestUrl;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setIndexSchemaManagementStrategy(IndexSchemaManagementStrategy theIndexSchemaManagementStrategy) {
|
||||||
|
myIndexSchemaManagementStrategy = theIndexSchemaManagementStrategy;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setIndexManagementWaitTimeoutMillis(long theIndexManagementWaitTimeoutMillis) {
|
||||||
|
myIndexManagementWaitTimeoutMillis = theIndexManagementWaitTimeoutMillis;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setDebugRefreshAfterWrite(boolean theDebugRefreshAfterWrite) {
|
||||||
|
myDebugRefreshAfterWrite = theDebugRefreshAfterWrite;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
public ElasticsearchHibernatePropertiesBuilder setDebugPrettyPrintJsonLog(boolean theDebugPrettyPrintJsonLog) {
|
||||||
|
myDebugPrettyPrintJsonLog = theDebugPrettyPrintJsonLog;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,4 +1,4 @@
|
||||||
package ca.uhn.fhir.jpa.search;
|
package ca.uhn.fhir.jpa.search.elastic;
|
||||||
|
|
||||||
/*-
|
/*-
|
||||||
* #%L
|
* #%L
|
||||||
|
@ -20,9 +20,8 @@ package ca.uhn.fhir.jpa.search;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import org.apache.lucene.analysis.core.WhitespaceTokenizerFactory;
|
|
||||||
import org.hibernate.search.elasticsearch.analyzer.definition.ElasticsearchAnalysisDefinitionRegistryBuilder;
|
|
||||||
import org.hibernate.search.elasticsearch.analyzer.definition.ElasticsearchAnalysisDefinitionProvider;
|
import org.hibernate.search.elasticsearch.analyzer.definition.ElasticsearchAnalysisDefinitionProvider;
|
||||||
|
import org.hibernate.search.elasticsearch.analyzer.definition.ElasticsearchAnalysisDefinitionRegistryBuilder;
|
||||||
|
|
||||||
public class ElasticsearchMappingProvider implements ElasticsearchAnalysisDefinitionProvider {
|
public class ElasticsearchMappingProvider implements ElasticsearchAnalysisDefinitionProvider {
|
||||||
|
|
||||||
|
@ -39,10 +38,7 @@ public class ElasticsearchMappingProvider implements ElasticsearchAnalysisDefini
|
||||||
|
|
||||||
builder.analyzer("autocompletePhoneticAnalyzer")
|
builder.analyzer("autocompletePhoneticAnalyzer")
|
||||||
.withTokenizer("standard")
|
.withTokenizer("standard")
|
||||||
.withTokenFilters("standard", "stop", "snowball_english", "phonetic_doublemetaphone");
|
.withTokenFilters("standard", "stop", "snowball_english");
|
||||||
builder.tokenFilter("phonetic_doublemetaphone")
|
|
||||||
.type("phonetic")
|
|
||||||
.param("encoder", "double_metaphone");
|
|
||||||
builder.tokenFilter("snowball_english").type("snowball").param("language", "English");
|
builder.tokenFilter("snowball_english").type("snowball").param("language", "English");
|
||||||
|
|
||||||
builder.analyzer("autocompleteNGramAnalyzer")
|
builder.analyzer("autocompleteNGramAnalyzer")
|
|
@ -63,9 +63,9 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome;
|
||||||
import org.quartz.Job;
|
import org.quartz.Job;
|
||||||
import org.quartz.JobExecutionContext;
|
import org.quartz.JobExecutionContext;
|
||||||
import org.hl7.fhir.r4.model.codesystems.ConceptSubsumptionOutcome;
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
|
@ -204,22 +204,6 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction<?> bool, ValueSet.ConceptSetFilterComponent nextFilter) {
|
|
||||||
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addDisplayFilterInexact(QueryBuilder qb, BooleanJunction<?> bool, ValueSet.ConceptSetFilterComponent nextFilter) {
|
|
||||||
Query textQuery = qb
|
|
||||||
.phrase()
|
|
||||||
.withSlop(2)
|
|
||||||
.onField("myDisplay").boostedTo(4.0f)
|
|
||||||
.andField("myDisplayEdgeNGram").boostedTo(2.0f)
|
|
||||||
// .andField("myDisplayNGram").boostedTo(1.0f)
|
|
||||||
// .andField("myDisplayPhonetic").boostedTo(0.5f)
|
|
||||||
.sentence(nextFilter.getValue().toLowerCase()).createQuery();
|
|
||||||
bool.must(textQuery);
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean addToSet(Set<TermConcept> theSetToPopulate, TermConcept theConcept) {
|
private boolean addToSet(Set<TermConcept> theSetToPopulate, TermConcept theConcept) {
|
||||||
boolean retVal = theSetToPopulate.add(theConcept);
|
boolean retVal = theSetToPopulate.add(theConcept);
|
||||||
if (retVal) {
|
if (retVal) {
|
||||||
|
@ -888,18 +872,20 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
break;
|
break;
|
||||||
case "parent":
|
case "parent":
|
||||||
case "child":
|
case "child":
|
||||||
if (isCodeSystemLoinc(theSystem)) {
|
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
||||||
handleFilterLoincParentChild(theQb, theBool, theFilter);
|
handleFilterLoincParentChild(theQb, theBool, theFilter);
|
||||||
} else {
|
break;
|
||||||
throw new InvalidRequestException("Invalid filter, property " + theFilter.getProperty() + " is LOINC-specific and cannot be used with system: " + theSystem);
|
case "ancestor":
|
||||||
}
|
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
||||||
|
handleFilterLoincAncestor(theSystem, theQb, theBool, theFilter);
|
||||||
|
break;
|
||||||
|
case "descendant":
|
||||||
|
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
||||||
|
handleFilterLoincDescendant(theSystem, theQb, theBool, theFilter);
|
||||||
break;
|
break;
|
||||||
case "copyright":
|
case "copyright":
|
||||||
if (isCodeSystemLoinc(theSystem)) {
|
isCodeSystemLoingOrThrowInvalidRequestException(theSystem, theFilter.getProperty());
|
||||||
handleFilterLoincCopyright(theQb, theBool, theFilter);
|
handleFilterLoincCopyright(theQb, theBool, theFilter);
|
||||||
} else {
|
|
||||||
throw new InvalidRequestException("Invalid filter, property " + theFilter.getProperty() + " is LOINC-specific and cannot be used with system: " + theSystem);
|
|
||||||
}
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
handleFilterRegex(theBool, theFilter);
|
handleFilterRegex(theBool, theFilter);
|
||||||
|
@ -907,6 +893,13 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean isCodeSystemLoingOrThrowInvalidRequestException(String theSystem, String theProperty) {
|
||||||
|
if (!isCodeSystemLoinc(theSystem)) {
|
||||||
|
throw new InvalidRequestException("Invalid filter, property " + theProperty + " is LOINC-specific and cannot be used with system: " + theSystem);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private boolean isCodeSystemLoinc(String theSystem) {
|
private boolean isCodeSystemLoinc(String theSystem) {
|
||||||
return IHapiTerminologyLoaderSvc.LOINC_URI.equals(theSystem);
|
return IHapiTerminologyLoaderSvc.LOINC_URI.equals(theSystem);
|
||||||
}
|
}
|
||||||
|
@ -923,6 +916,22 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addDisplayFilterExact(QueryBuilder qb, BooleanJunction<?> bool, ValueSet.ConceptSetFilterComponent nextFilter) {
|
||||||
|
bool.must(qb.phrase().onField("myDisplay").sentence(nextFilter.getValue()).createQuery());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addDisplayFilterInexact(QueryBuilder qb, BooleanJunction<?> bool, ValueSet.ConceptSetFilterComponent nextFilter) {
|
||||||
|
Query textQuery = qb
|
||||||
|
.phrase()
|
||||||
|
.withSlop(2)
|
||||||
|
.onField("myDisplay").boostedTo(4.0f)
|
||||||
|
.andField("myDisplayEdgeNGram").boostedTo(2.0f)
|
||||||
|
// .andField("myDisplayNGram").boostedTo(1.0f)
|
||||||
|
// .andField("myDisplayPhonetic").boostedTo(0.5f)
|
||||||
|
.sentence(nextFilter.getValue().toLowerCase()).createQuery();
|
||||||
|
bool.must(textQuery);
|
||||||
|
}
|
||||||
|
|
||||||
private void handleFilterConceptAndCode(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void handleFilterConceptAndCode(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
TermConcept code = findCode(theSystem, theFilter.getValue())
|
TermConcept code = findCode(theSystem, theFilter.getValue())
|
||||||
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theFilter.getValue()));
|
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theFilter.getValue()));
|
||||||
|
@ -936,12 +945,15 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFilterLoincParentChild(QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void handleFilterLoincParentChild(QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
|
switch (theFilter.getOp()) {
|
||||||
addLoincFilterParentChildEqual(theBool, theFilter.getProperty(), theFilter.getValue());
|
case EQUAL:
|
||||||
} else if (theFilter.getOp() == ValueSet.FilterOperator.IN) {
|
addLoincFilterParentChildEqual(theBool, theFilter.getProperty(), theFilter.getValue());
|
||||||
addLoincFilterParentChildIn(theBool, theFilter);
|
break;
|
||||||
} else {
|
case IN:
|
||||||
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
addLoincFilterParentChildIn(theBool, theFilter);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -964,6 +976,95 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
return new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theProperty, theValue);
|
return new Term(TermConceptPropertyFieldBridge.CONCEPT_FIELD_PROPERTY_PREFIX + theProperty, theValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void handleFilterLoincAncestor(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
|
switch (theFilter.getOp()) {
|
||||||
|
case EQUAL:
|
||||||
|
addLoincFilterAncestorEqual(theSystem, theQb, theBool, theFilter);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
addLoincFilterAncestorIn(theSystem, theQb, theBool, theFilter);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLoincFilterAncestorEqual(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
|
addLoincFilterAncestorEqual(theSystem, theQb, theBool, theFilter.getProperty(), theFilter.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLoincFilterAncestorEqual(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, String theProperty, String theValue) {
|
||||||
|
List<Term> terms = getAncestorTerms(theSystem, theProperty, theValue);
|
||||||
|
theBool.must(new TermsQuery(terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLoincFilterAncestorIn(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
|
String[] values = theFilter.getValue().split(",");
|
||||||
|
List<Term> terms = new ArrayList<>();
|
||||||
|
for (String value : values) {
|
||||||
|
terms.addAll(getAncestorTerms(theSystem, theFilter.getProperty(), value));
|
||||||
|
}
|
||||||
|
theBool.must(new TermsQuery(terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Term> getAncestorTerms(String theSystem, String theProperty, String theValue) {
|
||||||
|
List<Term> retVal = new ArrayList<>();
|
||||||
|
|
||||||
|
TermConcept code = findCode(theSystem, theValue)
|
||||||
|
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theValue));
|
||||||
|
|
||||||
|
retVal.add(new Term("myParentPids", "" + code.getId()));
|
||||||
|
logFilteringValueOnProperty(theValue, theProperty);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void handleFilterLoincDescendant(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
|
switch (theFilter.getOp()) {
|
||||||
|
case EQUAL:
|
||||||
|
addLoincFilterDescendantEqual(theSystem, theBool, theFilter);
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
addLoincFilterDescendantIn(theSystem, theQb, theBool, theFilter);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new InvalidRequestException("Don't know how to handle op=" + theFilter.getOp() + " on property " + theFilter.getProperty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
|
addLoincFilterDescendantEqual(theSystem, theBool, theFilter.getProperty(), theFilter.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLoincFilterDescendantEqual(String theSystem, BooleanJunction<?> theBool, String theProperty, String theValue) {
|
||||||
|
List<Term> terms = getDescendantTerms(theSystem, theProperty, theValue);
|
||||||
|
theBool.must(new TermsQuery(terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addLoincFilterDescendantIn(String theSystem, QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
|
String[] values = theFilter.getValue().split(",");
|
||||||
|
List<Term> terms = new ArrayList<>();
|
||||||
|
for (String value : values) {
|
||||||
|
terms.addAll(getDescendantTerms(theSystem, theFilter.getProperty(), value));
|
||||||
|
}
|
||||||
|
theBool.must(new TermsQuery(terms));
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<Term> getDescendantTerms(String theSystem, String theProperty, String theValue) {
|
||||||
|
List<Term> retVal = new ArrayList<>();
|
||||||
|
|
||||||
|
TermConcept code = findCode(theSystem, theValue)
|
||||||
|
.orElseThrow(() -> new InvalidRequestException("Invalid filter criteria - code does not exist: {" + theSystem + "}" + theValue));
|
||||||
|
|
||||||
|
String[] parentPids = code.getParentPidsAsString().split(" ");
|
||||||
|
for (String parentPid : parentPids) {
|
||||||
|
retVal.add(new Term("myId", parentPid));
|
||||||
|
}
|
||||||
|
logFilteringValueOnProperty(theValue, theProperty);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
private void handleFilterLoincCopyright(QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
private void handleFilterLoincCopyright(QueryBuilder theQb, BooleanJunction<?> theBool, ValueSet.ConceptSetFilterComponent theFilter) {
|
||||||
if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
|
if (theFilter.getOp() == ValueSet.FilterOperator.EQUAL) {
|
||||||
|
|
||||||
|
@ -1870,7 +1971,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) {
|
public void storeTermConceptMapAndChildren(ResourceTable theResourceTable, ConceptMap theConceptMap) {
|
||||||
ourLog.info("Storing TermConceptMap {}", theConceptMap.getIdElement().getValue());
|
ourLog.info("Storing TermConceptMap for {}", theConceptMap.getIdElement().toVersionless().getValueAsString());
|
||||||
|
|
||||||
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
|
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
|
||||||
ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theConceptMap.getUrl(), "ConceptMap has no value for ConceptMap.url");
|
ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theConceptMap.getUrl(), "ConceptMap has no value for ConceptMap.url");
|
||||||
|
@ -1981,7 +2082,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
throw new UnprocessableEntityException(msg);
|
throw new UnprocessableEntityException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Done storing TermConceptMap[{}]", termConceptMap.getId());
|
ourLog.info("Done storing TermConceptMap[{}] for {}", termConceptMap.getId(), theConceptMap.getIdElement().toVersionless().getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -2077,7 +2178,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
@Override
|
@Override
|
||||||
@Transactional
|
@Transactional
|
||||||
public void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet) {
|
public void storeTermValueSet(ResourceTable theResourceTable, ValueSet theValueSet) {
|
||||||
ourLog.info("Storing TermValueSet {}", theValueSet.getIdElement().getValue());
|
ourLog.info("Storing TermValueSet for {}", theValueSet.getIdElement().toVersionless().getValueAsString());
|
||||||
|
|
||||||
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
|
ValidateUtil.isTrueOrThrowInvalidRequest(theResourceTable != null, "No resource supplied");
|
||||||
ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theValueSet.getUrl(), "ValueSet has no value for ValueSet.url");
|
ValidateUtil.isNotBlankOrThrowUnprocessableEntity(theValueSet.getUrl(), "ValueSet has no value for ValueSet.url");
|
||||||
|
@ -2111,7 +2212,7 @@ public abstract class BaseHapiTerminologySvcImpl implements IHapiTerminologySvc,
|
||||||
throw new UnprocessableEntityException(msg);
|
throw new UnprocessableEntityException(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
ourLog.info("Done storing TermValueSet[{}]", termValueSet.getId());
|
ourLog.info("Done storing TermValueSet[{}] for {}", termValueSet.getId(), theValueSet.getIdElement().toVersionless().getValueAsString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -42,8 +42,8 @@ public class LoincPartRelatedCodeMappingHandler extends BaseLoincHandler impleme
|
||||||
public static final String LOINC_SCT_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-snomed-ct";
|
public static final String LOINC_SCT_PART_MAP_URI = "http://loinc.org/cm/loinc-parts-to-snomed-ct";
|
||||||
private static final String LOINC_SCT_PART_MAP_NAME = "LOINC Part Map to SNOMED CT";
|
private static final String LOINC_SCT_PART_MAP_NAME = "LOINC Part Map to SNOMED CT";
|
||||||
|
|
||||||
public static final String LOINC_TERM_TO_RPID_PART_MAP_ID = "loinc-term-to-rpids";
|
public static final String LOINC_TERM_TO_RPID_PART_MAP_ID = "loinc-to-rpids";
|
||||||
public static final String LOINC_TERM_TO_RPID_PART_MAP_URI = "http://loinc.org/cm/loinc-term-to-rpids";
|
public static final String LOINC_TERM_TO_RPID_PART_MAP_URI = "http://loinc.org/cm/loinc-to-rpids";
|
||||||
public static final String LOINC_TERM_TO_RPID_PART_MAP_NAME = "LOINC Terms to RadLex RPIDs";
|
public static final String LOINC_TERM_TO_RPID_PART_MAP_NAME = "LOINC Terms to RadLex RPIDs";
|
||||||
|
|
||||||
public static final String LOINC_PART_TO_RID_PART_MAP_ID = "loinc-part-to-rids";
|
public static final String LOINC_PART_TO_RID_PART_MAP_ID = "loinc-part-to-rids";
|
||||||
|
|
|
@ -38,7 +38,8 @@ public class JpaValidationSupportChainDstu3 extends ValidationSupportChain {
|
||||||
@Autowired
|
@Autowired
|
||||||
@Qualifier("myJpaValidationSupportDstu3")
|
@Qualifier("myJpaValidationSupportDstu3")
|
||||||
public ca.uhn.fhir.jpa.dao.dstu3.IJpaValidationSupportDstu3 myJpaValidationSupportDstu3;
|
public ca.uhn.fhir.jpa.dao.dstu3.IJpaValidationSupportDstu3 myJpaValidationSupportDstu3;
|
||||||
private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport();
|
@Autowired
|
||||||
|
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
|
||||||
@Autowired
|
@Autowired
|
||||||
private IHapiTerminologySvcDstu3 myTerminologyService;
|
private IHapiTerminologySvcDstu3 myTerminologyService;
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
|
@ -20,10 +20,8 @@ package ca.uhn.fhir.jpa.validation;
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||||
import org.hl7.fhir.r4.hapi.validation.SnapshotGeneratingValidationSupport;
|
import org.hl7.fhir.r4.hapi.validation.SnapshotGeneratingValidationSupport;
|
||||||
|
@ -32,11 +30,13 @@ import org.hl7.fhir.r4.model.StructureDefinition;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
|
import javax.annotation.PostConstruct;
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
public class JpaValidationSupportChainR4 extends ValidationSupportChain {
|
public class JpaValidationSupportChainR4 extends ValidationSupportChain {
|
||||||
|
|
||||||
private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport();
|
@Autowired
|
||||||
|
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myFhirContext;
|
private FhirContext myFhirContext;
|
||||||
|
|
|
@ -35,7 +35,8 @@ import javax.annotation.PreDestroy;
|
||||||
|
|
||||||
public class JpaValidationSupportChainR5 extends ValidationSupportChain {
|
public class JpaValidationSupportChainR5 extends ValidationSupportChain {
|
||||||
|
|
||||||
private DefaultProfileValidationSupport myDefaultProfileValidationSupport = new DefaultProfileValidationSupport();
|
@Autowired
|
||||||
|
private DefaultProfileValidationSupport myDefaultProfileValidationSupport;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private FhirContext myFhirContext;
|
private FhirContext myFhirContext;
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.config;
|
|
||||||
|
|
||||||
import java.util.Properties;
|
|
||||||
|
|
||||||
import org.hibernate.dialect.H2Dialect;
|
|
||||||
import org.hibernate.jpa.HibernatePersistenceProvider;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowire;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
|
|
||||||
import org.springframework.transaction.annotation.EnableTransactionManagement;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl;
|
|
||||||
import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
@EnableTransactionManagement()
|
|
||||||
public class TestDstu3WithoutLuceneConfig extends TestDstu3Config {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Disable fulltext searching
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public IFulltextSearchSvc searchDaoDstu3() {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@Bean
|
|
||||||
public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
|
|
||||||
LocalContainerEntityManagerFactoryBean retVal = super.entityManagerFactory();
|
|
||||||
retVal.setJpaProperties(jpaProperties());
|
|
||||||
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", H2Dialect.class.getName());
|
|
||||||
extraProperties.put("hibernate.search.autoregister_listeners", "false");
|
|
||||||
return extraProperties;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -138,7 +138,8 @@ public class TestR4Config extends BaseJavaConfigR4 {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties jpaProperties() {
|
@Bean
|
||||||
|
public Properties jpaProperties() {
|
||||||
Properties extraProperties = new Properties();
|
Properties extraProperties = new Properties();
|
||||||
extraProperties.put("hibernate.format_sql", "false");
|
extraProperties.put("hibernate.format_sql", "false");
|
||||||
extraProperties.put("hibernate.show_sql", "false");
|
extraProperties.put("hibernate.show_sql", "false");
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
package ca.uhn.fhir.jpa.config;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.ConfigurationException;
|
||||||
|
import ca.uhn.fhir.jpa.search.elastic.ElasticsearchHibernatePropertiesBuilder;
|
||||||
|
import org.hibernate.search.elasticsearch.cfg.ElasticsearchIndexStatus;
|
||||||
|
import org.hibernate.search.elasticsearch.cfg.IndexSchemaManagementStrategy;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import pl.allegro.tech.embeddedelasticsearch.EmbeddedElastic;
|
||||||
|
import pl.allegro.tech.embeddedelasticsearch.PopularProperties;
|
||||||
|
|
||||||
|
import javax.annotation.PreDestroy;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Properties;
|
||||||
|
import java.util.UUID;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
public class TestR4ConfigWithElasticSearch extends TestR4Config {
|
||||||
|
|
||||||
|
private static final Logger ourLog = LoggerFactory.getLogger(TestR4ConfigWithElasticSearch.class);
|
||||||
|
private static final String ELASTIC_VERSION = "6.5.4";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Bean
|
||||||
|
public Properties jpaProperties() {
|
||||||
|
Properties retVal = super.jpaProperties();
|
||||||
|
|
||||||
|
// Force elasticsearch to start first
|
||||||
|
int httpPort = embeddedElasticSearch().getHttpPort();
|
||||||
|
ourLog.info("ElasticSearch started on port: {}", httpPort);
|
||||||
|
|
||||||
|
new ElasticsearchHibernatePropertiesBuilder()
|
||||||
|
.setDebugRefreshAfterWrite(true)
|
||||||
|
.setDebugPrettyPrintJsonLog(true)
|
||||||
|
.setIndexSchemaManagementStrategy(IndexSchemaManagementStrategy.CREATE)
|
||||||
|
.setIndexManagementWaitTimeoutMillis(10000)
|
||||||
|
.setRequiredIndexStatus(ElasticsearchIndexStatus.YELLOW)
|
||||||
|
.setRestUrl("http://localhost:" + httpPort)
|
||||||
|
.setUsername("")
|
||||||
|
.setPassword("")
|
||||||
|
.apply(retVal);
|
||||||
|
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public EmbeddedElastic embeddedElasticSearch() {
|
||||||
|
EmbeddedElastic embeddedElastic = null;
|
||||||
|
try {
|
||||||
|
embeddedElastic = EmbeddedElastic.builder()
|
||||||
|
.withElasticVersion(ELASTIC_VERSION)
|
||||||
|
.withSetting(PopularProperties.TRANSPORT_TCP_PORT, 0)
|
||||||
|
.withSetting(PopularProperties.HTTP_PORT, 0)
|
||||||
|
.withSetting(PopularProperties.CLUSTER_NAME, UUID.randomUUID())
|
||||||
|
.withStartTimeout(60, TimeUnit.SECONDS)
|
||||||
|
.build()
|
||||||
|
.start();
|
||||||
|
} catch (IOException | InterruptedException e) {
|
||||||
|
throw new ConfigurationException(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
return embeddedElastic;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PreDestroy
|
||||||
|
public void stop() {
|
||||||
|
embeddedElasticSearch().stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -15,7 +15,7 @@ import ca.uhn.fhir.jpa.dao.IFulltextSearchSvc;
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableTransactionManagement()
|
@EnableTransactionManagement()
|
||||||
public class TestR4WithoutLuceneConfig extends TestR4Config {
|
public class TestR4WithLuceneDisabledConfig extends TestR4Config {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable fulltext searching
|
* Disable fulltext searching
|
||||||
|
@ -34,7 +34,8 @@ public class TestR4WithoutLuceneConfig extends TestR4Config {
|
||||||
return retVal;
|
return retVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Properties jpaProperties() {
|
@Override
|
||||||
|
public Properties jpaProperties() {
|
||||||
Properties extraProperties = new Properties();
|
Properties extraProperties = new Properties();
|
||||||
extraProperties.put("hibernate.format_sql", "false");
|
extraProperties.put("hibernate.format_sql", "false");
|
||||||
extraProperties.put("hibernate.show_sql", "false");
|
extraProperties.put("hibernate.show_sql", "false");
|
|
@ -537,6 +537,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
@Test
|
@Test
|
||||||
public void testIndexNoDuplicatesUri() {
|
public void testIndexNoDuplicatesUri() {
|
||||||
ValueSet res = new ValueSet();
|
ValueSet res = new ValueSet();
|
||||||
|
res.setUrl("http://www.example.org/vs");
|
||||||
res.getCompose().addInclude().setSystem("http://foo");
|
res.getCompose().addInclude().setSystem("http://foo");
|
||||||
res.getCompose().addInclude().setSystem("http://bar");
|
res.getCompose().addInclude().setSystem("http://bar");
|
||||||
res.getCompose().addInclude().setSystem("http://foo");
|
res.getCompose().addInclude().setSystem("http://foo");
|
||||||
|
@ -549,7 +550,7 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
|
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
|
||||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList();
|
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList();
|
||||||
ourLog.info(toStringMultiline(results));
|
ourLog.info(toStringMultiline(results));
|
||||||
assertEquals(2, results.size());
|
assertEquals(3, results.size());
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo"))));
|
List<IIdType> actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo"))));
|
||||||
assertThat(actual, contains(id));
|
assertThat(actual, contains(id));
|
||||||
|
@ -2161,13 +2162,14 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchUriWrongParam() throws Exception {
|
public void testSearchUriWrongParam() {
|
||||||
ValueSet v1 = new ValueSet();
|
ValueSet v1 = new ValueSet();
|
||||||
v1.getUrlElement().setValue("http://foo");
|
v1.getUrlElement().setValue("http://foo");
|
||||||
String id1 = myValueSetDao.create(v1).getId().toUnqualifiedVersionless().getValue();
|
String id1 = myValueSetDao.create(v1).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
ValueSet v2 = new ValueSet();
|
ValueSet v2 = new ValueSet();
|
||||||
v2.getExpansion().getIdentifierElement().setValue("http://foo");
|
v2.getExpansion().getIdentifierElement().setValue("http://foo");
|
||||||
|
v2.getUrlElement().setValue("http://www.example.org/vs");
|
||||||
String id2 = myValueSetDao.create(v2).getId().toUnqualifiedVersionless().getValue();
|
String id2 = myValueSetDao.create(v2).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -1,234 +0,0 @@
|
||||||
package ca.uhn.fhir.jpa.dao.dstu3;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.jpa.bulk.IBulkDataExportSvc;
|
|
||||||
import ca.uhn.fhir.jpa.config.TestDstu3WithoutLuceneConfig;
|
|
||||||
import ca.uhn.fhir.jpa.dao.*;
|
|
||||||
import ca.uhn.fhir.jpa.provider.dstu3.JpaSystemProviderDstu3;
|
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
|
||||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
|
||||||
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
|
||||||
import ca.uhn.fhir.rest.param.StringParam;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
|
||||||
import org.hl7.fhir.dstu3.hapi.ctx.IValidationSupport;
|
|
||||||
import org.hl7.fhir.dstu3.model.*;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.junit.AfterClass;
|
|
||||||
import org.junit.Before;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
|
||||||
|
|
||||||
import javax.persistence.EntityManager;
|
|
||||||
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
|
|
||||||
// @RunWith(SpringJUnit4ClassRunner.class)
|
|
||||||
// @ContextConfiguration(classes= {TestDstu3WithoutLuceneConfig.class})
|
|
||||||
// @SuppressWarnings("unchecked")
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
|
||||||
@ContextConfiguration(classes = {TestDstu3WithoutLuceneConfig.class})
|
|
||||||
public class FhirResourceDaoDstu3SearchWithLuceneDisabledTest extends BaseJpaTest {
|
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoDstu3SearchWithLuceneDisabledTest.class);
|
|
||||||
@Autowired
|
|
||||||
protected DaoConfig myDaoConfig;
|
|
||||||
@Autowired
|
|
||||||
protected PlatformTransactionManager myTxManager;
|
|
||||||
@Autowired
|
|
||||||
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
|
||||||
@Autowired
|
|
||||||
protected ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
|
||||||
@Autowired
|
|
||||||
protected ISearchParamRegistry mySearchParamRegistry;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myAllergyIntoleranceDaoDstu3")
|
|
||||||
private IFhirResourceDao<AllergyIntolerance> myAllergyIntoleranceDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myAppointmentDaoDstu3")
|
|
||||||
private IFhirResourceDao<Appointment> myAppointmentDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myAuditEventDaoDstu3")
|
|
||||||
private IFhirResourceDao<AuditEvent> myAuditEventDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myBundleDaoDstu3")
|
|
||||||
private IFhirResourceDao<Bundle> myBundleDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myCarePlanDaoDstu3")
|
|
||||||
private IFhirResourceDao<CarePlan> myCarePlanDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myCodeSystemDaoDstu3")
|
|
||||||
private IFhirResourceDao<CodeSystem> myCodeSystemDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myCompartmentDefinitionDaoDstu3")
|
|
||||||
private IFhirResourceDao<CompartmentDefinition> myCompartmentDefinitionDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myConceptMapDaoDstu3")
|
|
||||||
private IFhirResourceDao<ConceptMap> myConceptMapDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myConditionDaoDstu3")
|
|
||||||
private IFhirResourceDao<Condition> myConditionDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myDeviceDaoDstu3")
|
|
||||||
private IFhirResourceDao<Device> myDeviceDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myDiagnosticReportDaoDstu3")
|
|
||||||
private IFhirResourceDao<DiagnosticReport> myDiagnosticReportDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myEncounterDaoDstu3")
|
|
||||||
private IFhirResourceDao<Encounter> myEncounterDao;
|
|
||||||
// @PersistenceContext()
|
|
||||||
@Autowired
|
|
||||||
private EntityManager myEntityManager;
|
|
||||||
@Autowired
|
|
||||||
private FhirContext myFhirCtx;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myImmunizationDaoDstu3")
|
|
||||||
private IFhirResourceDao<Immunization> myImmunizationDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myLocationDaoDstu3")
|
|
||||||
private IFhirResourceDao<Location> myLocationDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myMediaDaoDstu3")
|
|
||||||
private IFhirResourceDao<Media> myMediaDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myMedicationDaoDstu3")
|
|
||||||
private IFhirResourceDao<Medication> myMedicationDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myMedicationRequestDaoDstu3")
|
|
||||||
private IFhirResourceDao<MedicationRequest> myMedicationRequestDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myNamingSystemDaoDstu3")
|
|
||||||
private IFhirResourceDao<NamingSystem> myNamingSystemDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myObservationDaoDstu3")
|
|
||||||
private IFhirResourceDao<Observation> myObservationDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myOperationDefinitionDaoDstu3")
|
|
||||||
private IFhirResourceDao<OperationDefinition> myOperationDefinitionDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myOrganizationDaoDstu3")
|
|
||||||
private IFhirResourceDao<Organization> myOrganizationDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myPatientDaoDstu3")
|
|
||||||
private IFhirResourceDaoPatient<Patient> myPatientDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myPractitionerDaoDstu3")
|
|
||||||
private IFhirResourceDao<Practitioner> myPractitionerDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myQuestionnaireDaoDstu3")
|
|
||||||
private IFhirResourceDao<Questionnaire> myQuestionnaireDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myQuestionnaireResponseDaoDstu3")
|
|
||||||
private IFhirResourceDao<QuestionnaireResponse> myQuestionnaireResponseDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myResourceProvidersDstu3")
|
|
||||||
private Object myResourceProviders;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myStructureDefinitionDaoDstu3")
|
|
||||||
private IFhirResourceDao<StructureDefinition> myStructureDefinitionDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("mySubscriptionDaoDstu3")
|
|
||||||
private IFhirResourceDaoSubscription<Subscription> mySubscriptionDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("mySubstanceDaoDstu3")
|
|
||||||
private IFhirResourceDao<Substance> mySubstanceDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("mySystemDaoDstu3")
|
|
||||||
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("mySystemProviderDstu3")
|
|
||||||
private JpaSystemProviderDstu3 mySystemProvider;
|
|
||||||
@Autowired
|
|
||||||
@Qualifier("myJpaValidationSupportChainDstu3")
|
|
||||||
private IValidationSupport myValidationSupport;
|
|
||||||
@Autowired
|
|
||||||
private IResourceReindexingSvc myResourceReindexingSvc;
|
|
||||||
@Autowired
|
|
||||||
private IBulkDataExportSvc myBulkDataExportSvc;
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void beforePurgeDatabase() {
|
|
||||||
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry, myBulkDataExportSvc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Before
|
|
||||||
public void beforeResetConfig() {
|
|
||||||
myDaoConfig.setHardSearchLimit(1000);
|
|
||||||
myDaoConfig.setHardTagListLimit(1000);
|
|
||||||
myDaoConfig.setIncludeLimit(2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected FhirContext getContext() {
|
|
||||||
return myFhirCtx;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected PlatformTransactionManager getTxManager() {
|
|
||||||
return myTxManager;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSearchWithContent() throws Exception {
|
|
||||||
String methodName = "testEverythingIncludesBackReferences";
|
|
||||||
|
|
||||||
Organization org = new Organization();
|
|
||||||
org.setName(methodName);
|
|
||||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
SearchParameterMap map = new SearchParameterMap();
|
|
||||||
map.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, new StringParam(methodName));
|
|
||||||
try {
|
|
||||||
myOrganizationDao.search(map).size();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("Fulltext search is not enabled on this service, can not process parameter: _content", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSearchWithRegularParam() throws Exception {
|
|
||||||
String methodName = "testEverythingIncludesBackReferences";
|
|
||||||
|
|
||||||
Organization org = new Organization();
|
|
||||||
org.setName(methodName);
|
|
||||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
SearchParameterMap map = new SearchParameterMap();
|
|
||||||
map.add(Organization.SP_NAME, new StringParam(methodName));
|
|
||||||
myOrganizationDao.search(map);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testSearchWithText() throws Exception {
|
|
||||||
String methodName = "testEverythingIncludesBackReferences";
|
|
||||||
|
|
||||||
Organization org = new Organization();
|
|
||||||
org.setName(methodName);
|
|
||||||
IIdType orgId = myOrganizationDao.create(org, mySrd).getId().toUnqualifiedVersionless();
|
|
||||||
|
|
||||||
SearchParameterMap map = new SearchParameterMap();
|
|
||||||
map.add(ca.uhn.fhir.rest.api.Constants.PARAM_TEXT, new StringParam(methodName));
|
|
||||||
try {
|
|
||||||
myOrganizationDao.search(map).size();
|
|
||||||
fail();
|
|
||||||
} catch (InvalidRequestException e) {
|
|
||||||
assertEquals("Fulltext search is not enabled on this service, can not process parameter: _text", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -229,7 +229,7 @@ public class FhirResourceDaoDstu3ValueSetTest extends BaseJpaDstu3Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValiedateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
|
public void testValidateCodeAgainstBuiltInValueSetAndCodeSystemWithValidCode() {
|
||||||
IPrimitiveType<String> display = null;
|
IPrimitiveType<String> display = null;
|
||||||
Coding coding = null;
|
Coding coding = null;
|
||||||
CodeableConcept codeableConcept = null;
|
CodeableConcept codeableConcept = null;
|
||||||
|
|
|
@ -1,25 +1,26 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.*;
|
|
||||||
import static org.junit.Assert.*;
|
|
||||||
import static org.mockito.Mockito.mock;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
import ca.uhn.fhir.jpa.dao.BaseHapiFhirDao;
|
||||||
import org.hl7.fhir.r4.model.*;
|
|
||||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
|
||||||
import org.junit.*;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
import ca.uhn.fhir.jpa.dao.FulltextSearchSvcImpl.Suggestion;
|
||||||
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.param.*;
|
import ca.uhn.fhir.rest.param.*;
|
||||||
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Ignore;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.*;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
|
@ -30,12 +31,6 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
myDaoConfig.setReuseCachedSearchResultsForMillis(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
|
||||||
public static void afterClassClearContext() {
|
|
||||||
TestUtil.clearAllStaticFieldsForUnitTest();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCodeTextSearch() {
|
public void testCodeTextSearch() {
|
||||||
Observation obs1 = new Observation();
|
Observation obs1 = new Observation();
|
||||||
|
@ -72,7 +67,6 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testResourceTextSearch() {
|
public void testResourceTextSearch() {
|
||||||
Observation obs1 = new Observation();
|
Observation obs1 = new Observation();
|
||||||
|
@ -127,7 +121,6 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSuggestIgnoresBase64Content() {
|
public void testSuggestIgnoresBase64Content() {
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
|
@ -153,7 +146,7 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
Media med = new Media();
|
Media med = new Media();
|
||||||
med.getSubject().setReferenceElement(ptId);
|
med.getSubject().setReferenceElement(ptId);
|
||||||
med.getContent().setContentType("LCws");
|
med.getContent().setContentType("LCws");
|
||||||
med.getContent().setDataElement(new Base64BinaryType(new byte[] {44,44,44,44,44,44,44,44}));
|
med.getContent().setDataElement(new Base64BinaryType(new byte[]{44, 44, 44, 44, 44, 44, 44, 44}));
|
||||||
med.getContent().setTitle("bbbb syst");
|
med.getContent().setTitle("bbbb syst");
|
||||||
myMediaDao.create(med, mockSrd());
|
myMediaDao.create(med, mockSrd());
|
||||||
ourLog.info(myFhirCtx.newJsonParser().encodeResourceToString(med));
|
ourLog.info(myFhirCtx.newJsonParser().encodeResourceToString(med));
|
||||||
|
@ -251,7 +244,6 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testSearchAndReindex() {
|
public void testSearchAndReindex() {
|
||||||
Patient patient;
|
Patient patient;
|
||||||
|
@ -478,7 +470,6 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When processing transactions, we do two passes. Make sure we don't update the lucene index twice since that would
|
* When processing transactions, we do two passes. Make sure we don't update the lucene index twice since that would
|
||||||
* be inefficient
|
* be inefficient
|
||||||
|
@ -576,4 +567,9 @@ public class FhirResourceDaoR4SearchFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -914,6 +914,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testIndexNoDuplicatesUri() {
|
public void testIndexNoDuplicatesUri() {
|
||||||
ValueSet res = new ValueSet();
|
ValueSet res = new ValueSet();
|
||||||
|
res.setUrl("http://www.example.org/vs");
|
||||||
res.getCompose().addInclude().setSystem("http://foo");
|
res.getCompose().addInclude().setSystem("http://foo");
|
||||||
res.getCompose().addInclude().setSystem("http://bar");
|
res.getCompose().addInclude().setSystem("http://bar");
|
||||||
res.getCompose().addInclude().setSystem("http://foo");
|
res.getCompose().addInclude().setSystem("http://foo");
|
||||||
|
@ -927,7 +928,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
|
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
|
||||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList();
|
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList();
|
||||||
ourLog.info(toStringMultiline(results));
|
ourLog.info(toStringMultiline(results));
|
||||||
assertEquals(2, results.size());
|
assertEquals(3, results.size());
|
||||||
});
|
});
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo"))));
|
List<IIdType> actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo"))));
|
||||||
|
@ -2951,6 +2952,7 @@ public class FhirResourceDaoR4SearchNoFtTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
ValueSet v2 = new ValueSet();
|
ValueSet v2 = new ValueSet();
|
||||||
v2.getExpansion().getIdentifierElement().setValue("http://foo");
|
v2.getExpansion().getIdentifierElement().setValue("http://foo");
|
||||||
|
v2.getUrlElement().setValue("http://www.example.org/vs");
|
||||||
String id2 = myValueSetDao.create(v2).getId().toUnqualifiedVersionless().getValue();
|
String id2 = myValueSetDao.create(v2).getId().toUnqualifiedVersionless().getValue();
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
@ -772,6 +772,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
||||||
@Test
|
@Test
|
||||||
public void testIndexNoDuplicatesUri() {
|
public void testIndexNoDuplicatesUri() {
|
||||||
ValueSet res = new ValueSet();
|
ValueSet res = new ValueSet();
|
||||||
|
res.setUrl("http://www.example.org/vs");
|
||||||
res.getCompose().addInclude().setSystem("http://foo");
|
res.getCompose().addInclude().setSystem("http://foo");
|
||||||
res.getCompose().addInclude().setSystem("http://bar");
|
res.getCompose().addInclude().setSystem("http://bar");
|
||||||
res.getCompose().addInclude().setSystem("http://foo");
|
res.getCompose().addInclude().setSystem("http://foo");
|
||||||
|
@ -785,7 +786,7 @@ public class FhirResourceDaoR4SearchNoHashesTest extends BaseJpaR4Test {
|
||||||
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
|
Class<ResourceIndexedSearchParamUri> type = ResourceIndexedSearchParamUri.class;
|
||||||
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList();
|
List<?> results = myEntityManager.createQuery("SELECT i FROM " + type.getSimpleName() + " i WHERE i.myMissing = false", type).getResultList();
|
||||||
ourLog.info(toStringMultiline(results));
|
ourLog.info(toStringMultiline(results));
|
||||||
assertEquals(2, results.size());
|
assertEquals(3, results.size());
|
||||||
});
|
});
|
||||||
|
|
||||||
List<IIdType> actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo"))));
|
List<IIdType> actual = toUnqualifiedVersionlessIds(myValueSetDao.search(new SearchParameterMap().setLoadSynchronous(true).add(ValueSet.SP_REFERENCE, new UriParam("http://foo"))));
|
||||||
|
|
|
@ -527,7 +527,12 @@ public class FhirResourceDaoR4SearchOptimizedTest extends BaseJpaR4Test {
|
||||||
/*
|
/*
|
||||||
* 20 should be prefetched since that's the initial page size
|
* 20 should be prefetched since that's the initial page size
|
||||||
*/
|
*/
|
||||||
|
await().until(()->{
|
||||||
|
return runInTransaction(()->{
|
||||||
|
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
|
||||||
|
return search.getNumFound() == 20;
|
||||||
|
});
|
||||||
|
});
|
||||||
runInTransaction(() -> {
|
runInTransaction(() -> {
|
||||||
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
|
Search search = mySearchEntityDao.findByUuidAndFetchIncludes(uuid).orElseThrow(() -> new InternalErrorException(""));
|
||||||
assertEquals(20, search.getNumFound());
|
assertEquals(20, search.getNumFound());
|
||||||
|
|
|
@ -0,0 +1,230 @@
|
||||||
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.jpa.bulk.IBulkDataExportSvc;
|
||||||
|
import ca.uhn.fhir.jpa.config.TestR4ConfigWithElasticSearch;
|
||||||
|
import ca.uhn.fhir.jpa.dao.*;
|
||||||
|
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
|
import ca.uhn.fhir.jpa.provider.r4.JpaSystemProviderR4;
|
||||||
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
|
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.SearchParameterMap;
|
||||||
|
import ca.uhn.fhir.jpa.searchparam.registry.ISearchParamRegistry;
|
||||||
|
import ca.uhn.fhir.jpa.sp.ISearchParamPresenceSvc;
|
||||||
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvcR4;
|
||||||
|
import ca.uhn.fhir.parser.IParser;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.param.StringParam;
|
||||||
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
|
import ca.uhn.fhir.validation.FhirValidator;
|
||||||
|
import ca.uhn.fhir.validation.ValidationResult;
|
||||||
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
|
import org.hl7.fhir.r4.hapi.ctx.IValidationSupport;
|
||||||
|
import org.hl7.fhir.r4.model.*;
|
||||||
|
import org.junit.AfterClass;
|
||||||
|
import org.junit.Before;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
|
|
||||||
|
import javax.persistence.EntityManager;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
|
@ContextConfiguration(classes = {TestR4ConfigWithElasticSearch.class})
|
||||||
|
public class FhirResourceDaoR4SearchWithElasticSearchTest extends BaseJpaTest {
|
||||||
|
public static final String URL_MY_CODE_SYSTEM = "http://example.com/my_code_system";
|
||||||
|
public static final String URL_MY_VALUE_SET = "http://example.com/my_value_set";
|
||||||
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchWithElasticSearchTest.class);
|
||||||
|
@Autowired
|
||||||
|
protected DaoConfig myDaoConfig;
|
||||||
|
@Autowired
|
||||||
|
protected PlatformTransactionManager myTxManager;
|
||||||
|
@Autowired
|
||||||
|
protected ISearchParamPresenceSvc mySearchParamPresenceSvc;
|
||||||
|
@Autowired
|
||||||
|
protected ISearchCoordinatorSvc mySearchCoordinatorSvc;
|
||||||
|
@Autowired
|
||||||
|
protected ISearchParamRegistry mySearchParamRegistry;
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("myValueSetDaoR4")
|
||||||
|
protected IFhirResourceDaoValueSet<ValueSet, Coding, CodeableConcept> myValueSetDao;
|
||||||
|
@Autowired
|
||||||
|
protected IHapiTerminologySvcR4 myTermSvc;
|
||||||
|
@Autowired
|
||||||
|
protected IResourceTableDao myResourceTableDao;
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("myCodeSystemDaoR4")
|
||||||
|
private IFhirResourceDao<CodeSystem> myCodeSystemDao;
|
||||||
|
@Autowired
|
||||||
|
private FhirContext myFhirCtx;
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("myObservationDaoR4")
|
||||||
|
private IFhirResourceDao<Observation> myObservationDao;
|
||||||
|
@Autowired
|
||||||
|
@Qualifier("mySystemDaoR4")
|
||||||
|
private IFhirSystemDao<Bundle, Meta> mySystemDao;
|
||||||
|
@Autowired
|
||||||
|
private IResourceReindexingSvc myResourceReindexingSvc;
|
||||||
|
@Autowired
|
||||||
|
private IBulkDataExportSvc myBulkDataExportSvc;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void beforePurgeDatabase() {
|
||||||
|
purgeDatabase(myDaoConfig, mySystemDao, myResourceReindexingSvc, mySearchCoordinatorSvc, mySearchParamRegistry, myBulkDataExportSvc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected FhirContext getContext() {
|
||||||
|
return myFhirCtx;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected PlatformTransactionManager getTxManager() {
|
||||||
|
return myTxManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testResourceTextSearch() throws InterruptedException {
|
||||||
|
Observation obs1 = new Observation();
|
||||||
|
obs1.getCode().setText("Systolic Blood Pressure");
|
||||||
|
obs1.setStatus(Observation.ObservationStatus.FINAL);
|
||||||
|
obs1.setValue(new Quantity(123));
|
||||||
|
obs1.getNoteFirstRep().setText("obs1");
|
||||||
|
IIdType id1 = myObservationDao.create(obs1, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
Observation obs2 = new Observation();
|
||||||
|
obs2.getCode().setText("Diastolic Blood Pressure");
|
||||||
|
obs2.setStatus(Observation.ObservationStatus.FINAL);
|
||||||
|
obs2.setValue(new Quantity(81));
|
||||||
|
IIdType id2 = myObservationDao.create(obs2, mySrd).getId().toUnqualifiedVersionless();
|
||||||
|
|
||||||
|
SearchParameterMap map;
|
||||||
|
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add(ca.uhn.fhir.rest.api.Constants.PARAM_CONTENT, new StringParam("systolic"));
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1)));
|
||||||
|
|
||||||
|
map = new SearchParameterMap();
|
||||||
|
map.add(Constants.PARAM_CONTENT, new StringParam("blood"));
|
||||||
|
assertThat(toUnqualifiedVersionlessIdValues(myObservationDao.search(map)), containsInAnyOrder(toValues(id1, id2)));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandWithIsAInExternalValueSet() {
|
||||||
|
createExternalCsAndLocalVs();
|
||||||
|
|
||||||
|
ValueSet vs = new ValueSet();
|
||||||
|
ValueSet.ConceptSetComponent include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(URL_MY_CODE_SYSTEM);
|
||||||
|
include.addFilter().setOp(ValueSet.FilterOperator.ISA).setValue("childAA").setProperty("concept");
|
||||||
|
|
||||||
|
ValueSet result = myValueSetDao.expand(vs, null);
|
||||||
|
logAndValidateValueSet(result);
|
||||||
|
|
||||||
|
ArrayList<String> codes = toCodesContains(result.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("childAAA", "childAAB"));
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private CodeSystem createExternalCs() {
|
||||||
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
|
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||||
|
codeSystem.setContent(CodeSystem.CodeSystemContentMode.NOTPRESENT);
|
||||||
|
IIdType id = myCodeSystemDao.create(codeSystem, mySrd).getId().toUnqualified();
|
||||||
|
|
||||||
|
ResourceTable table = myResourceTableDao.findById(id.getIdPartAsLong()).orElseThrow(IllegalStateException::new);
|
||||||
|
|
||||||
|
TermCodeSystemVersion cs = new TermCodeSystemVersion();
|
||||||
|
cs.setResource(table);
|
||||||
|
|
||||||
|
TermConcept parentA = new TermConcept(cs, "ParentA").setDisplay("Parent A");
|
||||||
|
cs.getConcepts().add(parentA);
|
||||||
|
|
||||||
|
TermConcept childAA = new TermConcept(cs, "childAA").setDisplay("Child AA");
|
||||||
|
parentA.addChild(childAA, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept childAAA = new TermConcept(cs, "childAAA").setDisplay("Child AAA");
|
||||||
|
childAA.addChild(childAAA, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept childAAB = new TermConcept(cs, "childAAB").setDisplay("Child AAB");
|
||||||
|
childAA.addChild(childAAB, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept childAB = new TermConcept(cs, "childAB").setDisplay("Child AB");
|
||||||
|
parentA.addChild(childAB, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept parentB = new TermConcept(cs, "ParentB").setDisplay("Parent B");
|
||||||
|
cs.getConcepts().add(parentB);
|
||||||
|
|
||||||
|
TermConcept childBA = new TermConcept(cs, "childBA").setDisplay("Child BA");
|
||||||
|
childBA.addChild(childAAB, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
|
parentB.addChild(childBA, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
TermConcept parentC = new TermConcept(cs, "ParentC").setDisplay("Parent C");
|
||||||
|
cs.getConcepts().add(parentC);
|
||||||
|
|
||||||
|
TermConcept childCA = new TermConcept(cs, "childCA").setDisplay("Child CA");
|
||||||
|
parentC.addChild(childCA, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
|
|
||||||
|
myTermSvc.storeNewCodeSystemVersion(table.getId(), URL_MY_CODE_SYSTEM, "SYSTEM NAME", "SYSTEM VERSION", cs, table);
|
||||||
|
return codeSystem;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createExternalCsAndLocalVs() {
|
||||||
|
CodeSystem codeSystem = createExternalCs();
|
||||||
|
|
||||||
|
createLocalVs(codeSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void createLocalVs(CodeSystem codeSystem) {
|
||||||
|
ValueSet valueSet = new ValueSet();
|
||||||
|
valueSet.setUrl(URL_MY_VALUE_SET);
|
||||||
|
valueSet.getCompose().addInclude().setSystem(codeSystem.getUrl());
|
||||||
|
myValueSetDao.create(valueSet, mySrd);
|
||||||
|
}
|
||||||
|
|
||||||
|
private ArrayList<String> toCodesContains(List<ValueSet.ValueSetExpansionContainsComponent> theContains) {
|
||||||
|
ArrayList<String> retVal = new ArrayList<String>();
|
||||||
|
for (ValueSet.ValueSetExpansionContainsComponent next : theContains) {
|
||||||
|
retVal.add(next.getCode());
|
||||||
|
}
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void logAndValidateValueSet(ValueSet theResult) {
|
||||||
|
IParser parser = myFhirCtx.newXmlParser().setPrettyPrint(true);
|
||||||
|
String encoded = parser.encodeResourceToString(theResult);
|
||||||
|
ourLog.info(encoded);
|
||||||
|
|
||||||
|
FhirValidator validator = myFhirCtx.newValidator();
|
||||||
|
validator.setValidateAgainstStandardSchema(true);
|
||||||
|
validator.setValidateAgainstStandardSchematron(true);
|
||||||
|
ValidationResult result = validator.validateWithResult(theResult);
|
||||||
|
|
||||||
|
assertEquals(0, result.getMessages().size());
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@AfterClass
|
||||||
|
public static void afterClassClearContext() {
|
||||||
|
TestUtil.clearAllStaticFieldsForUnitTest();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -1,9 +1,8 @@
|
||||||
package ca.uhn.fhir.jpa.dao.r4;
|
package ca.uhn.fhir.jpa.dao.r4;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.jpa.config.TestR4Config;
|
|
||||||
import ca.uhn.fhir.jpa.bulk.IBulkDataExportSvc;
|
import ca.uhn.fhir.jpa.bulk.IBulkDataExportSvc;
|
||||||
import ca.uhn.fhir.jpa.config.TestR4WithoutLuceneConfig;
|
import ca.uhn.fhir.jpa.config.TestR4WithLuceneDisabledConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.*;
|
import ca.uhn.fhir.jpa.dao.*;
|
||||||
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
import ca.uhn.fhir.jpa.search.ISearchCoordinatorSvc;
|
||||||
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
import ca.uhn.fhir.jpa.search.reindex.IResourceReindexingSvc;
|
||||||
|
@ -27,7 +26,6 @@ import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Qualifier;
|
import org.springframework.beans.factory.annotation.Qualifier;
|
||||||
import org.springframework.test.context.ContextConfiguration;
|
import org.springframework.test.context.ContextConfiguration;
|
||||||
import org.springframework.test.context.TestPropertySource;
|
|
||||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||||
import org.springframework.transaction.PlatformTransactionManager;
|
import org.springframework.transaction.PlatformTransactionManager;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
@ -40,7 +38,7 @@ import static org.junit.Assert.*;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
|
||||||
@RunWith(SpringJUnit4ClassRunner.class)
|
@RunWith(SpringJUnit4ClassRunner.class)
|
||||||
@ContextConfiguration(classes = {TestR4WithoutLuceneConfig.class})
|
@ContextConfiguration(classes = {TestR4WithLuceneDisabledConfig.class})
|
||||||
public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
|
public class FhirResourceDaoR4SearchWithLuceneDisabledTest extends BaseJpaTest {
|
||||||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchWithLuceneDisabledTest.class);
|
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(FhirResourceDaoR4SearchWithLuceneDisabledTest.class);
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() {
|
public void after() {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
|
myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
@ -128,7 +128,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateCodeOperationByResourceIdAndCodeableConceptWithExistingValueSetAndPreExpansionEnabled() {
|
public void testValidateCodeOperationByResourceIdAndCodeableConceptWithExistingValueSetAndPreExpansionEnabled() {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
UriType valueSetIdentifier = null;
|
UriType valueSetIdentifier = null;
|
||||||
IIdType id = myExtensionalVsId;
|
IIdType id = myExtensionalVsId;
|
||||||
|
@ -169,7 +169,7 @@ public class FhirResourceDaoR4ValueSetTest extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateCodeOperationByResourceIdAndCodeAndSystemWithExistingValueSetAndPreExpansionEnabled() {
|
public void testValidateCodeOperationByResourceIdAndCodeAndSystemWithExistingValueSetAndPreExpansionEnabled() {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
UriType valueSetIdentifier = null;
|
UriType valueSetIdentifier = null;
|
||||||
IIdType id = myExtensionalVsId;
|
IIdType id = myExtensionalVsId;
|
||||||
|
|
|
@ -140,7 +140,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
createLocalVsWithUnknownCode(codeSystem);
|
createLocalVsWithUnknownCode(codeSystem);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void createLocalCsAndVs() {
|
private void createLocalCs() {
|
||||||
CodeSystem codeSystem = new CodeSystem();
|
CodeSystem codeSystem = new CodeSystem();
|
||||||
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
codeSystem.setUrl(URL_MY_CODE_SYSTEM);
|
||||||
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
|
codeSystem.setContent(CodeSystemContentMode.COMPLETE);
|
||||||
|
@ -155,8 +155,6 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
|
.addConcept(new ConceptDefinitionComponent().setCode("BA").setDisplay("Code BA"))
|
||||||
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
|
.addConcept(new ConceptDefinitionComponent().setCode("BB").setDisplay("Code BB"));
|
||||||
myCodeSystemDao.create(codeSystem, mySrd);
|
myCodeSystemDao.create(codeSystem, mySrd);
|
||||||
|
|
||||||
createLocalVs(codeSystem);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -242,6 +240,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
|
|
||||||
// Include
|
// Include
|
||||||
vs = new ValueSet();
|
vs = new ValueSet();
|
||||||
|
vs.setUrl("http://www.example.org/vs");
|
||||||
vs.getCompose()
|
vs.getCompose()
|
||||||
.addInclude()
|
.addInclude()
|
||||||
.setSystem(CS_URL);
|
.setSystem(CS_URL);
|
||||||
|
@ -282,6 +281,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
|
|
||||||
// Include
|
// Include
|
||||||
vs = new ValueSet();
|
vs = new ValueSet();
|
||||||
|
vs.setUrl("http://www.example.org/vs");
|
||||||
vs.getCompose()
|
vs.getCompose()
|
||||||
.addInclude()
|
.addInclude()
|
||||||
.setSystem(CS_URL);
|
.setSystem(CS_URL);
|
||||||
|
@ -329,7 +329,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByIdWithPreExpansion() throws Exception {
|
public void testExpandByIdWithPreExpansion() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -445,7 +445,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByUrlWithPreExpansion() throws Exception {
|
public void testExpandByUrlWithPreExpansion() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -468,7 +468,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception {
|
public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -746,7 +746,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
|
public void testValidateCodeOperationByCodeAndSystemInstanceOnInstance() throws IOException {
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
|
|
||||||
createLocalCsAndVs();
|
createLocalCs();
|
||||||
createLocalVsWithIncludeConcept();
|
createLocalVsWithIncludeConcept();
|
||||||
|
|
||||||
String url = ourServerBase +
|
String url = ourServerBase +
|
||||||
|
@ -789,7 +789,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
* Technically this is the wrong param name
|
* Technically this is the wrong param name
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testValiedateCodeAgainstBuiltInSystem() throws Exception {
|
public void testValidateCodeAgainstBuiltInSystem() throws Exception {
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
|
|
||||||
Parameters respParam = ourClient
|
Parameters respParam = ourClient
|
||||||
|
@ -819,7 +819,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
* Technically this is the right param name
|
* Technically this is the right param name
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testValiedateCodeAgainstBuiltInSystemByUrl() throws Exception {
|
public void testValidateCodeAgainstBuiltInSystemByUrl() throws Exception {
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
|
|
||||||
Parameters respParam = ourClient
|
Parameters respParam = ourClient
|
||||||
|
@ -847,7 +847,7 @@ public class ResourceProviderDstu3ValueSetTest extends BaseResourceProviderDstu3
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void afterResetPreExpansionDefault() {
|
public void afterResetPreExpansionDefault() {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
|
myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -4,21 +4,20 @@ import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||||
|
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.auth.*;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.IAuthRule;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.PolicyEnum;
|
|
||||||
import ca.uhn.fhir.rest.server.interceptor.auth.RuleBuilder;
|
|
||||||
import ca.uhn.fhir.util.TestUtil;
|
import ca.uhn.fhir.util.TestUtil;
|
||||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||||
import org.apache.http.client.methods.HttpDelete;
|
import org.apache.http.client.methods.HttpDelete;
|
||||||
import org.apache.http.client.methods.HttpPost;
|
import org.apache.http.client.methods.HttpPost;
|
||||||
import org.apache.http.entity.ContentType;
|
import org.apache.http.entity.ContentType;
|
||||||
import org.apache.http.entity.StringEntity;
|
import org.apache.http.entity.StringEntity;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.*;
|
import org.hl7.fhir.r4.model.*;
|
||||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||||
|
@ -102,7 +101,7 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testCreateConditional() {
|
public void testUpdateConditional() {
|
||||||
|
|
||||||
Patient patient = new Patient();
|
Patient patient = new Patient();
|
||||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||||
|
@ -150,6 +149,99 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testCreateConditionalViaTransaction() {
|
||||||
|
ourRestServer.getInterceptorService().registerInterceptor(new AuthorizationInterceptor(PolicyEnum.DENY) {
|
||||||
|
@Override
|
||||||
|
public List<IAuthRule> buildRuleList(RequestDetails theRequestDetails) {
|
||||||
|
return new RuleBuilder()
|
||||||
|
.allow().create().resourcesOfType("Patient").withAnyId().withTester(new IAuthRuleTester() {
|
||||||
|
@Override
|
||||||
|
public boolean matches(RestOperationTypeEnum theOperation, RequestDetails theRequestDetails, IIdType theInputResourceId, IBaseResource theInputResource) {
|
||||||
|
if (theInputResource instanceof Patient) {
|
||||||
|
Patient patient = (Patient) theInputResource;
|
||||||
|
return patient
|
||||||
|
.getIdentifier()
|
||||||
|
.stream()
|
||||||
|
.filter(t-> "http://uhn.ca/mrns".equals(t.getSystem()))
|
||||||
|
.anyMatch(t-> "100".equals(t.getValue()));
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}).andThen()
|
||||||
|
.allow().createConditional().resourcesOfType("Patient").andThen()
|
||||||
|
.allow().transaction().withAnyOperation().andApplyNormalRules().andThen()
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a patient (allowed)
|
||||||
|
{
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||||
|
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||||
|
|
||||||
|
Bundle request = new Bundle();
|
||||||
|
request.setType(Bundle.BundleType.TRANSACTION);
|
||||||
|
request.addEntry()
|
||||||
|
.setResource(patient)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(Bundle.HTTPVerb.POST)
|
||||||
|
.setIfNoneExist("Patient?identifier=http://uhn.ca/mrns|100");
|
||||||
|
Bundle response = ourClient.transaction().withBundle(request).execute();
|
||||||
|
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(response));
|
||||||
|
|
||||||
|
// Subsequent calls also shouldn't fail
|
||||||
|
ourClient.transaction().withBundle(request).execute();
|
||||||
|
ourClient.transaction().withBundle(request).execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a patient with wrong identifier (blocked)
|
||||||
|
{
|
||||||
|
Patient patient = new Patient();
|
||||||
|
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("101");
|
||||||
|
patient.addName().setFamily("Tester").addGiven("Fozzie");
|
||||||
|
|
||||||
|
Bundle request = new Bundle();
|
||||||
|
request.setType(Bundle.BundleType.TRANSACTION);
|
||||||
|
request.addEntry()
|
||||||
|
.setResource(patient)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(Bundle.HTTPVerb.POST)
|
||||||
|
.setIfNoneExist("Patient?identifier=http://uhn.ca/mrns|101");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ourClient.transaction().withBundle(request).execute();
|
||||||
|
fail();
|
||||||
|
} catch (ForbiddenOperationException e) {
|
||||||
|
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create an organization (blocked)
|
||||||
|
{
|
||||||
|
Organization patient = new Organization();
|
||||||
|
patient.setName("FOO");
|
||||||
|
|
||||||
|
Bundle request = new Bundle();
|
||||||
|
request.setType(Bundle.BundleType.TRANSACTION);
|
||||||
|
request.addEntry()
|
||||||
|
.setResource(patient)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(Bundle.HTTPVerb.POST)
|
||||||
|
.setIfNoneExist("Organization?name=FOO");
|
||||||
|
|
||||||
|
try {
|
||||||
|
ourClient.transaction().withBundle(request).execute();
|
||||||
|
fail();
|
||||||
|
} catch (ForbiddenOperationException e) {
|
||||||
|
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testReadInTransaction() {
|
public void testReadInTransaction() {
|
||||||
|
|
||||||
|
|
|
@ -70,6 +70,7 @@ import java.nio.charset.StandardCharsets;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static ca.uhn.fhir.jpa.util.TestUtil.sleepAtLeast;
|
||||||
import static ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick;
|
import static ca.uhn.fhir.jpa.util.TestUtil.sleepOneClick;
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
import static org.hamcrest.Matchers.*;
|
import static org.hamcrest.Matchers.*;
|
||||||
|
@ -846,7 +847,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void interceptResponse(IHttpResponse theResponse) { // TODO Auto-generated method stu
|
public void interceptResponse(IHttpResponse theResponse) { // TODO Auto-generated method stub
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
@ -3900,10 +3901,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
}
|
}
|
||||||
ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute();
|
ourClient.transaction().withResources(resources).prettyPrint().encodedXml().execute();
|
||||||
|
|
||||||
/*
|
|
||||||
* First, make sure that we don't reuse a search if
|
|
||||||
* it's not marked with an expiry
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(10L);
|
myDaoConfig.setReuseCachedSearchResultsForMillis(10L);
|
||||||
Bundle result1 = ourClient
|
Bundle result1 = ourClient
|
||||||
|
@ -3912,7 +3910,7 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
final String uuid1 = toSearchUuidFromLinkNext(result1);
|
final String uuid1 = toSearchUuidFromLinkNext(result1);
|
||||||
sleepOneClick();
|
sleepAtLeast(11L);
|
||||||
Bundle result2 = ourClient
|
Bundle result2 = ourClient
|
||||||
.search()
|
.search()
|
||||||
.forResource("Organization")
|
.forResource("Organization")
|
||||||
|
@ -3922,10 +3920,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
assertNotEquals(uuid1, uuid2);
|
assertNotEquals(uuid1, uuid2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Now try one but mark it with an expiry time
|
|
||||||
* in the future
|
|
||||||
*/
|
|
||||||
{
|
{
|
||||||
myDaoConfig.setReuseCachedSearchResultsForMillis(1000L);
|
myDaoConfig.setReuseCachedSearchResultsForMillis(1000L);
|
||||||
Bundle result1 = ourClient
|
Bundle result1 = ourClient
|
||||||
|
@ -3946,7 +3940,6 @@ public class ResourceProviderR4Test extends BaseResourceProviderR4Test {
|
||||||
.returnBundle(Bundle.class)
|
.returnBundle(Bundle.class)
|
||||||
.execute();
|
.execute();
|
||||||
|
|
||||||
// Expiry doesn't affect reusablility
|
|
||||||
final String uuid2 = toSearchUuidFromLinkNext(result2);
|
final String uuid2 = toSearchUuidFromLinkNext(result2);
|
||||||
assertEquals(uuid1, uuid2);
|
assertEquals(uuid1, uuid2);
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,7 @@ package ca.uhn.fhir.jpa.provider.r4;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||||
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
import ca.uhn.fhir.jpa.dao.data.IResourceTableDao;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.*;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
import ca.uhn.fhir.jpa.term.IHapiTerminologySvc;
|
||||||
|
@ -36,6 +35,7 @@ import org.springframework.transaction.support.TransactionTemplate;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM;
|
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_CODE_SYSTEM;
|
||||||
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
|
import static ca.uhn.fhir.jpa.dao.r4.FhirResourceDaoR4TerminologyTest.URL_MY_VALUE_SET;
|
||||||
|
@ -57,12 +57,28 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
loadAndPersistValueSet(theVerb);
|
loadAndPersistValueSet(theVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb theVerb) throws IOException {
|
||||||
|
loadAndPersistCodeSystemWithDesignations(theVerb);
|
||||||
|
loadAndPersistValueSet(theVerb);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb theVerb) throws IOException {
|
||||||
|
loadAndPersistCodeSystemWithDesignations(theVerb);
|
||||||
|
loadAndPersistValueSetWithExclude(theVerb);
|
||||||
|
}
|
||||||
|
|
||||||
private void loadAndPersistCodeSystem(HttpVerb theVerb) throws IOException {
|
private void loadAndPersistCodeSystem(HttpVerb theVerb) throws IOException {
|
||||||
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs.xml");
|
||||||
codeSystem.setId("CodeSystem/cs");
|
codeSystem.setId("CodeSystem/cs");
|
||||||
persistCodeSystem(codeSystem, theVerb);
|
persistCodeSystem(codeSystem, theVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndPersistCodeSystemWithDesignations(HttpVerb theVerb) throws IOException {
|
||||||
|
CodeSystem codeSystem = loadResourceFromClasspath(CodeSystem.class, "/extensional-case-3-cs-with-designations.xml");
|
||||||
|
codeSystem.setId("CodeSystem/cs");
|
||||||
|
persistCodeSystem(codeSystem, theVerb);
|
||||||
|
}
|
||||||
|
|
||||||
private void persistCodeSystem(CodeSystem theCodeSystem, HttpVerb theVerb) {
|
private void persistCodeSystem(CodeSystem theCodeSystem, HttpVerb theVerb) {
|
||||||
switch (theVerb) {
|
switch (theVerb) {
|
||||||
case POST:
|
case POST:
|
||||||
|
@ -93,6 +109,12 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
persistValueSet(valueSet, theVerb);
|
persistValueSet(valueSet, theVerb);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadAndPersistValueSetWithExclude(HttpVerb theVerb) throws IOException {
|
||||||
|
ValueSet valueSet = loadResourceFromClasspath(ValueSet.class, "/extensional-case-3-vs-with-exclude.xml");
|
||||||
|
valueSet.setId("ValueSet/vs");
|
||||||
|
persistValueSet(valueSet, theVerb);
|
||||||
|
}
|
||||||
|
|
||||||
private void persistValueSet(ValueSet theValueSet, HttpVerb theVerb) {
|
private void persistValueSet(ValueSet theValueSet, HttpVerb theVerb) {
|
||||||
switch (theVerb) {
|
switch (theVerb) {
|
||||||
case POST:
|
case POST:
|
||||||
|
@ -222,7 +244,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByIdWithPreExpansion() throws Exception {
|
public void testExpandByIdWithPreExpansion() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -274,7 +296,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByIdWithFilterWithPreExpansion() throws Exception {
|
public void testExpandByIdWithFilterWithPreExpansion() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -333,7 +355,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByUrlWithPreExpansion() throws Exception {
|
public void testExpandByUrlWithPreExpansion() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -356,7 +378,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception {
|
public void testExpandByUrlWithPreExpansionAndBogusUrl() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -398,7 +420,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandByValueSetWithPreExpansion() throws IOException {
|
public void testExpandByValueSetWithPreExpansion() throws IOException {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystem(HttpVerb.POST);
|
loadAndPersistCodeSystem(HttpVerb.POST);
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
@ -687,6 +709,168 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateValueSetTriggersAnotherPreExpansion() throws Exception {
|
||||||
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
|
||||||
|
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
|
||||||
|
|
||||||
|
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
||||||
|
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
||||||
|
|
||||||
|
String initialValueSetName = valueSet.getName();
|
||||||
|
validateTermValueSetNotExpanded(initialValueSetName);
|
||||||
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
validateTermValueSetExpandedAndChildren(initialValueSetName, codeSystem);
|
||||||
|
|
||||||
|
ValueSet updatedValueSet = valueSet;
|
||||||
|
updatedValueSet.setName(valueSet.getName().concat(" - MODIFIED"));
|
||||||
|
persistValueSet(updatedValueSet, HttpVerb.PUT);
|
||||||
|
updatedValueSet = myValueSetDao.read(myExtensionalVsId);
|
||||||
|
ourLog.info("Updated ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(updatedValueSet));
|
||||||
|
|
||||||
|
String updatedValueSetName = valueSet.getName();
|
||||||
|
validateTermValueSetNotExpanded(updatedValueSetName);
|
||||||
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
validateTermValueSetExpandedAndChildren(updatedValueSetName, codeSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUpdateValueSetTriggersAnotherPreExpansionUsingTransactionBundle() throws Exception {
|
||||||
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
|
||||||
|
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
|
||||||
|
|
||||||
|
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
||||||
|
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
||||||
|
|
||||||
|
String initialValueSetName = valueSet.getName();
|
||||||
|
validateTermValueSetNotExpanded(initialValueSetName);
|
||||||
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
validateTermValueSetExpandedAndChildren(initialValueSetName, codeSystem);
|
||||||
|
|
||||||
|
ValueSet updatedValueSet = valueSet;
|
||||||
|
updatedValueSet.setName(valueSet.getName().concat(" - MODIFIED"));
|
||||||
|
|
||||||
|
String url = ourClient.getServerBase().concat("/").concat(myExtensionalVsId.getValueAsString());
|
||||||
|
Bundle bundle = new Bundle();
|
||||||
|
bundle.setType(Bundle.BundleType.TRANSACTION);
|
||||||
|
bundle
|
||||||
|
.addEntry()
|
||||||
|
.setFullUrl(url)
|
||||||
|
.setResource(updatedValueSet)
|
||||||
|
.getRequest()
|
||||||
|
.setMethod(Bundle.HTTPVerb.PUT)
|
||||||
|
.setUrl(url);
|
||||||
|
ourLog.info("Transaction Bundle:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||||
|
ourClient.transaction().withBundle(bundle).execute();
|
||||||
|
|
||||||
|
updatedValueSet = myValueSetDao.read(myExtensionalVsId);
|
||||||
|
ourLog.info("Updated ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(updatedValueSet));
|
||||||
|
|
||||||
|
String updatedValueSetName = valueSet.getName();
|
||||||
|
validateTermValueSetNotExpanded(updatedValueSetName);
|
||||||
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
validateTermValueSetExpandedAndChildren(updatedValueSetName, codeSystem);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateTermValueSetNotExpanded(String theValueSetName) {
|
||||||
|
runInTransaction(()->{
|
||||||
|
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable);
|
||||||
|
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||||
|
|
||||||
|
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||||
|
assertTrue(optionalValueSetByUrl.isPresent());
|
||||||
|
|
||||||
|
TermValueSet termValueSet = optionalValueSetByUrl.get();
|
||||||
|
assertSame(optionalValueSetByResourcePid.get(), termValueSet);
|
||||||
|
ourLog.info("ValueSet:\n" + termValueSet.toString());
|
||||||
|
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl());
|
||||||
|
assertEquals(theValueSetName, termValueSet.getName());
|
||||||
|
assertEquals(0, termValueSet.getConcepts().size());
|
||||||
|
assertEquals(TermValueSetPreExpansionStatusEnum.NOT_EXPANDED, termValueSet.getExpansionStatus());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private void validateTermValueSetExpandedAndChildren(String theValueSetName, CodeSystem theCodeSystem) {
|
||||||
|
runInTransaction(()->{
|
||||||
|
Optional<TermValueSet> optionalValueSetByResourcePid = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable);
|
||||||
|
assertTrue(optionalValueSetByResourcePid.isPresent());
|
||||||
|
|
||||||
|
Optional<TermValueSet> optionalValueSetByUrl = myTermValueSetDao.findByUrl("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2");
|
||||||
|
assertTrue(optionalValueSetByUrl.isPresent());
|
||||||
|
|
||||||
|
TermValueSet termValueSet = optionalValueSetByUrl.get();
|
||||||
|
assertSame(optionalValueSetByResourcePid.get(), termValueSet);
|
||||||
|
ourLog.info("ValueSet:\n" + termValueSet.toString());
|
||||||
|
assertEquals("http://www.healthintersections.com.au/fhir/ValueSet/extensional-case-2", termValueSet.getUrl());
|
||||||
|
assertEquals(theValueSetName, termValueSet.getName());
|
||||||
|
assertEquals(theCodeSystem.getConcept().size(), termValueSet.getConcepts().size());
|
||||||
|
assertEquals(TermValueSetPreExpansionStatusEnum.EXPANDED, termValueSet.getExpansionStatus());
|
||||||
|
|
||||||
|
TermValueSetConcept concept = termValueSet.getConcepts().get(0);
|
||||||
|
ourLog.info("Concept:\n" + concept.toString());
|
||||||
|
assertEquals("http://acme.org", concept.getSystem());
|
||||||
|
assertEquals("8450-9", concept.getCode());
|
||||||
|
assertEquals("Systolic blood pressure--expiration", concept.getDisplay());
|
||||||
|
assertEquals(2, concept.getDesignations().size());
|
||||||
|
assertEquals(0, concept.getOrder());
|
||||||
|
|
||||||
|
TermValueSetConceptDesignation designation = concept.getDesignations().get(0);
|
||||||
|
assertEquals("nl", designation.getLanguage());
|
||||||
|
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||||
|
assertEquals("900000000000013009", designation.getUseCode());
|
||||||
|
assertEquals("Synonym", designation.getUseDisplay());
|
||||||
|
assertEquals("Systolische bloeddruk - expiratie", designation.getValue());
|
||||||
|
|
||||||
|
designation = concept.getDesignations().get(1);
|
||||||
|
assertEquals("sv", designation.getLanguage());
|
||||||
|
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||||
|
assertEquals("900000000000013009", designation.getUseCode());
|
||||||
|
assertEquals("Synonym", designation.getUseDisplay());
|
||||||
|
assertEquals("Systoliskt blodtryck - utgång", designation.getValue());
|
||||||
|
|
||||||
|
concept = termValueSet.getConcepts().get(1);
|
||||||
|
ourLog.info("Concept:\n" + concept.toString());
|
||||||
|
assertEquals("http://acme.org", concept.getSystem());
|
||||||
|
assertEquals("11378-7", concept.getCode());
|
||||||
|
assertEquals("Systolic blood pressure at First encounter", concept.getDisplay());
|
||||||
|
assertEquals(0, concept.getDesignations().size());
|
||||||
|
assertEquals(1, concept.getOrder());
|
||||||
|
|
||||||
|
// ...
|
||||||
|
|
||||||
|
concept = termValueSet.getConcepts().get(22);
|
||||||
|
ourLog.info("Concept:\n" + concept.toString());
|
||||||
|
assertEquals("http://acme.org", concept.getSystem());
|
||||||
|
assertEquals("8491-3", concept.getCode());
|
||||||
|
assertEquals("Systolic blood pressure 1 hour minimum", concept.getDisplay());
|
||||||
|
assertEquals(1, concept.getDesignations().size());
|
||||||
|
assertEquals(22, concept.getOrder());
|
||||||
|
|
||||||
|
designation = concept.getDesignations().get(0);
|
||||||
|
assertEquals("nl", designation.getLanguage());
|
||||||
|
assertEquals("http://snomed.info/sct", designation.getUseSystem());
|
||||||
|
assertEquals("900000000000013009", designation.getUseCode());
|
||||||
|
assertEquals("Synonym", designation.getUseDisplay());
|
||||||
|
assertEquals("Systolische bloeddruk minimaal 1 uur", designation.getValue());
|
||||||
|
|
||||||
|
concept = termValueSet.getConcepts().get(23);
|
||||||
|
ourLog.info("Concept:\n" + concept.toString());
|
||||||
|
assertEquals("http://acme.org", concept.getSystem());
|
||||||
|
assertEquals("8492-1", concept.getCode());
|
||||||
|
assertEquals("Systolic blood pressure 8 hour minimum", concept.getDisplay());
|
||||||
|
assertEquals(0, concept.getDesignations().size());
|
||||||
|
assertEquals(23, concept.getOrder());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception {
|
public void testValidateCodeOperationByCodeAndSystemInstance() throws Exception {
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
|
@ -767,7 +951,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValiedateCodeAgainstBuiltInSystem() {
|
public void testValidateCodeAgainstBuiltInSystem() {
|
||||||
Parameters respParam = ourClient
|
Parameters respParam = ourClient
|
||||||
.operation()
|
.operation()
|
||||||
.onType(ValueSet.class)
|
.onType(ValueSet.class)
|
||||||
|
@ -839,7 +1023,7 @@ public class ResourceProviderR4ValueSetTest extends BaseResourceProviderR4Test {
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void afterResetPreExpansionDefault() {
|
public void afterResetPreExpansionDefault() {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
|
myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets());
|
||||||
}
|
}
|
||||||
|
|
||||||
@AfterClass
|
@AfterClass
|
||||||
|
|
|
@ -90,9 +90,7 @@ public class TerminologyLoaderSvcLoincTest extends BaseLoaderTest {
|
||||||
|
|
||||||
// LOINC code with 3rd party copyright
|
// LOINC code with 3rd party copyright
|
||||||
code = concepts.get("47239-9");
|
code = concepts.get("47239-9");
|
||||||
// FIXME: DM 2019-09-13 - We presently truncate down to 500. The longest value for EXTERNAL_COPYRIGHT_NOTICE is 2,597 so we should use a LOB instead of a String.
|
String expectedExternalCopyrightNotice = "Copyright © 2006 World Health Organization. Used with permission. Publications of the World Health Organization can be obtained from WHO Press, World Health Organization, 20 Avenue Appia, 1211 Geneva 27, Switzerland (tel: +41 22 791 2476; fax: +41 22 791 4857; email: bookorders@who.int). Requests for permission to reproduce or translate WHO publications – whether for sale or for noncommercial distribution – should be addressed to WHO Press, at the above address (fax: +41 22 791 4806; email: permissions@who.int). The designations employed and the presentation of the material in this publication do not imply the expression of any opinion whatsoever on the part of the World Health Organization concerning the legal status of any country, territory, city or area or of its authorities, or concerning the delimitation of its frontiers or boundaries. Dotted lines on maps represent approximate border lines for which there may not yet be full agreement. The mention of specific companies or of certain manufacturers’ products does not imply that they are endorsed or recommended by the World Health Organization in preference to others of a similar nature that are not mentioned. Errors and omissions excepted, the names of proprietary products are distinguished by initial capital letters. All reasonable precautions have been taken by WHO to verify the information contained in this publication. However, the published material is being distributed without warranty of any kind, either express or implied. The responsibility for the interpretation and use of the material lies with the reader. In no event shall the World Health Organization be liable for damages arising from its use.";
|
||||||
// String expectedExternalCopyrightNotice = "Copyright © 2006 World Health Organization. Used with permission. Publications of the World Health Organization can be obtained from WHO Press, World Health Organization, 20 Avenue Appia, 1211 Geneva 27, Switzerland (tel: +41 22 791 2476; fax: +41 22 791 4857; email: bookorders@who.int). Requests for permission to reproduce or translate WHO publications – whether for sale or for noncommercial distribution – should be addressed to WHO Press, at the above address (fax: +41 22 791 4806; email: permissions@who.int). The designations employed and the presentation of the material in this publication do not imply the expression of any opinion whatsoever on the part of the World Health Organization concerning the legal status of any country, territory, city or area or of its authorities, or concerning the delimitation of its frontiers or boundaries. Dotted lines on maps represent approximate border lines for which there may not yet be full agreement. The mention of specific companies or of certain manufacturers’ products does not imply that they are endorsed or recommended by the World Health Organization in preference to others of a similar nature that are not mentioned. Errors and omissions excepted, the names of proprietary products are distinguished by initial capital letters. All reasonable precautions have been taken by WHO to verify the information contained in this publication. However, the published material is being distributed without warranty of any kind, either express or implied. The responsibility for the interpretation and use of the material lies with the reader. In no event shall the World Health Organization be liable for damages arising from its use.";
|
|
||||||
String expectedExternalCopyrightNotice = "Copyright © 2006 World Health Organization. Used with permission. Publications of the World Health Organization can be obtained from WHO Press, World Health Organization, 20 Avenue Appia, 1211 Geneva 27, Switzerland (tel: +41 22 791 2476; fax: +41 22 791 4857; email: bookorders@who.int). Requests for permission to reproduce or translate WHO publications – whether for sale or for noncommercial distribution – should be addressed to WHO Press, at the above address (fax: +41 22 791 4806; email: perm";
|
|
||||||
assertEquals(expectedExternalCopyrightNotice, code.getStringProperty("EXTERNAL_COPYRIGHT_NOTICE"));
|
assertEquals(expectedExternalCopyrightNotice, code.getStringProperty("EXTERNAL_COPYRIGHT_NOTICE"));
|
||||||
|
|
||||||
// Answer list
|
// Answer list
|
||||||
|
|
|
@ -5,6 +5,7 @@ import ca.uhn.fhir.jpa.dao.dstu3.BaseJpaDstu3Test;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystem;
|
||||||
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
import ca.uhn.fhir.jpa.entity.TermCodeSystemVersion;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConcept;
|
import ca.uhn.fhir.jpa.entity.TermConcept;
|
||||||
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink;
|
||||||
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
import ca.uhn.fhir.jpa.entity.TermConceptParentChildLink.RelationshipTypeEnum;
|
||||||
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
import ca.uhn.fhir.jpa.model.entity.ResourceTable;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
@ -17,9 +18,8 @@ import org.hl7.fhir.dstu3.model.CodeSystem;
|
||||||
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
import org.hl7.fhir.dstu3.model.CodeSystem.CodeSystemContentMode;
|
||||||
import org.hl7.fhir.instance.model.api.IIdType;
|
import org.hl7.fhir.instance.model.api.IIdType;
|
||||||
import org.hl7.fhir.r4.model.ValueSet;
|
import org.hl7.fhir.r4.model.ValueSet;
|
||||||
import org.junit.After;
|
import org.junit.*;
|
||||||
import org.junit.AfterClass;
|
import org.junit.rules.ExpectedException;
|
||||||
import org.junit.Test;
|
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.transaction.TransactionStatus;
|
import org.springframework.transaction.TransactionStatus;
|
||||||
|
@ -38,6 +38,9 @@ import static org.junit.Assert.*;
|
||||||
public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcImplDstu3Test.class);
|
private static final Logger ourLog = LoggerFactory.getLogger(TerminologySvcImplDstu3Test.class);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public final ExpectedException expectedException = ExpectedException.none();
|
||||||
|
|
||||||
private static final String CS_URL = "http://example.com/my_code_system";
|
private static final String CS_URL = "http://example.com/my_code_system";
|
||||||
private static final String CS_URL_2 = "http://example.com/my_code_system2";
|
private static final String CS_URL_2 = "http://example.com/my_code_system2";
|
||||||
|
|
||||||
|
@ -145,6 +148,7 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
LOINC_URI,
|
LOINC_URI,
|
||||||
code2.getCode(),
|
code2.getCode(),
|
||||||
code2.getDisplay());
|
code2.getDisplay());
|
||||||
|
code1.addChild(code2, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
cs.getConcepts().add(code1);
|
cs.getConcepts().add(code1);
|
||||||
|
|
||||||
code2.addPropertyString("SYSTEM", "Ser");
|
code2.addPropertyString("SYSTEM", "Ser");
|
||||||
|
@ -159,11 +163,13 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
LOINC_URI,
|
LOINC_URI,
|
||||||
code3.getCode(),
|
code3.getCode(),
|
||||||
code3.getDisplay());
|
code3.getDisplay());
|
||||||
|
code2.addChild(code3, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
code2.addPropertyCoding(
|
code2.addPropertyCoding(
|
||||||
"child",
|
"child",
|
||||||
LOINC_URI,
|
LOINC_URI,
|
||||||
code4.getCode(),
|
code4.getCode(),
|
||||||
code4.getDisplay());
|
code4.getDisplay());
|
||||||
|
code2.addChild(code4, TermConceptParentChildLink.RelationshipTypeEnum.ISA);
|
||||||
cs.getConcepts().add(code2);
|
cs.getConcepts().add(code2);
|
||||||
|
|
||||||
code3.addPropertyString("SYSTEM", "Ser");
|
code3.addPropertyString("SYSTEM", "Ser");
|
||||||
|
@ -306,7 +312,6 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
outcome = myTermSvc.expandValueSet(vs);
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
codes = toCodesContains(outcome.getExpansion().getContains());
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
assertThat(codes, empty());
|
assertThat(codes, empty());
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -485,12 +490,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
.setProperty("copyright")
|
.setProperty("copyright")
|
||||||
.setOp(ValueSet.FilterOperator.ISA)
|
.setOp(ValueSet.FilterOperator.ISA)
|
||||||
.setValue("LOINC");
|
.setValue("LOINC");
|
||||||
try {
|
|
||||||
myTermSvc.expandValueSet(vs);
|
expectedException.expect(InvalidRequestException.class);
|
||||||
} catch (InvalidRequestException e) {
|
expectedException.expectMessage("Don't know how to handle op=ISA on property copyright");
|
||||||
assertEquals(400, e.getStatusCode());
|
myTermSvc.expandValueSet(vs);
|
||||||
assertEquals("Don't know how to handle op=ISA on property copyright", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -504,18 +507,16 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
// Include
|
// Include
|
||||||
vs = new ValueSet();
|
vs = new ValueSet();
|
||||||
include = vs.getCompose().addInclude();
|
include = vs.getCompose().addInclude();
|
||||||
include.setSystem(LOINC_URI);
|
include.setSystem(CS_URL);
|
||||||
include
|
include
|
||||||
.addFilter()
|
.addFilter()
|
||||||
.setProperty("copyright")
|
.setProperty("copyright")
|
||||||
.setOp(ValueSet.FilterOperator.EQUAL)
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
.setValue("LOINC");
|
.setValue("LOINC");
|
||||||
try {
|
|
||||||
myTermSvc.expandValueSet(vs);
|
expectedException.expect(InvalidRequestException.class);
|
||||||
} catch (InvalidRequestException e) {
|
expectedException.expectMessage("Invalid filter, property copyright is LOINC-specific and cannot be used with system: http://example.com/my_code_system");
|
||||||
assertEquals(400, e.getStatusCode());
|
myTermSvc.expandValueSet(vs);
|
||||||
assertEquals("Invalid filter, property copyright is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -534,12 +535,243 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
.setProperty("copyright")
|
.setProperty("copyright")
|
||||||
.setOp(ValueSet.FilterOperator.EQUAL)
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
.setValue("bogus");
|
.setValue("bogus");
|
||||||
try {
|
|
||||||
myTermSvc.expandValueSet(vs);
|
expectedException.expect(InvalidRequestException.class);
|
||||||
} catch (InvalidRequestException e) {
|
expectedException.expectMessage("Don't know how to handle value=bogus on property copyright");
|
||||||
assertEquals(400, e.getStatusCode());
|
myTermSvc.expandValueSet(vs);
|
||||||
assertEquals("Don't know how to handle value=bogus on property copyright", e.getMessage());
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincAncestorWithExcludeAndEqual() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent exclude;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("50015-7");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-3");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7", "43343-3"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-4");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincAncestorWithExcludeAndIn() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent exclude;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.IN)
|
||||||
|
.setValue("50015-7,43343-3,43343-4,47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincAncestorWithIncludeAndEqual() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("50015-7");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-3");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("43343-4", "47239-9"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-4");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
assertEquals(0, outcome.getExpansion().getContains().size());
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
assertEquals(0, outcome.getExpansion().getContains().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincAncestorWithIncludeAndIn() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.IN)
|
||||||
|
.setValue("50015-7,43343-3,43343-4,47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincAncestorWithUnsupportedOp() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.ISA)
|
||||||
|
.setValue("50015-7");
|
||||||
|
|
||||||
|
expectedException.expect(InvalidRequestException.class);
|
||||||
|
expectedException.expectMessage("Don't know how to handle op=ISA on property ancestor");
|
||||||
|
myTermSvc.expandValueSet(vs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincAncestorWithUnsupportedSystem() {
|
||||||
|
createCodeSystem();
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(CS_URL);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("ancestor")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("50015-7");
|
||||||
|
|
||||||
|
expectedException.expect(InvalidRequestException.class);
|
||||||
|
expectedException.expectMessage("Invalid filter, property ancestor is LOINC-specific and cannot be used with system: http://example.com/my_code_system");
|
||||||
|
myTermSvc.expandValueSet(vs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -747,12 +979,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
.setProperty("child")
|
.setProperty("child")
|
||||||
.setOp(ValueSet.FilterOperator.ISA)
|
.setOp(ValueSet.FilterOperator.ISA)
|
||||||
.setValue("50015-7");
|
.setValue("50015-7");
|
||||||
try {
|
|
||||||
myTermSvc.expandValueSet(vs);
|
expectedException.expect(InvalidRequestException.class);
|
||||||
} catch (InvalidRequestException e) {
|
expectedException.expectMessage("Don't know how to handle op=ISA on property child");
|
||||||
assertEquals(400, e.getStatusCode());
|
myTermSvc.expandValueSet(vs);
|
||||||
assertEquals("Don't know how to handle op=ISA on property child", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -772,12 +1002,244 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
.setProperty("child")
|
.setProperty("child")
|
||||||
.setOp(ValueSet.FilterOperator.EQUAL)
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
.setValue("50015-7");
|
.setValue("50015-7");
|
||||||
try {
|
|
||||||
myTermSvc.expandValueSet(vs);
|
expectedException.expect(InvalidRequestException.class);
|
||||||
} catch (InvalidRequestException e) {
|
expectedException.expectMessage("Invalid filter, property child is LOINC-specific and cannot be used with system: http://example.com/my_code_system");
|
||||||
assertEquals(400, e.getStatusCode());
|
myTermSvc.expandValueSet(vs);
|
||||||
assertEquals("Invalid filter, property child is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage());
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincDescendantWithExcludeAndEqual() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent exclude;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("50015-7");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7", "43343-3", "43343-4", "47239-9"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-3");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("43343-3", "43343-4", "47239-9"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-4");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("43343-4", "47239-9"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("43343-4", "47239-9"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincDescendantWithExcludeAndIn() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent exclude;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
vs.getCompose()
|
||||||
|
.addInclude()
|
||||||
|
.setSystem(LOINC_URI);
|
||||||
|
// Exclude
|
||||||
|
exclude = vs.getCompose().addExclude();
|
||||||
|
exclude.setSystem(LOINC_URI);
|
||||||
|
exclude
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.IN)
|
||||||
|
.setValue("50015-7,43343-3,43343-4,47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("43343-4", "47239-9"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincDescendantWithIncludeAndEqual() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("50015-7");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
assertEquals(0, outcome.getExpansion().getContains().size());
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-3");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("43343-4");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7", "43343-3"));
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7", "43343-3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincDescendantWithIncludeAndIn() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
List<String> codes;
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet outcome;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.IN)
|
||||||
|
.setValue("50015-7,43343-3,43343-4,47239-9");
|
||||||
|
outcome = myTermSvc.expandValueSet(vs);
|
||||||
|
codes = toCodesContains(outcome.getExpansion().getContains());
|
||||||
|
assertThat(codes, containsInAnyOrder("50015-7", "43343-3"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincDescendantWithUnsupportedOp() {
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(LOINC_URI);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.ISA)
|
||||||
|
.setValue("50015-7");
|
||||||
|
|
||||||
|
expectedException.expect(InvalidRequestException.class);
|
||||||
|
expectedException.expectMessage("Don't know how to handle op=ISA on property descendant");
|
||||||
|
myTermSvc.expandValueSet(vs);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testExpandValueSetPropertyFilterLoincDescendantWithUnsupportedSystem() {
|
||||||
|
createCodeSystem();
|
||||||
|
createLoincSystemWithSomeCodes();
|
||||||
|
|
||||||
|
ValueSet vs;
|
||||||
|
ValueSet.ConceptSetComponent include;
|
||||||
|
|
||||||
|
// Include
|
||||||
|
vs = new ValueSet();
|
||||||
|
include = vs.getCompose().addInclude();
|
||||||
|
include.setSystem(CS_URL);
|
||||||
|
include
|
||||||
|
.addFilter()
|
||||||
|
.setProperty("descendant")
|
||||||
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
|
.setValue("50015-7");
|
||||||
|
|
||||||
|
expectedException.expect(InvalidRequestException.class);
|
||||||
|
expectedException.expectMessage("Invalid filter, property descendant is LOINC-specific and cannot be used with system: http://example.com/my_code_system");
|
||||||
|
myTermSvc.expandValueSet(vs);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -984,12 +1446,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
.setProperty("parent")
|
.setProperty("parent")
|
||||||
.setOp(ValueSet.FilterOperator.ISA)
|
.setOp(ValueSet.FilterOperator.ISA)
|
||||||
.setValue("50015-7");
|
.setValue("50015-7");
|
||||||
try {
|
|
||||||
myTermSvc.expandValueSet(vs);
|
expectedException.expect(InvalidRequestException.class);
|
||||||
} catch (InvalidRequestException e) {
|
expectedException.expectMessage("Don't know how to handle op=ISA on property parent");
|
||||||
assertEquals(400, e.getStatusCode());
|
myTermSvc.expandValueSet(vs);
|
||||||
assertEquals("Don't know how to handle op=ISA on property parent", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1009,12 +1469,10 @@ public class TerminologySvcImplDstu3Test extends BaseJpaDstu3Test {
|
||||||
.setProperty("parent")
|
.setProperty("parent")
|
||||||
.setOp(ValueSet.FilterOperator.EQUAL)
|
.setOp(ValueSet.FilterOperator.EQUAL)
|
||||||
.setValue("50015-7");
|
.setValue("50015-7");
|
||||||
try {
|
|
||||||
myTermSvc.expandValueSet(vs);
|
expectedException.expect(InvalidRequestException.class);
|
||||||
} catch (InvalidRequestException e) {
|
expectedException.expectMessage("Invalid filter, property parent is LOINC-specific and cannot be used with system: http://example.com/my_code_system");
|
||||||
assertEquals(400, e.getStatusCode());
|
myTermSvc.expandValueSet(vs);
|
||||||
assertEquals("Invalid filter, property parent is LOINC-specific and cannot be used with system: http://example.com/my_code_system", e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -65,7 +65,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
@After
|
@After
|
||||||
public void after() {
|
public void after() {
|
||||||
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
myDaoConfig.setAllowExternalReferences(new DaoConfig().isAllowExternalReferences());
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(new DaoConfig().isPreExpandValueSetsExperimental());
|
myDaoConfig.setPreExpandValueSets(new DaoConfig().isPreExpandValueSets());
|
||||||
}
|
}
|
||||||
|
|
||||||
private IIdType createCodeSystem() {
|
private IIdType createCodeSystem() {
|
||||||
|
@ -629,7 +629,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteValueSet() throws Exception {
|
public void testDeleteValueSet() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -641,7 +641,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get();
|
TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get();
|
||||||
|
@ -666,7 +666,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeleteValueSetWithClientAssignedId() throws Exception {
|
public void testDeleteValueSetWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -678,7 +678,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get();
|
TermValueSet termValueSet = myTermValueSetDao.findByResourcePid(myExtensionalVsIdOnResourceTable).get();
|
||||||
|
@ -723,7 +723,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDuplicateValueSetUrls() throws Exception {
|
public void testDuplicateValueSetUrls() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
// DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail.
|
// DM 2019-03-05 - We pre-load our custom CodeSystem otherwise pre-expansion of the ValueSet will fail.
|
||||||
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSet(HttpVerb.POST);
|
||||||
|
@ -736,7 +736,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildren() throws Exception {
|
public void testExpandTermValueSetAndChildren() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -750,7 +750,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myCaptureQueriesListener.clear();
|
myCaptureQueriesListener.clear();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
myCaptureQueriesListener.logSelectQueriesForCurrentThread();
|
||||||
|
@ -760,7 +760,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
assertThat(myCaptureQueriesListener.getDeleteQueriesForCurrentThread(), empty());
|
assertThat(myCaptureQueriesListener.getDeleteQueriesForCurrentThread(), empty());
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
||||||
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
||||||
|
@ -821,7 +821,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
public void testExpandExistingValueSetNotPreExpanded() throws Exception {
|
public void testExpandExistingValueSetNotPreExpanded() throws Exception {
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
|
CodeSystem codeSystem = myCodeSystemDao.read(myExtensionalCsId);
|
||||||
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
|
ourLog.info("CodeSystem:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(codeSystem));
|
||||||
|
@ -829,11 +829,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
ValueSet valueSet = myValueSetDao.read(myExtensionalVsId);
|
||||||
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
ourLog.info("ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(valueSet));
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().size());
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size());
|
||||||
|
@ -885,11 +885,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay());
|
assertEquals("Systolic blood pressure 8 hour minimum", containsComponent.getDisplay());
|
||||||
assertFalse(containsComponent.hasDesignation());
|
assertFalse(containsComponent.hasDesignation());
|
||||||
|
|
||||||
expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().size());
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getContains().size());
|
||||||
|
@ -944,7 +944,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithClientAssignedId() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -956,11 +956,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
||||||
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
||||||
|
@ -1019,7 +1019,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithCount() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithCount() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -1031,11 +1031,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 23);
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 23);
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
||||||
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
||||||
|
@ -1088,7 +1088,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithCountWithClientAssignedId() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithCountWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -1100,11 +1100,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 23);
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 23);
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
||||||
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
||||||
|
@ -1157,7 +1157,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithCountOfZero() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithCountOfZero() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -1169,11 +1169,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 0);
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 0);
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
||||||
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
||||||
|
@ -1185,7 +1185,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithCountOfZeroWithClientAssignedId() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithCountOfZeroWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -1197,11 +1197,11 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), 0);
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, myDaoConfig.getPreExpandValueSetsDefaultOffset(), 0);
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffsetExperimental(), expandedValueSet.getExpansion().getOffset());
|
assertEquals(myDaoConfig.getPreExpandValueSetsDefaultOffset(), expandedValueSet.getExpansion().getOffset());
|
||||||
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
assertEquals(2, expandedValueSet.getExpansion().getParameter().size());
|
||||||
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
assertEquals("offset", expandedValueSet.getExpansion().getParameter().get(0).getName());
|
||||||
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
assertEquals(0, expandedValueSet.getExpansion().getParameter().get(0).getValueIntegerType().getValue().intValue());
|
||||||
|
@ -1213,7 +1213,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithOffset() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithOffset() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -1225,7 +1225,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
|
@ -1274,7 +1274,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithOffsetWithClientAssignedId() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithOffsetWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -1286,7 +1286,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
myTermSvc.preExpandDeferredValueSetsToTerminologyTables();
|
||||||
|
|
||||||
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCountExperimental());
|
ValueSet expandedValueSet = myTermSvc.expandValueSet(valueSet, 1, myDaoConfig.getPreExpandValueSetsDefaultCount());
|
||||||
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
ourLog.info("Expanded ValueSet:\n" + myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(expandedValueSet));
|
||||||
|
|
||||||
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
assertEquals(codeSystem.getConcept().size(), expandedValueSet.getExpansion().getTotal());
|
||||||
|
@ -1335,7 +1335,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithOffsetAndCount() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithOffsetAndCount() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -1390,7 +1390,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testExpandTermValueSetAndChildrenWithOffsetAndCountWithClientAssignedId() throws Exception {
|
public void testExpandTermValueSetAndChildrenWithOffsetAndCountWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -2046,7 +2046,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStoreTermValueSetAndChildren() throws Exception {
|
public void testStoreTermValueSetAndChildren() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -2148,7 +2148,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStoreTermValueSetAndChildrenWithClientAssignedId() throws Exception {
|
public void testStoreTermValueSetAndChildrenWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -2250,7 +2250,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStoreTermValueSetAndChildrenWithExclude() throws Exception {
|
public void testStoreTermValueSetAndChildrenWithExclude() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -2352,7 +2352,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testStoreTermValueSetAndChildrenWithExcludeWithClientAssignedId() throws Exception {
|
public void testStoreTermValueSetAndChildrenWithExcludeWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignationsAndExclude(HttpVerb.PUT);
|
||||||
|
|
||||||
|
@ -3600,7 +3600,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateCodeIsInPreExpandedValueSet() throws Exception {
|
public void testValidateCodeIsInPreExpandedValueSet() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.POST);
|
||||||
|
|
||||||
|
@ -3650,7 +3650,7 @@ public class TerminologySvcImplR4Test extends BaseJpaR4Test {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateCodeIsInPreExpandedValueSetWithClientAssignedId() throws Exception {
|
public void testValidateCodeIsInPreExpandedValueSetWithClientAssignedId() throws Exception {
|
||||||
myDaoConfig.setPreExpandValueSetsExperimental(true);
|
myDaoConfig.setPreExpandValueSets(true);
|
||||||
|
|
||||||
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
loadAndPersistCodeSystemAndValueSetWithDesignations(HttpVerb.PUT);
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
<configuration>
|
<configuration>
|
||||||
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
|
||||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||||
<level>INFO</level>
|
<level>TRACE</level>
|
||||||
</filter>
|
</filter>
|
||||||
<encoder>
|
<encoder>
|
||||||
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
|
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} [%file:%line] %msg%n</pattern>
|
||||||
|
@ -40,6 +40,11 @@
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
</logger>
|
</logger>
|
||||||
|
|
||||||
|
<logger name="org.hibernate.search.elasticsearch.request" additivity="false" level="trace">
|
||||||
|
<appender-ref ref="STDOUT" />
|
||||||
|
</logger>
|
||||||
|
|
||||||
|
|
||||||
<root level="info">
|
<root level="info">
|
||||||
<appender-ref ref="STDOUT" />
|
<appender-ref ref="STDOUT" />
|
||||||
</root>
|
</root>
|
||||||
|
|
|
@ -1,23 +0,0 @@
|
||||||
<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>4.1.0-SNAPSHOT</version>
|
|
||||||
<relativePath>../hapi-deployable-pom/pom.xml</relativePath>
|
|
||||||
</parent>
|
|
||||||
|
|
||||||
<artifactId>hapi-fhir-jpaserver-elasticsearch</artifactId>
|
|
||||||
<packaging>jar</packaging>
|
|
||||||
|
|
||||||
<name>HAPI FHIR JPA Server - ElasticSearch Integration</name>
|
|
||||||
|
|
||||||
<dependencies>
|
|
||||||
<dependency>
|
|
||||||
<groupId>org.hibernate</groupId>
|
|
||||||
<artifactId>hibernate-search-elasticsearch</artifactId>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
|
||||||
|
|
||||||
</project>
|
|
|
@ -6,7 +6,7 @@ import javax.sql.DataSource;
|
||||||
|
|
||||||
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
|
import ca.uhn.fhir.jpa.config.BaseJavaConfigDstu3;
|
||||||
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
import ca.uhn.fhir.jpa.dao.DaoConfig;
|
||||||
import ca.uhn.fhir.jpa.search.ElasticsearchMappingProvider;
|
import ca.uhn.fhir.jpa.search.elastic.ElasticsearchMappingProvider;
|
||||||
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
|
import ca.uhn.fhir.jpa.util.SubscriptionsRequireManualActivationInterceptorDstu3;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.IServerInterceptor;
|
||||||
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
import ca.uhn.fhir.rest.server.interceptor.ResponseHighlighterInterceptor;
|
||||||
|
|
|
@ -29,7 +29,6 @@ import ca.uhn.fhir.jpa.migrate.tasks.api.BaseMigrationTasks;
|
||||||
import ca.uhn.fhir.jpa.model.entity.*;
|
import ca.uhn.fhir.jpa.model.entity.*;
|
||||||
import ca.uhn.fhir.util.VersionEnum;
|
import ca.uhn.fhir.util.VersionEnum;
|
||||||
|
|
||||||
import javax.persistence.Index;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -165,6 +164,9 @@ public class HapiFhirJpaMigrationTasks extends BaseMigrationTasks<VersionEnum> {
|
||||||
// TermValueSetConceptDesignation
|
// TermValueSetConceptDesignation
|
||||||
version.startSectionWithMessage("Processing table: TRM_VALUESET_C_DESIGNATION");
|
version.startSectionWithMessage("Processing table: TRM_VALUESET_C_DESIGNATION");
|
||||||
version.onTable("TRM_VALUESET_C_DESIGNATION").modifyColumn("VAL").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 2000);
|
version.onTable("TRM_VALUESET_C_DESIGNATION").modifyColumn("VAL").nonNullable().withType(BaseTableColumnTypeTask.ColumnTypeEnum.STRING, 2000);
|
||||||
|
|
||||||
|
version.startSectionWithMessage("Processing table: TRM_CONCEPT_PROPERTY");
|
||||||
|
version.onTable("TRM_CONCEPT_PROPERTY").addColumn("PROP_VAL_LOB").nullable().type(BaseTableColumnTypeTask.ColumnTypeEnum.CLOB);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void init400() {
|
protected void init400() {
|
||||||
|
|
|
@ -73,6 +73,7 @@ public abstract class RequestDetails {
|
||||||
private Map<Object, Object> myUserData;
|
private Map<Object, Object> myUserData;
|
||||||
private IBaseResource myResource;
|
private IBaseResource myResource;
|
||||||
private String myRequestId;
|
private String myRequestId;
|
||||||
|
private String myFixedConditionalUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
|
@ -81,6 +82,14 @@ public abstract class RequestDetails {
|
||||||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public String getFixedConditionalUrl() {
|
||||||
|
return myFixedConditionalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFixedConditionalUrl(String theFixedConditionalUrl) {
|
||||||
|
myFixedConditionalUrl = theFixedConditionalUrl;
|
||||||
|
}
|
||||||
|
|
||||||
public String getRequestId() {
|
public String getRequestId() {
|
||||||
return myRequestId;
|
return myRequestId;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +161,9 @@ public abstract class RequestDetails {
|
||||||
* @return Returns the <b>conditional URL</b> if this request has one, or <code>null</code> otherwise
|
* @return Returns the <b>conditional URL</b> if this request has one, or <code>null</code> otherwise
|
||||||
*/
|
*/
|
||||||
public String getConditionalUrl(RestOperationTypeEnum theOperationType) {
|
public String getConditionalUrl(RestOperationTypeEnum theOperationType) {
|
||||||
|
if (myFixedConditionalUrl != null) {
|
||||||
|
return myFixedConditionalUrl;
|
||||||
|
}
|
||||||
switch (theOperationType) {
|
switch (theOperationType) {
|
||||||
case CREATE:
|
case CREATE:
|
||||||
String retVal = this.getHeader(Constants.HEADER_IF_NONE_EXIST);
|
String retVal = this.getHeader(Constants.HEADER_IF_NONE_EXIST);
|
||||||
|
|
|
@ -108,8 +108,17 @@ public interface IAuthRuleBuilderRule {
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderRuleOp write();
|
IAuthRuleBuilderRuleOp write();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This rule specifically allows a user to perform a FHIR create, but not an update or other write operations
|
||||||
|
*
|
||||||
|
* @see #write()
|
||||||
|
* @since 4.1.0
|
||||||
|
*/
|
||||||
|
IAuthRuleBuilderRuleOp create();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Allow a GraphQL query
|
* Allow a GraphQL query
|
||||||
*/
|
*/
|
||||||
IAuthRuleBuilderGraphQL graphQL();
|
IAuthRuleBuilderGraphQL graphQL();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -253,6 +253,14 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
||||||
return myWriteRuleBuilder;
|
return myWriteRuleBuilder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public IAuthRuleBuilderRuleOp create() {
|
||||||
|
if (myWriteRuleBuilder == null) {
|
||||||
|
myWriteRuleBuilder = new RuleBuilderRuleOp(RuleOpEnum.CREATE);
|
||||||
|
}
|
||||||
|
return myWriteRuleBuilder;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public IAuthRuleBuilderGraphQL graphQL() {
|
public IAuthRuleBuilderGraphQL graphQL() {
|
||||||
return new RuleBuilderGraphQL();
|
return new RuleBuilderGraphQL();
|
||||||
|
|
|
@ -207,6 +207,19 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case CREATE:
|
||||||
|
if (theInputResource == null && theInputResourceId == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (theOperation == RestOperationTypeEnum.CREATE) {
|
||||||
|
appliesToResource = theInputResource;
|
||||||
|
if (theInputResourceId != null) {
|
||||||
|
appliesToResourceId = Collections.singletonList(theInputResourceId);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case DELETE:
|
case DELETE:
|
||||||
if (theOperation == RestOperationTypeEnum.DELETE) {
|
if (theOperation == RestOperationTypeEnum.DELETE) {
|
||||||
if (myAppliesToDeleteCascade != (thePointcut == Pointcut.STORAGE_CASCADE_DELETE)) {
|
if (myAppliesToDeleteCascade != (thePointcut == Pointcut.STORAGE_CASCADE_DELETE)) {
|
||||||
|
@ -288,7 +301,13 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String previousFixedConditionalUrl = theRequestDetails.getFixedConditionalUrl();
|
||||||
|
theRequestDetails.setFixedConditionalUrl(nextPart.getConditionalUrl());
|
||||||
|
|
||||||
Verdict newVerdict = theRuleApplier.applyRulesAndReturnDecision(operation, theRequestDetails, inputResource, inputResourceId, null, thePointcut);
|
Verdict newVerdict = theRuleApplier.applyRulesAndReturnDecision(operation, theRequestDetails, inputResource, inputResourceId, null, thePointcut);
|
||||||
|
|
||||||
|
theRequestDetails.setFixedConditionalUrl(previousFixedConditionalUrl);
|
||||||
|
|
||||||
if (newVerdict == null) {
|
if (newVerdict == null) {
|
||||||
continue;
|
continue;
|
||||||
} else if (verdict == null) {
|
} else if (verdict == null) {
|
||||||
|
|
|
@ -33,5 +33,6 @@ enum RuleOpEnum {
|
||||||
DELETE,
|
DELETE,
|
||||||
OPERATION,
|
OPERATION,
|
||||||
GRAPHQL,
|
GRAPHQL,
|
||||||
|
CREATE,
|
||||||
PATCH
|
PATCH
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,6 +14,7 @@ import ca.uhn.fhir.rest.api.ValidationModeEnum;
|
||||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||||
import ca.uhn.fhir.rest.param.BaseAndListParam;
|
import ca.uhn.fhir.rest.param.BaseAndListParam;
|
||||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||||
|
import ca.uhn.fhir.rest.param.TokenParam;
|
||||||
import ca.uhn.fhir.rest.param.binder.CollectionBinder;
|
import ca.uhn.fhir.rest.param.binder.CollectionBinder;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
|
@ -21,14 +22,12 @@ import ca.uhn.fhir.rest.server.exceptions.MethodNotAllowedException;
|
||||||
import ca.uhn.fhir.util.FhirTerser;
|
import ca.uhn.fhir.util.FhirTerser;
|
||||||
import ca.uhn.fhir.util.ReflectionUtil;
|
import ca.uhn.fhir.util.ReflectionUtil;
|
||||||
import org.apache.commons.lang3.Validate;
|
import org.apache.commons.lang3.Validate;
|
||||||
import org.hl7.fhir.instance.model.api.IBase;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.hl7.fhir.instance.model.api.IBaseDatatype;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
|
||||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.lang.reflect.Modifier;
|
import java.lang.reflect.Modifier;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
|
@ -163,7 +162,10 @@ public class OperationParameter implements IParameter {
|
||||||
*/
|
*/
|
||||||
isSearchParam &= typeIsConcrete && !IBase.class.isAssignableFrom(myParameterType);
|
isSearchParam &= typeIsConcrete && !IBase.class.isAssignableFrom(myParameterType);
|
||||||
|
|
||||||
myAllowGet = IPrimitiveType.class.isAssignableFrom(myParameterType) || String.class.equals(myParameterType) || isSearchParam || ValidationModeEnum.class.equals(myParameterType);
|
myAllowGet = IPrimitiveType.class.isAssignableFrom(myParameterType)
|
||||||
|
|| String.class.equals(myParameterType)
|
||||||
|
|| isSearchParam
|
||||||
|
|| ValidationModeEnum.class.equals(myParameterType);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The parameter can be of type string for validation methods - This is a bit weird. See ValidateDstu2Test. We
|
* The parameter can be of type string for validation methods - This is a bit weird. See ValidateDstu2Test. We
|
||||||
|
@ -172,6 +174,12 @@ public class OperationParameter implements IParameter {
|
||||||
if (!myParameterType.equals(IBase.class) && !myParameterType.equals(String.class)) {
|
if (!myParameterType.equals(IBase.class) && !myParameterType.equals(String.class)) {
|
||||||
if (IBaseResource.class.isAssignableFrom(myParameterType) && myParameterType.isInterface()) {
|
if (IBaseResource.class.isAssignableFrom(myParameterType) && myParameterType.isInterface()) {
|
||||||
myParamType = "Resource";
|
myParamType = "Resource";
|
||||||
|
} else if (IBaseReference.class.isAssignableFrom(myParameterType)) {
|
||||||
|
myParamType = "Reference";
|
||||||
|
myAllowGet = true;
|
||||||
|
} else if (IBaseCoding.class.isAssignableFrom(myParameterType)) {
|
||||||
|
myParamType = "Coding";
|
||||||
|
myAllowGet = true;
|
||||||
} else if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
|
} else if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
|
||||||
myParamType = "date";
|
myParamType = "date";
|
||||||
myMax = 2;
|
myMax = 2;
|
||||||
|
@ -266,7 +274,7 @@ public class OperationParameter implements IParameter {
|
||||||
if (myAllowGet) {
|
if (myAllowGet) {
|
||||||
|
|
||||||
if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
|
if (DateRangeParam.class.isAssignableFrom(myParameterType)) {
|
||||||
List<QualifiedParamList> parameters = new ArrayList<QualifiedParamList>();
|
List<QualifiedParamList> parameters = new ArrayList<>();
|
||||||
parameters.add(QualifiedParamList.singleton(paramValues[0]));
|
parameters.add(QualifiedParamList.singleton(paramValues[0]));
|
||||||
if (paramValues.length > 1) {
|
if (paramValues.length > 1) {
|
||||||
parameters.add(QualifiedParamList.singleton(paramValues[1]));
|
parameters.add(QualifiedParamList.singleton(paramValues[1]));
|
||||||
|
@ -275,11 +283,31 @@ public class OperationParameter implements IParameter {
|
||||||
FhirContext ctx = theRequest.getServer().getFhirContext();
|
FhirContext ctx = theRequest.getServer().getFhirContext();
|
||||||
dateRangeParam.setValuesAsQueryTokens(ctx, myName, parameters);
|
dateRangeParam.setValuesAsQueryTokens(ctx, myName, parameters);
|
||||||
matchingParamValues.add(dateRangeParam);
|
matchingParamValues.add(dateRangeParam);
|
||||||
|
|
||||||
|
} else if (IBaseReference.class.isAssignableFrom(myParameterType)) {
|
||||||
|
|
||||||
|
processAllCommaSeparatedValues(paramValues, t -> {
|
||||||
|
IBaseReference param = (IBaseReference) ReflectionUtil.newInstance(myParameterType);
|
||||||
|
param.setReference(t);
|
||||||
|
matchingParamValues.add(param);
|
||||||
|
});
|
||||||
|
|
||||||
|
} else if (IBaseCoding.class.isAssignableFrom(myParameterType)) {
|
||||||
|
|
||||||
|
processAllCommaSeparatedValues(paramValues, t -> {
|
||||||
|
TokenParam tokenParam = new TokenParam();
|
||||||
|
tokenParam.setValueAsQueryToken(myContext, myName, null, t);
|
||||||
|
|
||||||
|
IBaseCoding param = (IBaseCoding) ReflectionUtil.newInstance(myParameterType);
|
||||||
|
param.setSystem(tokenParam.getSystem());
|
||||||
|
param.setCode(tokenParam.getValue());
|
||||||
|
matchingParamValues.add(param);
|
||||||
|
});
|
||||||
|
|
||||||
} else if (String.class.isAssignableFrom(myParameterType)) {
|
} else if (String.class.isAssignableFrom(myParameterType)) {
|
||||||
|
|
||||||
for (String next : paramValues) {
|
matchingParamValues.addAll(Arrays.asList(paramValues));
|
||||||
matchingParamValues.add(next);
|
|
||||||
}
|
|
||||||
} else if (ValidationModeEnum.class.equals(myParameterType)) {
|
} else if (ValidationModeEnum.class.equals(myParameterType)) {
|
||||||
|
|
||||||
if (isNotBlank(paramValues[0])) {
|
if (isNotBlank(paramValues[0])) {
|
||||||
|
@ -309,6 +337,22 @@ public class OperationParameter implements IParameter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method is here to mediate between the POST form of operation parameters (i.e. elements within a <code>Parameters</code>
|
||||||
|
* resource) and the GET form (i.e. URL parameters).
|
||||||
|
* <p>
|
||||||
|
* Essentially we want to allow comma-separated values as is done with searches on URLs.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private void processAllCommaSeparatedValues(String[] theParamValues, Consumer<String> theHandler) {
|
||||||
|
for (String nextValue : theParamValues) {
|
||||||
|
QualifiedParamList qualifiedParamList = QualifiedParamList.splitQueryStringByCommasIgnoreEscape(null, nextValue);
|
||||||
|
for (String nextSplitValue : qualifiedParamList) {
|
||||||
|
theHandler.accept(nextSplitValue);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void translateQueryParametersIntoServerArgumentForPost(RequestDetails theRequest, List<Object> matchingParamValues) {
|
private void translateQueryParametersIntoServerArgumentForPost(RequestDetails theRequest, List<Object> matchingParamValues) {
|
||||||
IBaseResource requestContents = (IBaseResource) theRequest.getUserData().get(REQUEST_CONTENTS_USERDATA_KEY);
|
IBaseResource requestContents = (IBaseResource) theRequest.getUserData().get(REQUEST_CONTENTS_USERDATA_KEY);
|
||||||
if (requestContents != null) {
|
if (requestContents != null) {
|
||||||
|
@ -394,10 +438,6 @@ public class OperationParameter implements IParameter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void throwInvalidMode(String paramValues) {
|
|
||||||
throw new InvalidRequestException("Invalid mode value: \"" + paramValues + "\"");
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IOperationParamConverter {
|
interface IOperationParamConverter {
|
||||||
|
|
||||||
Object incomingServer(Object theObject);
|
Object incomingServer(Object theObject);
|
||||||
|
@ -429,5 +469,9 @@ public class OperationParameter implements IParameter {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void throwInvalidMode(String paramValues) {
|
||||||
|
throw new InvalidRequestException("Invalid mode value: \"" + paramValues + "\"");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,63 @@
|
||||||
|
package ca.uhn.fhir.rest.server.provider;
|
||||||
|
|
||||||
|
/*-
|
||||||
|
* #%L
|
||||||
|
* HAPI FHIR - Server Framework
|
||||||
|
* %%
|
||||||
|
* Copyright (C) 2014 - 2019 University Health Network
|
||||||
|
* %%
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
* #L%
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.annotation.Operation;
|
||||||
|
import ca.uhn.fhir.rest.annotation.OperationParam;
|
||||||
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
|
import ca.uhn.fhir.rest.server.servlet.ServletRequestDetails;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class implements the Observation
|
||||||
|
* <a href="http://hl7.org/fhir/observation-operation-lastn.html">$lastn</a> operation.
|
||||||
|
* <p>
|
||||||
|
* It is does not implement the actual storage logic for this operation, but can be
|
||||||
|
* subclassed to provide this functionality.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 4.1.0
|
||||||
|
*/
|
||||||
|
public abstract class BaseLastNProvider {
|
||||||
|
|
||||||
|
@Operation(name = Constants.OPERATION_LASTN, typeName = "Observation", idempotent = true)
|
||||||
|
public IBaseBundle lastN(
|
||||||
|
ServletRequestDetails theRequestDetails,
|
||||||
|
@OperationParam(name = "subject", typeName = "reference", min = 0, max = 1) IBaseReference theSubject,
|
||||||
|
@OperationParam(name = "category", typeName = "coding", min = 0, max = OperationParam.MAX_UNLIMITED) List<IBaseCoding> theCategories,
|
||||||
|
@OperationParam(name = "code", typeName = "coding", min = 0, max = OperationParam.MAX_UNLIMITED) List<IBaseCoding> theCodes,
|
||||||
|
@OperationParam(name = "max", typeName = "integer", min = 0, max = 1) IPrimitiveType<Integer> theMax
|
||||||
|
) {
|
||||||
|
return processLastN(theSubject, theCategories, theCodes, theMax);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Subclasses should implement this method
|
||||||
|
*/
|
||||||
|
protected abstract IBaseBundle processLastN(IBaseReference theSubject, List<IBaseCoding> theCategories, List<IBaseCoding> theCodes, IPrimitiveType<Integer> theMax);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -19,13 +19,6 @@ package org.hl7.fhir.dstu2016may.hapi.rest.server;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.hl7.fhir.dstu2016may.model.*;
|
|
||||||
import org.hl7.fhir.dstu2016may.model.Bundle.*;
|
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
||||||
|
@ -35,6 +28,18 @@ import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.Bundle;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.Bundle.BundleEntryComponent;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.Bundle.BundleLinkComponent;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.Bundle.SearchEntryMode;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.DomainResource;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.IdType;
|
||||||
|
import org.hl7.fhir.dstu2016may.model.Resource;
|
||||||
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public class Dstu2_1BundleFactory implements IVersionSpecificBundleFactory {
|
public class Dstu2_1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
|
|
||||||
|
@ -46,90 +51,6 @@ public class Dstu2_1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
|
||||||
Resource next = (Resource) nextBaseRes;
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
|
||||||
if (next instanceof DomainResource) {
|
|
||||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
|
||||||
if (nextContained.getIdElement().isEmpty() == false) {
|
|
||||||
containedIds.add(nextContained.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
|
|
||||||
do {
|
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
|
||||||
|
|
||||||
for (IBaseReference nextRef : references) {
|
|
||||||
IAnyResource nextRes = (IAnyResource) nextRef.getResource();
|
|
||||||
if (nextRes != null) {
|
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIdType id = nextRes.getIdElement();
|
|
||||||
if (id.hasResourceType() == false) {
|
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
|
||||||
id = id.withResourceType(resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
|
||||||
addedResourceIds.add(id);
|
|
||||||
addedResourcesThisPass.add(nextRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
|
||||||
references = new ArrayList<IBaseReference>();
|
|
||||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
|
||||||
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, IBaseReference.class);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource(next);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
|
||||||
if (httpVerb != null) {
|
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
|
||||||
entry.getRequest().getUrlElement().setValue(next.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually add the resources to the bundle
|
|
||||||
*/
|
|
||||||
for (IBaseResource next : includedResources) {
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
ensureBundle();
|
ensureBundle();
|
||||||
|
@ -160,7 +81,7 @@ public class Dstu2_1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||||
|
|
||||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||||
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
if (theBundleInclusionRule != null && !theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -282,44 +203,6 @@ public class Dstu2_1BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
|
||||||
BundleTypeEnum theBundleType) {
|
|
||||||
ensureBundle();
|
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
myBundle.getMeta().setLastUpdated(new Date());
|
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
|
||||||
Resource next = (Resource) nextBaseRes;
|
|
||||||
BundleEntryComponent nextEntry = myBundle.addEntry();
|
|
||||||
|
|
||||||
nextEntry.setResource(next);
|
|
||||||
if (next.getIdElement().isEmpty()) {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
|
||||||
} else {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
|
||||||
if (next.getIdElement().isAbsolute()) {
|
|
||||||
nextEntry.getRequest().setUrl(next.getId());
|
|
||||||
} else {
|
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
|
||||||
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(), next.getIdElement().getVersionIdPart()).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
myBundle = (Bundle) theBundle;
|
myBundle = (Bundle) theBundle;
|
||||||
|
|
|
@ -50,86 +50,6 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
|
||||||
IResource next = (IResource) nextBaseRes;
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
|
||||||
for (IResource nextContained : next.getContained().getContainedResources()) {
|
|
||||||
if (nextContained.getId().isEmpty() == false) {
|
|
||||||
containedIds.add(nextContained.getId().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BaseResourceReferenceDt> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, BaseResourceReferenceDt.class);
|
|
||||||
do {
|
|
||||||
List<IResource> addedResourcesThisPass = new ArrayList<IResource>();
|
|
||||||
|
|
||||||
for (BaseResourceReferenceDt nextRef : references) {
|
|
||||||
IResource nextRes = (IResource) nextRef.getResource();
|
|
||||||
if (nextRes != null) {
|
|
||||||
if (nextRes.getId().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getId().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IdDt id = nextRes.getId();
|
|
||||||
if (id.hasResourceType() == false) {
|
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
|
||||||
id = id.withResourceType(resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
|
||||||
addedResourceIds.add(id);
|
|
||||||
addedResourcesThisPass.add(nextRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
|
||||||
references = new ArrayList<BaseResourceReferenceDt>();
|
|
||||||
for (IResource iResource : addedResourcesThisPass) {
|
|
||||||
List<BaseResourceReferenceDt> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, BaseResourceReferenceDt.class);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
Entry entry = myBundle.addEntry().setResource(next);
|
|
||||||
if (next.getId().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getId().getValue());
|
|
||||||
}
|
|
||||||
BundleEntryTransactionMethodEnum httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
|
||||||
if (httpVerb != null) {
|
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb.getCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually add the resources to the bundle
|
|
||||||
*/
|
|
||||||
for (IBaseResource next : includedResources) {
|
|
||||||
Entry entry = myBundle.addEntry();
|
|
||||||
entry.setResource((IResource) next).getSearch().setMode(SearchEntryModeEnum.INCLUDE);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
ensureBundle();
|
ensureBundle();
|
||||||
|
@ -275,44 +195,6 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
|
||||||
BundleTypeEnum theBundleType) {
|
|
||||||
ensureBundle();
|
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
ResourceMetadataKeyEnum.PUBLISHED.put(myBundle, InstantDt.withCurrentTime());
|
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
|
||||||
IResource next = (IResource) nextBaseRes;
|
|
||||||
Entry nextEntry = myBundle.addEntry();
|
|
||||||
|
|
||||||
nextEntry.setResource(next);
|
|
||||||
if (next.getId().isEmpty()) {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerbEnum.POST);
|
|
||||||
} else {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerbEnum.PUT);
|
|
||||||
if (next.getId().isAbsolute()) {
|
|
||||||
nextEntry.getRequest().setUrl(next.getId());
|
|
||||||
} else {
|
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
|
||||||
nextEntry.getRequest().setUrl(new IdDt(theServerBase, resourceType, next.getId().getIdPart(), next.getId().getVersionIdPart()).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
myBundle = (Bundle) theBundle;
|
myBundle = (Bundle) theBundle;
|
||||||
|
|
|
@ -2231,25 +2231,27 @@ public class GenericClientDstu2Test {
|
||||||
|
|
||||||
Patient p2 = new Patient(); // Yes ID
|
Patient p2 = new Patient(); // Yes ID
|
||||||
p2.addName().addFamily("PATIENT2");
|
p2.addName().addFamily("PATIENT2");
|
||||||
p2.setId("Patient/2");
|
p2.setId("http://foo.com/Patient/2");
|
||||||
input.add(p2);
|
input.add(p2);
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
List<IBaseResource> response = client.transaction()
|
List<IBaseResource> response = client.transaction()
|
||||||
.withResources(input)
|
.withResources(input)
|
||||||
.encodedJson()
|
.encodedJson()
|
||||||
|
.prettyPrint()
|
||||||
.execute();
|
.execute();
|
||||||
//@formatter:on
|
//@formatter:on
|
||||||
|
|
||||||
assertEquals("http://example.com/fhir", capt.getValue().getURI().toString());
|
assertEquals("http://example.com/fhir?_pretty=true", capt.getValue().getURI().toString());
|
||||||
assertEquals(2, response.size());
|
assertEquals(2, response.size());
|
||||||
|
|
||||||
String requestString = IOUtils.toString(((HttpEntityEnclosingRequest) capt.getValue()).getEntity().getContent());
|
String requestString = IOUtils.toString(((HttpEntityEnclosingRequest) capt.getValue()).getEntity().getContent());
|
||||||
|
ourLog.info(requestString);
|
||||||
ca.uhn.fhir.model.dstu2.resource.Bundle requestBundle = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, requestString);
|
ca.uhn.fhir.model.dstu2.resource.Bundle requestBundle = ourCtx.newJsonParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, requestString);
|
||||||
assertEquals(2, requestBundle.getEntry().size());
|
assertEquals(2, requestBundle.getEntry().size());
|
||||||
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod());
|
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod());
|
||||||
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod());
|
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod());
|
||||||
assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl());
|
assertEquals("http://foo.com/Patient/2", requestBundle.getEntry().get(1).getFullUrl());
|
||||||
assertEquals("application/json+fhir", capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
assertEquals("application/json+fhir", capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||||
|
|
||||||
p1 = (Patient) response.get(0);
|
p1 = (Patient) response.get(0);
|
||||||
|
|
|
@ -32,7 +32,6 @@ import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle;
|
import org.hl7.fhir.dstu3.model.Bundle;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.dstu3.model.Bundle.BundleEntryComponent;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent;
|
import org.hl7.fhir.dstu3.model.Bundle.BundleLinkComponent;
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.HTTPVerb;
|
|
||||||
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
|
import org.hl7.fhir.dstu3.model.Bundle.SearchEntryMode;
|
||||||
import org.hl7.fhir.dstu3.model.DomainResource;
|
import org.hl7.fhir.dstu3.model.DomainResource;
|
||||||
import org.hl7.fhir.dstu3.model.IdType;
|
import org.hl7.fhir.dstu3.model.IdType;
|
||||||
|
@ -52,93 +51,6 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
|
||||||
Resource next = (Resource) nextBaseRes;
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
|
||||||
if (next instanceof DomainResource) {
|
|
||||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
|
||||||
if (nextContained.getIdElement().isEmpty() == false) {
|
|
||||||
containedIds.add(nextContained.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
|
|
||||||
do {
|
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
|
||||||
|
|
||||||
for (IBaseReference nextRef : references) {
|
|
||||||
IAnyResource nextRes = (IAnyResource) nextRef.getResource();
|
|
||||||
if (nextRes != null) {
|
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIdType id = nextRes.getIdElement();
|
|
||||||
if (id.hasResourceType() == false) {
|
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
|
||||||
id = id.withResourceType(resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
|
||||||
addedResourceIds.add(id);
|
|
||||||
addedResourcesThisPass.add(nextRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
|
||||||
references = new ArrayList<IBaseReference>();
|
|
||||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
|
||||||
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, IBaseReference.class);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource(next);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
|
||||||
if (httpVerb != null) {
|
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
|
||||||
entry.getRequest().getUrlElement().setValue(next.getId());
|
|
||||||
}
|
|
||||||
if ("DELETE".equals(httpVerb)) {
|
|
||||||
entry.setResource(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually add the resources to the bundle
|
|
||||||
*/
|
|
||||||
for (IBaseResource next : includedResources) {
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
|
@ -170,7 +82,7 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||||
|
|
||||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||||
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
if (theBundleInclusionRule != null && !theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -314,44 +226,6 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
|
||||||
BundleTypeEnum theBundleType) {
|
|
||||||
myBundle = new Bundle();
|
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
myBundle.getMeta().setLastUpdated(new Date());
|
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
|
||||||
Resource next = (Resource) nextBaseRes;
|
|
||||||
BundleEntryComponent nextEntry = myBundle.addEntry();
|
|
||||||
|
|
||||||
nextEntry.setResource(next);
|
|
||||||
if (next.getIdElement().isEmpty()) {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
|
||||||
} else {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
|
||||||
if (next.getIdElement().isAbsolute()) {
|
|
||||||
nextEntry.getRequest().setUrl(next.getId());
|
|
||||||
} else {
|
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
|
||||||
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(), next.getIdElement().getVersionIdPart()).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
myBundle = (Bundle) theBundle;
|
myBundle = (Bundle) theBundle;
|
||||||
|
|
|
@ -23,18 +23,16 @@ package ca.uhn.fhir.rest.server.provider.dstu2hl7org;
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
|
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||||
|
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||||
import org.hl7.fhir.dstu2.model.Bundle;
|
import org.hl7.fhir.dstu2.model.*;
|
||||||
import org.hl7.fhir.dstu2.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.dstu2.model.Bundle.BundleEntryComponent;
|
||||||
import org.hl7.fhir.dstu2.model.Bundle.BundleLinkComponent;
|
import org.hl7.fhir.dstu2.model.Bundle.BundleLinkComponent;
|
||||||
import org.hl7.fhir.dstu2.model.Bundle.HTTPVerb;
|
|
||||||
import org.hl7.fhir.dstu2.model.Bundle.SearchEntryMode;
|
import org.hl7.fhir.dstu2.model.Bundle.SearchEntryMode;
|
||||||
import org.hl7.fhir.dstu2.model.IdType;
|
|
||||||
import org.hl7.fhir.dstu2.model.InstantType;
|
|
||||||
import org.hl7.fhir.dstu2.model.Resource;
|
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
import org.hl7.fhir.instance.model.api.*;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
@ -52,8 +50,12 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
@Override
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase,
|
||||||
|
BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
|
ensureBundle();
|
||||||
|
|
||||||
|
List<IAnyResource> includedResources = new ArrayList<IAnyResource>();
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
for (IBaseResource next : theResult) {
|
||||||
|
@ -62,22 +64,28 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
for (IBaseResource next : theResult) {
|
||||||
IDomainResource next = (IDomainResource) nextBaseRes;
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
Set<String> containedIds = new HashSet<String>();
|
||||||
for (IBaseResource nextContained : next.getContained()) {
|
|
||||||
if (nextContained.getIdElement().isEmpty() == false) {
|
if (next instanceof DomainResource) {
|
||||||
containedIds.add(nextContained.getIdElement().getValue());
|
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
||||||
|
if (isNotBlank(nextContained.getId())) {
|
||||||
|
containedIds.add(nextContained.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next,
|
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
||||||
IBaseReference.class);
|
|
||||||
do {
|
do {
|
||||||
List<IBaseResource> addedResourcesThisPass = new ArrayList<IBaseResource>();
|
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||||
|
|
||||||
for (IBaseReference nextRef : references) {
|
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||||
IBaseResource nextRes = (IBaseResource) nextRef.getResource();
|
if (theBundleInclusionRule != null && !theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
IAnyResource nextRes = (IAnyResource) nextRefInfo.getResourceReference().getResource();
|
||||||
if (nextRes != null) {
|
if (nextRes != null) {
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
if (nextRes.getIdElement().hasIdPart()) {
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
||||||
|
@ -100,119 +108,62 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
|
||||||
references = new ArrayList<IBaseReference>();
|
|
||||||
for (IBaseResource iResource : addedResourcesThisPass) {
|
|
||||||
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource,
|
|
||||||
IBaseReference.class);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
|
||||||
populateBundleEntryFullUrl(next, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually add the resources to the bundle
|
|
||||||
*/
|
|
||||||
for (IBaseResource next : includedResources) {
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
|
||||||
populateBundleEntryFullUrl(next, entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase,
|
|
||||||
BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
|
||||||
ensureBundle();
|
|
||||||
|
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
|
||||||
|
|
||||||
List<? extends IAnyResource> contained;
|
|
||||||
if (next instanceof IDomainResource) {
|
|
||||||
IDomainResource nextDomain = (IDomainResource) next;
|
|
||||||
contained = nextDomain.getContained();
|
|
||||||
} else {
|
|
||||||
contained = Collections.emptyList();
|
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
|
||||||
for (IAnyResource nextContained : contained) {
|
|
||||||
if (nextContained.getId().isEmpty() == false) {
|
|
||||||
containedIds.add(nextContained.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
|
||||||
do {
|
|
||||||
List<IBaseResource> addedResourcesThisPass = new ArrayList<IBaseResource>();
|
|
||||||
|
|
||||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
|
||||||
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
IBaseResource nextRes = (IBaseResource) nextRefInfo.getResourceReference().getResource();
|
|
||||||
if (nextRes != null) {
|
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IdType id = (IdType) nextRes.getIdElement();
|
|
||||||
if (id.hasResourceType() == false) {
|
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
|
||||||
id = id.withResourceType(resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
|
||||||
addedResourceIds.add(id);
|
|
||||||
addedResourcesThisPass.add(nextRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
includedResources.addAll(addedResourcesThisPass);
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
// Linked resources may themselves have linked resources
|
||||||
references = new ArrayList<ResourceReferenceInfo>();
|
references = new ArrayList<>();
|
||||||
for (IBaseResource iResource : addedResourcesThisPass) {
|
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||||
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
||||||
references.addAll(newReferences);
|
references.addAll(newReferences);
|
||||||
}
|
}
|
||||||
} while (references.isEmpty() == false);
|
} while (references.isEmpty() == false);
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
||||||
populateBundleEntryFullUrl(next, entry);
|
Resource nextAsResource = (Resource) next;
|
||||||
|
IIdType id = populateBundleEntryFullUrl(next, entry);
|
||||||
|
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(nextAsResource);
|
||||||
|
if (httpVerb != null) {
|
||||||
|
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
||||||
|
if (id != null) {
|
||||||
|
entry.getRequest().setUrl(id.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("DELETE".equals(httpVerb)) {
|
||||||
|
entry.setResource(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate Bundle.entry.response
|
||||||
|
if (theBundleType != null) {
|
||||||
|
switch (theBundleType) {
|
||||||
|
case BATCH_RESPONSE:
|
||||||
|
case TRANSACTION_RESPONSE:
|
||||||
|
if ("1".equals(id.getVersionIdPart())) {
|
||||||
|
entry.getResponse().setStatus("201 Created");
|
||||||
|
} else if (isNotBlank(id.getVersionIdPart())) {
|
||||||
|
entry.getResponse().setStatus("200 OK");
|
||||||
|
}
|
||||||
|
if (isNotBlank(id.getVersionIdPart())) {
|
||||||
|
entry.getResponse().setEtag(RestfulServerUtils.createEtag(id.getVersionIdPart()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate Bundle.entry.search
|
||||||
|
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
||||||
|
if (searchMode != null) {
|
||||||
|
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
||||||
|
}
|
||||||
|
|
||||||
// BundleEntrySearchModeEnum searchMode =
|
|
||||||
// ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(next);
|
|
||||||
// if (searchMode != null) {
|
|
||||||
// entry.getSearch().getModeElement().setValue(searchMode.getCode());
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Actually add the resources to the bundle
|
* Actually add the resources to the bundle
|
||||||
*/
|
*/
|
||||||
for (IBaseResource next : includedResources) {
|
for (IAnyResource next : includedResources) {
|
||||||
myBundle.addEntry().setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
BundleEntryComponent entry = myBundle.addEntry();
|
||||||
|
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||||
|
populateBundleEntryFullUrl(next, entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -229,7 +180,7 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
myBundle.setId(UUID.randomUUID().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myBundle.getMeta().getLastUpdated() == null) {
|
if (myBundle.getMeta().getLastUpdated() == null && theLastUpdated != null) {
|
||||||
InstantType instantType = new InstantType();
|
InstantType instantType = new InstantType();
|
||||||
instantType.setValueAsString(theLastUpdated.getValueAsString());
|
instantType.setValueAsString(theLastUpdated.getValueAsString());
|
||||||
myBundle.getMeta().setLastUpdatedElement(instantType);
|
myBundle.getMeta().setLastUpdatedElement(instantType);
|
||||||
|
@ -276,60 +227,24 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources,
|
|
||||||
String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType) {
|
|
||||||
ensureBundle();
|
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
myBundle.getMeta().setLastUpdatedElement(InstantType.withCurrentTime());
|
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
|
||||||
IBaseResource next = (IBaseResource) nextBaseRes;
|
|
||||||
BundleEntryComponent nextEntry = myBundle.addEntry();
|
|
||||||
|
|
||||||
nextEntry.setResource((Resource) next);
|
|
||||||
if (next.getIdElement().isEmpty()) {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
|
||||||
} else {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
|
||||||
if (next.getIdElement().isAbsolute()) {
|
|
||||||
nextEntry.getRequest().setUrl(next.getIdElement().getValue());
|
|
||||||
} else {
|
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
|
||||||
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(),
|
|
||||||
next.getIdElement().getVersionIdPart()).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
myBundle = (Bundle) theBundle;
|
myBundle = (Bundle) theBundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
private IIdType populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
||||||
|
IIdType idElement = null;
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
if (next.getIdElement().hasBaseUrl()) {
|
||||||
entry.setFullUrl(next.getIdElement().toVersionless().getValue());
|
idElement = next.getIdElement();
|
||||||
|
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||||
} else {
|
} else {
|
||||||
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
||||||
IIdType id = next.getIdElement().toVersionless();
|
idElement = next.getIdElement();
|
||||||
id = id.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
idElement = idElement.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
||||||
entry.setFullUrl(id.getValue());
|
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return idElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -629,7 +629,7 @@ public class GenericClientDstu2Hl7OrgTest {
|
||||||
|
|
||||||
Patient p2 = new Patient(); // Yes ID
|
Patient p2 = new Patient(); // Yes ID
|
||||||
p2.addName().addFamily("PATIENT2");
|
p2.addName().addFamily("PATIENT2");
|
||||||
p2.setId("Patient/2");
|
p2.setId("http://example.com/Patient/2");
|
||||||
input.add(p2);
|
input.add(p2);
|
||||||
|
|
||||||
//@formatter:off
|
//@formatter:off
|
||||||
|
@ -647,7 +647,7 @@ public class GenericClientDstu2Hl7OrgTest {
|
||||||
assertEquals(2, requestBundle.getEntry().size());
|
assertEquals(2, requestBundle.getEntry().size());
|
||||||
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod().name());
|
assertEquals("POST", requestBundle.getEntry().get(0).getRequest().getMethod().name());
|
||||||
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod().name());
|
assertEquals("PUT", requestBundle.getEntry().get(1).getRequest().getMethod().name());
|
||||||
assertEquals("Patient/2", requestBundle.getEntry().get(1).getRequest().getUrl());
|
assertEquals("http://example.com/Patient/2", requestBundle.getEntry().get(1).getFullUrl());
|
||||||
|
|
||||||
p1 = (Patient) response.get(0);
|
p1 = (Patient) response.get(0);
|
||||||
assertEquals(new IdType("Patient/1/_history/1"), p1.getIdElement().toUnqualified());
|
assertEquals(new IdType("Patient/1/_history/1"), p1.getIdElement().toUnqualified());
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.hl7.fhir.r4.model.Bundle;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.r4.model.Bundle.BundleEntryComponent;
|
||||||
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
import org.hl7.fhir.r4.model.Bundle.BundleLinkComponent;
|
||||||
import org.hl7.fhir.r4.model.Bundle.HTTPVerb;
|
|
||||||
import org.hl7.fhir.r4.model.Bundle.SearchEntryMode;
|
import org.hl7.fhir.r4.model.Bundle.SearchEntryMode;
|
||||||
import org.hl7.fhir.r4.model.DomainResource;
|
import org.hl7.fhir.r4.model.DomainResource;
|
||||||
import org.hl7.fhir.r4.model.IdType;
|
import org.hl7.fhir.r4.model.IdType;
|
||||||
|
@ -53,93 +52,6 @@ public class R4BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
|
||||||
Resource next = (Resource) nextBaseRes;
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
|
||||||
if (next instanceof DomainResource) {
|
|
||||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
|
||||||
if (nextContained.getIdElement().isEmpty() == false) {
|
|
||||||
containedIds.add(nextContained.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
|
|
||||||
do {
|
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<>();
|
|
||||||
|
|
||||||
for (IBaseReference nextRef : references) {
|
|
||||||
IAnyResource nextRes = (IAnyResource) nextRef.getResource();
|
|
||||||
if (nextRes != null) {
|
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIdType id = nextRes.getIdElement();
|
|
||||||
if (id.hasResourceType() == false) {
|
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
|
||||||
id = id.withResourceType(resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
|
||||||
addedResourceIds.add(id);
|
|
||||||
addedResourcesThisPass.add(nextRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
|
||||||
references = new ArrayList<>();
|
|
||||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
|
||||||
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, IBaseReference.class);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource(next);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
|
||||||
if (httpVerb != null) {
|
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
|
||||||
entry.getRequest().getUrlElement().setValue(next.getId());
|
|
||||||
}
|
|
||||||
if ("DELETE".equals(httpVerb)) {
|
|
||||||
entry.setResource(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually add the resources to the bundle
|
|
||||||
*/
|
|
||||||
for (IBaseResource next : includedResources) {
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
ensureBundle();
|
ensureBundle();
|
||||||
|
@ -170,7 +82,7 @@ public class R4BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||||
|
|
||||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||||
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
if (theBundleInclusionRule != null && !theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -316,44 +228,6 @@ public class R4BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
|
||||||
BundleTypeEnum theBundleType) {
|
|
||||||
myBundle = new Bundle();
|
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
myBundle.getMeta().setLastUpdated(new Date());
|
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
|
||||||
Resource next = (Resource) nextBaseRes;
|
|
||||||
BundleEntryComponent nextEntry = myBundle.addEntry();
|
|
||||||
|
|
||||||
nextEntry.setResource(next);
|
|
||||||
if (next.getIdElement().isEmpty()) {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
|
||||||
} else {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
|
||||||
if (next.getIdElement().isAbsolute()) {
|
|
||||||
nextEntry.getRequest().setUrl(next.getId());
|
|
||||||
} else {
|
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
|
||||||
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(), next.getIdElement().getVersionIdPart()).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
myBundle = (Bundle) theBundle;
|
myBundle = (Bundle) theBundle;
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
|
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
||||||
|
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||||
|
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
||||||
|
import ca.uhn.fhir.rest.client.api.ServerValidationModeEnum;
|
||||||
|
import ca.uhn.fhir.test.utilities.JettyUtil;
|
||||||
|
import org.eclipse.jetty.server.Server;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHandler;
|
||||||
|
import org.eclipse.jetty.servlet.ServletHolder;
|
||||||
|
import org.junit.After;
|
||||||
|
|
||||||
|
public class BaseR4ServerTest {
|
||||||
|
private FhirContext myCtx = FhirContext.forR4();
|
||||||
|
private Server myServer;
|
||||||
|
protected IGenericClient myClient;
|
||||||
|
protected String myBaseUrl;
|
||||||
|
|
||||||
|
@After
|
||||||
|
public void after() throws Exception {
|
||||||
|
JettyUtil.closeServer(myServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void startServer(Object theProvider) throws Exception {
|
||||||
|
RestfulServer servlet = new RestfulServer(myCtx);
|
||||||
|
servlet.registerProvider(theProvider);
|
||||||
|
ServletHandler proxyHandler = new ServletHandler();
|
||||||
|
servlet.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||||
|
servlet.setBundleInclusionRule(BundleInclusionRule.BASED_ON_RESOURCE_PRESENCE);
|
||||||
|
ServletHolder servletHolder = new ServletHolder(servlet);
|
||||||
|
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
||||||
|
|
||||||
|
myServer = new Server(0);
|
||||||
|
myServer.setHandler(proxyHandler);
|
||||||
|
JettyUtil.startServer(myServer);
|
||||||
|
int port = JettyUtil.getPortForStartedServer(myServer);
|
||||||
|
|
||||||
|
myBaseUrl = "http://localhost:" + port;
|
||||||
|
myCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||||
|
myClient = myCtx.newRestfulGenericClient(myBaseUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
|
import ca.uhn.fhir.rest.server.provider.BaseLastNProvider;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseCoding;
|
||||||
|
import org.hl7.fhir.instance.model.api.IBaseReference;
|
||||||
|
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||||
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
|
public class LastNProviderTest extends BaseR4ServerTest {
|
||||||
|
|
||||||
|
private IBaseReference myLastSubject;
|
||||||
|
private List<IBaseCoding> myLastCategories;
|
||||||
|
private List<IBaseCoding> myLastCodes;
|
||||||
|
private IPrimitiveType<Integer> myLastMax;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAllParamsPopulated() throws Exception {
|
||||||
|
|
||||||
|
class MyProvider extends BaseLastNProvider {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected IBaseBundle processLastN(IBaseReference theSubject, List<IBaseCoding> theCategories, List<IBaseCoding> theCodes, IPrimitiveType<Integer> theMax) {
|
||||||
|
myLastSubject = theSubject;
|
||||||
|
myLastCategories = theCategories;
|
||||||
|
myLastCodes = theCodes;
|
||||||
|
myLastMax = theMax;
|
||||||
|
|
||||||
|
Bundle retVal = new Bundle();
|
||||||
|
retVal.setId("abc123");
|
||||||
|
retVal.setType(Bundle.BundleType.SEARCHSET);
|
||||||
|
return retVal;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MyProvider provider = new MyProvider();
|
||||||
|
startServer(provider);
|
||||||
|
|
||||||
|
Bundle response = myClient
|
||||||
|
.search()
|
||||||
|
.byUrl(myBaseUrl + "/Observation/$lastn?subject=Patient/123&category=http://terminology.hl7.org/CodeSystem/observation-category|laboratory,http://terminology.hl7.org/CodeSystem/observation-category|vital-signs&code=http://loinc.org|1111-1,http://loinc.org|2222-2&max=15")
|
||||||
|
.returnBundle(Bundle.class)
|
||||||
|
.execute();
|
||||||
|
assertEquals("abc123", response.getIdElement().getIdPart());
|
||||||
|
assertEquals("Patient/123", myLastSubject.getReferenceElement().getValue());
|
||||||
|
assertEquals(2, myLastCategories.size());
|
||||||
|
assertEquals("http://terminology.hl7.org/CodeSystem/observation-category", myLastCategories.get(0).getSystem());
|
||||||
|
assertEquals("laboratory", myLastCategories.get(0).getCode());
|
||||||
|
assertEquals("http://terminology.hl7.org/CodeSystem/observation-category", myLastCategories.get(1).getSystem());
|
||||||
|
assertEquals("vital-signs", myLastCategories.get(1).getCode());
|
||||||
|
assertEquals(2, myLastCodes.size());
|
||||||
|
assertEquals("http://loinc.org", myLastCodes.get(0).getSystem());
|
||||||
|
assertEquals("1111-1", myLastCodes.get(0).getCode());
|
||||||
|
assertEquals("http://loinc.org", myLastCodes.get(1).getSystem());
|
||||||
|
assertEquals("2222-2", myLastCodes.get(1).getCode());
|
||||||
|
assertEquals(15, myLastMax.getValue().intValue());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
|
@ -1,24 +1,15 @@
|
||||||
package ca.uhn.fhir.rest.server;
|
package ca.uhn.fhir.rest.server;
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
|
||||||
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
|
||||||
import ca.uhn.fhir.model.api.Include;
|
import ca.uhn.fhir.model.api.Include;
|
||||||
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
import ca.uhn.fhir.rest.annotation.IncludeParam;
|
||||||
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
import ca.uhn.fhir.rest.annotation.OptionalParam;
|
||||||
import ca.uhn.fhir.rest.annotation.Search;
|
import ca.uhn.fhir.rest.annotation.Search;
|
||||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
|
||||||
import ca.uhn.fhir.rest.client.api.IGenericClient;
|
|
||||||
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
||||||
import ca.uhn.fhir.test.utilities.JettyUtil;
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
import org.eclipse.jetty.server.Server;
|
|
||||||
import org.eclipse.jetty.servlet.ServletHandler;
|
|
||||||
import org.eclipse.jetty.servlet.ServletHolder;
|
|
||||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||||
import org.hl7.fhir.r4.model.Bundle;
|
import org.hl7.fhir.r4.model.Bundle;
|
||||||
import org.hl7.fhir.r4.model.Patient;
|
import org.hl7.fhir.r4.model.Patient;
|
||||||
import org.hl7.fhir.r4.model.StringType;
|
import org.hl7.fhir.r4.model.StringType;
|
||||||
import org.junit.After;
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -27,18 +18,9 @@ import java.util.Set;
|
||||||
import static org.hamcrest.CoreMatchers.containsString;
|
import static org.hamcrest.CoreMatchers.containsString;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
public class ServerMethodSelectionR4Test {
|
public class ServerMethodSelectionR4Test extends BaseR4ServerTest {
|
||||||
|
|
||||||
|
|
||||||
private FhirContext myCtx = FhirContext.forR4();
|
|
||||||
private Server myServer;
|
|
||||||
private IGenericClient myClient;
|
|
||||||
|
|
||||||
@After
|
|
||||||
public void after() throws Exception {
|
|
||||||
JettyUtil.closeServer(myServer);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Server method with no _include
|
* Server method with no _include
|
||||||
* Client request with _include
|
* Client request with _include
|
||||||
|
@ -161,22 +143,6 @@ public class ServerMethodSelectionR4Test {
|
||||||
assertEquals(1, results.getEntry().size());
|
assertEquals(1, results.getEntry().size());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void startServer(Object theProvider) throws Exception {
|
|
||||||
RestfulServer servlet = new RestfulServer(myCtx);
|
|
||||||
servlet.registerProvider(theProvider);
|
|
||||||
ServletHandler proxyHandler = new ServletHandler();
|
|
||||||
servlet.setDefaultResponseEncoding(EncodingEnum.XML);
|
|
||||||
servlet.setBundleInclusionRule(BundleInclusionRule.BASED_ON_RESOURCE_PRESENCE);
|
|
||||||
ServletHolder servletHolder = new ServletHolder(servlet);
|
|
||||||
proxyHandler.addServletWithMapping(servletHolder, "/*");
|
|
||||||
|
|
||||||
myServer = new Server(0);
|
|
||||||
myServer.setHandler(proxyHandler);
|
|
||||||
JettyUtil.startServer(myServer);
|
|
||||||
int port = JettyUtil.getPortForStartedServer(myServer);
|
|
||||||
|
|
||||||
myClient = myCtx.newRestfulGenericClient("http://localhost:" + port);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public static class MyBaseProvider implements IResourceProvider {
|
public static class MyBaseProvider implements IResourceProvider {
|
||||||
|
@ -185,6 +151,7 @@ public class ServerMethodSelectionR4Test {
|
||||||
public Class<? extends IBaseResource> getResourceType() {
|
public Class<? extends IBaseResource> getResourceType() {
|
||||||
return Patient.class;
|
return Patient.class;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,7 +33,6 @@ import org.hl7.fhir.instance.model.api.*;
|
||||||
import org.hl7.fhir.r5.model.Bundle;
|
import org.hl7.fhir.r5.model.Bundle;
|
||||||
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
import org.hl7.fhir.r5.model.Bundle.BundleEntryComponent;
|
||||||
import org.hl7.fhir.r5.model.Bundle.BundleLinkComponent;
|
import org.hl7.fhir.r5.model.Bundle.BundleLinkComponent;
|
||||||
import org.hl7.fhir.r5.model.Bundle.HTTPVerb;
|
|
||||||
import org.hl7.fhir.r5.model.Bundle.SearchEntryMode;
|
import org.hl7.fhir.r5.model.Bundle.SearchEntryMode;
|
||||||
import org.hl7.fhir.r5.model.DomainResource;
|
import org.hl7.fhir.r5.model.DomainResource;
|
||||||
import org.hl7.fhir.r5.model.IdType;
|
import org.hl7.fhir.r5.model.IdType;
|
||||||
|
@ -45,352 +44,228 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
@SuppressWarnings("Duplicates")
|
@SuppressWarnings("Duplicates")
|
||||||
public class R5BundleFactory implements IVersionSpecificBundleFactory {
|
public class R5BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
private String myBase;
|
private String myBase;
|
||||||
private Bundle myBundle;
|
private Bundle myBundle;
|
||||||
private FhirContext myContext;
|
private FhirContext myContext;
|
||||||
|
|
||||||
public R5BundleFactory(FhirContext theContext) {
|
public R5BundleFactory(FhirContext theContext) {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
@Override
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
ensureBundle();
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
List<IAnyResource> includedResources = new ArrayList<IAnyResource>();
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
for (IBaseResource next : theResult) {
|
||||||
Resource next = (Resource) nextBaseRes;
|
if (next.getIdElement().isEmpty() == false) {
|
||||||
Set<String> containedIds = new HashSet<String>();
|
addedResourceIds.add(next.getIdElement());
|
||||||
if (next instanceof DomainResource) {
|
}
|
||||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
}
|
||||||
if (nextContained.getIdElement().isEmpty() == false) {
|
|
||||||
containedIds.add(nextContained.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, IBaseReference.class);
|
for (IBaseResource next : theResult) {
|
||||||
do {
|
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<>();
|
|
||||||
|
|
||||||
for (IBaseReference nextRef : references) {
|
Set<String> containedIds = new HashSet<String>();
|
||||||
IAnyResource nextRes = (IAnyResource) nextRef.getResource();
|
|
||||||
if (nextRes != null) {
|
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IIdType id = nextRes.getIdElement();
|
if (next instanceof DomainResource) {
|
||||||
if (id.hasResourceType() == false) {
|
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
if (isNotBlank(nextContained.getId())) {
|
||||||
id = id.withResourceType(resName);
|
containedIds.add(nextContained.getId());
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
||||||
addedResourceIds.add(id);
|
do {
|
||||||
addedResourcesThisPass.add(nextRes);
|
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||||
}
|
|
||||||
|
|
||||||
}
|
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||||
}
|
if (theBundleInclusionRule != null && !theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
IAnyResource nextRes = (IAnyResource) nextRefInfo.getResourceReference().getResource();
|
||||||
references = new ArrayList<>();
|
if (nextRes != null) {
|
||||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
if (nextRes.getIdElement().hasIdPart()) {
|
||||||
List<IBaseReference> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, IBaseReference.class);
|
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
||||||
references.addAll(newReferences);
|
// Don't add contained IDs as top level resources
|
||||||
}
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
IIdType id = nextRes.getIdElement();
|
||||||
|
if (id.hasResourceType() == false) {
|
||||||
|
String resName = myContext.getResourceDefinition(nextRes).getName();
|
||||||
|
id = id.withResourceType(resName);
|
||||||
|
}
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
if (!addedResourceIds.contains(id)) {
|
||||||
|
addedResourceIds.add(id);
|
||||||
|
addedResourcesThisPass.add(nextRes);
|
||||||
|
}
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource(next);
|
}
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
}
|
||||||
entry.setFullUrl(next.getId());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
includedResources.addAll(addedResourcesThisPass);
|
||||||
if (httpVerb != null) {
|
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
|
||||||
entry.getRequest().getUrlElement().setValue(next.getId());
|
|
||||||
}
|
|
||||||
if ("DELETE".equals(httpVerb)) {
|
|
||||||
entry.setResource(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
// Linked resources may themselves have linked resources
|
||||||
* Actually add the resources to the bundle
|
references = new ArrayList<>();
|
||||||
*/
|
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||||
for (IBaseResource next : includedResources) {
|
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
references.addAll(newReferences);
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
}
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
} while (references.isEmpty() == false);
|
||||||
entry.setFullUrl(next.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
Resource nextAsResource = (Resource) next;
|
||||||
ensureBundle();
|
IIdType id = populateBundleEntryFullUrl(next, entry);
|
||||||
|
|
||||||
List<IAnyResource> includedResources = new ArrayList<IAnyResource>();
|
// Populate Request
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(nextAsResource);
|
||||||
|
if (httpVerb != null) {
|
||||||
|
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
||||||
|
if (id != null) {
|
||||||
|
entry.getRequest().setUrl(id.getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if ("DELETE".equals(httpVerb)) {
|
||||||
|
entry.setResource(null);
|
||||||
|
}
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
// Populate Bundle.entry.response
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
if (theBundleType != null) {
|
||||||
addedResourceIds.add(next.getIdElement());
|
switch (theBundleType) {
|
||||||
}
|
case BATCH_RESPONSE:
|
||||||
}
|
case TRANSACTION_RESPONSE:
|
||||||
|
case HISTORY:
|
||||||
|
if ("1".equals(id.getVersionIdPart())) {
|
||||||
|
entry.getResponse().setStatus("201 Created");
|
||||||
|
} else if (isNotBlank(id.getVersionIdPart())) {
|
||||||
|
entry.getResponse().setStatus("200 OK");
|
||||||
|
}
|
||||||
|
if (isNotBlank(id.getVersionIdPart())) {
|
||||||
|
entry.getResponse().setEtag(RestfulServerUtils.createEtag(id.getVersionIdPart()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
// Populate Bundle.entry.search
|
||||||
|
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
||||||
|
if (searchMode != null) {
|
||||||
|
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
/*
|
||||||
|
* Actually add the resources to the bundle
|
||||||
|
*/
|
||||||
|
for (IAnyResource next : includedResources) {
|
||||||
|
BundleEntryComponent entry = myBundle.addEntry();
|
||||||
|
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||||
|
populateBundleEntryFullUrl(next, entry);
|
||||||
|
}
|
||||||
|
|
||||||
if (next instanceof DomainResource) {
|
}
|
||||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
|
||||||
if (isNotBlank(nextContained.getId())) {
|
|
||||||
containedIds.add(nextContained.getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
@Override
|
||||||
do {
|
public void addRootPropertiesToBundle(String theId, String theServerBase, String theLinkSelf, String theLinkPrev, String theLinkNext, Integer theTotalResults, BundleTypeEnum theBundleType,
|
||||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
IPrimitiveType<Date> theLastUpdated) {
|
||||||
|
ensureBundle();
|
||||||
|
|
||||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
myBase = theServerBase;
|
||||||
if (!theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IAnyResource nextRes = (IAnyResource) nextRefInfo.getResourceReference().getResource();
|
if (myBundle.getIdElement().isEmpty()) {
|
||||||
if (nextRes != null) {
|
myBundle.setId(theId);
|
||||||
if (nextRes.getIdElement().hasIdPart()) {
|
}
|
||||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
if (myBundle.getIdElement().isEmpty()) {
|
||||||
// Don't add contained IDs as top level resources
|
myBundle.setId(UUID.randomUUID().toString());
|
||||||
continue;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
IIdType id = nextRes.getIdElement();
|
if (myBundle.getMeta().getLastUpdated() == null && theLastUpdated != null) {
|
||||||
if (id.hasResourceType() == false) {
|
myBundle.getMeta().getLastUpdatedElement().setValueAsString(theLastUpdated.getValueAsString());
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
}
|
||||||
id = id.withResourceType(resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
if (!hasLink(Constants.LINK_SELF, myBundle) && isNotBlank(theLinkSelf)) {
|
||||||
addedResourceIds.add(id);
|
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theLinkSelf);
|
||||||
addedResourcesThisPass.add(nextRes);
|
}
|
||||||
}
|
if (!hasLink(Constants.LINK_NEXT, myBundle) && isNotBlank(theLinkNext)) {
|
||||||
|
myBundle.addLink().setRelation(Constants.LINK_NEXT).setUrl(theLinkNext);
|
||||||
|
}
|
||||||
|
if (!hasLink(Constants.LINK_PREVIOUS, myBundle) && isNotBlank(theLinkPrev)) {
|
||||||
|
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS).setUrl(theLinkPrev);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
if (myBundle.getTypeElement().isEmpty() && theBundleType != null) {
|
||||||
}
|
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
||||||
}
|
}
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
if (myBundle.getTotalElement().isEmpty() && theTotalResults != null) {
|
||||||
|
myBundle.getTotalElement().setValue(theTotalResults);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
private void ensureBundle() {
|
||||||
references = new ArrayList<>();
|
if (myBundle == null) {
|
||||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
myBundle = new Bundle();
|
||||||
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
}
|
||||||
references.addAll(newReferences);
|
}
|
||||||
}
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
BundleEntryComponent entry = myBundle.addEntry().setResource((Resource) next);
|
@Override
|
||||||
Resource nextAsResource = (Resource) next;
|
public IBaseResource getResourceBundle() {
|
||||||
IIdType id = populateBundleEntryFullUrl(next, entry);
|
return myBundle;
|
||||||
|
}
|
||||||
|
|
||||||
// Populate Request
|
private boolean hasLink(String theLinkType, Bundle theBundle) {
|
||||||
String httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(nextAsResource);
|
for (BundleLinkComponent next : theBundle.getLink()) {
|
||||||
if (httpVerb != null) {
|
if (theLinkType.equals(next.getRelation())) {
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb);
|
return true;
|
||||||
if (id != null) {
|
}
|
||||||
entry.getRequest().setUrl(id.getValue());
|
}
|
||||||
}
|
return false;
|
||||||
}
|
}
|
||||||
if ("DELETE".equals(httpVerb)) {
|
|
||||||
entry.setResource(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate Bundle.entry.response
|
|
||||||
if (theBundleType != null) {
|
|
||||||
switch (theBundleType) {
|
|
||||||
case BATCH_RESPONSE:
|
|
||||||
case TRANSACTION_RESPONSE:
|
|
||||||
case HISTORY:
|
|
||||||
if ("1".equals(id.getVersionIdPart())) {
|
|
||||||
entry.getResponse().setStatus("201 Created");
|
|
||||||
} else if (isNotBlank(id.getVersionIdPart())) {
|
|
||||||
entry.getResponse().setStatus("200 OK");
|
|
||||||
}
|
|
||||||
if (isNotBlank(id.getVersionIdPart())) {
|
|
||||||
entry.getResponse().setEtag(RestfulServerUtils.createEtag(id.getVersionIdPart()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Populate Bundle.entry.search
|
@Override
|
||||||
String searchMode = ResourceMetadataKeyEnum.ENTRY_SEARCH_MODE.get(nextAsResource);
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
if (searchMode != null) {
|
myBundle = (Bundle) theBundle;
|
||||||
entry.getSearch().getModeElement().setValueAsString(searchMode);
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
private IIdType populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
||||||
* Actually add the resources to the bundle
|
IIdType idElement = null;
|
||||||
*/
|
if (next.getIdElement().hasBaseUrl()) {
|
||||||
for (IAnyResource next : includedResources) {
|
idElement = next.getIdElement();
|
||||||
BundleEntryComponent entry = myBundle.addEntry();
|
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
} else {
|
||||||
populateBundleEntryFullUrl(next, entry);
|
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
||||||
}
|
idElement = next.getIdElement();
|
||||||
|
idElement = idElement.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
||||||
|
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return idElement;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public List<IBaseResource> toListOfResources() {
|
||||||
@Override
|
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||||
public void addRootPropertiesToBundle(String theId, String theServerBase, String theLinkSelf, String theLinkPrev, String theLinkNext, Integer theTotalResults, BundleTypeEnum theBundleType,
|
for (BundleEntryComponent next : myBundle.getEntry()) {
|
||||||
IPrimitiveType<Date> theLastUpdated) {
|
if (next.getResource() != null) {
|
||||||
ensureBundle();
|
retVal.add(next.getResource());
|
||||||
|
} else if (next.getResponse().getLocationElement().isEmpty() == false) {
|
||||||
myBase = theServerBase;
|
IdType id = new IdType(next.getResponse().getLocation());
|
||||||
|
String resourceType = id.getResourceType();
|
||||||
if (myBundle.getIdElement().isEmpty()) {
|
if (isNotBlank(resourceType)) {
|
||||||
myBundle.setId(theId);
|
IAnyResource res = (IAnyResource) myContext.getResourceDefinition(resourceType).newInstance();
|
||||||
}
|
res.setId(id);
|
||||||
if (myBundle.getIdElement().isEmpty()) {
|
retVal.add(res);
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (myBundle.getMeta().getLastUpdated() == null && theLastUpdated != null) {
|
return retVal;
|
||||||
myBundle.getMeta().getLastUpdatedElement().setValueAsString(theLastUpdated.getValueAsString());
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!hasLink(Constants.LINK_SELF, myBundle) && isNotBlank(theLinkSelf)) {
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theLinkSelf);
|
|
||||||
}
|
|
||||||
if (!hasLink(Constants.LINK_NEXT, myBundle) && isNotBlank(theLinkNext)) {
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_NEXT).setUrl(theLinkNext);
|
|
||||||
}
|
|
||||||
if (!hasLink(Constants.LINK_PREVIOUS, myBundle) && isNotBlank(theLinkPrev)) {
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS).setUrl(theLinkPrev);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myBundle.getTypeElement().isEmpty() && theBundleType != null) {
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (myBundle.getTotalElement().isEmpty() && theTotalResults != null) {
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureBundle() {
|
|
||||||
if (myBundle == null) {
|
|
||||||
myBundle = new Bundle();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public IBaseResource getResourceBundle() {
|
|
||||||
return myBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean hasLink(String theLinkType, Bundle theBundle) {
|
|
||||||
for (BundleLinkComponent next : theBundle.getLink()) {
|
|
||||||
if (theLinkType.equals(next.getRelation())) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
|
||||||
BundleTypeEnum theBundleType) {
|
|
||||||
myBundle = new Bundle();
|
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
myBundle.getMeta().setLastUpdated(new Date());
|
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
|
||||||
Resource next = (Resource) nextBaseRes;
|
|
||||||
BundleEntryComponent nextEntry = myBundle.addEntry();
|
|
||||||
|
|
||||||
nextEntry.setResource(next);
|
|
||||||
if (next.getIdElement().isEmpty()) {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.POST);
|
|
||||||
} else {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerb.PUT);
|
|
||||||
if (next.getIdElement().isAbsolute()) {
|
|
||||||
nextEntry.getRequest().setUrl(next.getId());
|
|
||||||
} else {
|
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
|
||||||
nextEntry.getRequest().setUrl(new IdType(theServerBase, resourceType, next.getIdElement().getIdPart(), next.getIdElement().getVersionIdPart()).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
|
||||||
myBundle = (Bundle) theBundle;
|
|
||||||
}
|
|
||||||
|
|
||||||
private IIdType populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
|
||||||
IIdType idElement = null;
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
idElement = next.getIdElement();
|
|
||||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
|
||||||
} else {
|
|
||||||
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
|
||||||
idElement = next.getIdElement();
|
|
||||||
idElement = idElement.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
|
||||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return idElement;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<IBaseResource> toListOfResources() {
|
|
||||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
|
||||||
for (BundleEntryComponent next : myBundle.getEntry()) {
|
|
||||||
if (next.getResource() != null) {
|
|
||||||
retVal.add(next.getResource());
|
|
||||||
} else if (next.getResponse().getLocationElement().isEmpty() == false) {
|
|
||||||
IdType id = new IdType(next.getResponse().getLocation());
|
|
||||||
String resourceType = id.getResourceType();
|
|
||||||
if (isNotBlank(resourceType)) {
|
|
||||||
IAnyResource res = (IAnyResource) myContext.getResourceDefinition(resourceType).newInstance();
|
|
||||||
res.setId(id);
|
|
||||||
retVal.add(res);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return retVal;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,27 +19,32 @@ package ca.uhn.fhir.rest.server.provider.dstu2;
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
* #L%
|
* #L%
|
||||||
*/
|
*/
|
||||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
|
||||||
|
|
||||||
import java.util.*;
|
|
||||||
|
|
||||||
import org.hl7.fhir.instance.model.api.*;
|
|
||||||
|
|
||||||
import ca.uhn.fhir.context.FhirContext;
|
import ca.uhn.fhir.context.FhirContext;
|
||||||
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
import ca.uhn.fhir.context.api.BundleInclusionRule;
|
||||||
import ca.uhn.fhir.model.api.*;
|
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.base.composite.BaseResourceReferenceDt;
|
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
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.Entry;
|
||||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
|
import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.HTTPVerbEnum;
|
|
||||||
import ca.uhn.fhir.model.dstu2.valueset.SearchEntryModeEnum;
|
import ca.uhn.fhir.model.dstu2.valueset.SearchEntryModeEnum;
|
||||||
import ca.uhn.fhir.model.primitive.IdDt;
|
import ca.uhn.fhir.model.primitive.IdDt;
|
||||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||||
import ca.uhn.fhir.model.valueset.*;
|
import ca.uhn.fhir.model.valueset.BundleEntrySearchModeEnum;
|
||||||
|
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||||
|
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||||
import ca.uhn.fhir.rest.api.Constants;
|
import ca.uhn.fhir.rest.api.Constants;
|
||||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||||
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
import ca.uhn.fhir.util.ResourceReferenceInfo;
|
||||||
|
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 java.util.*;
|
||||||
|
|
||||||
|
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||||
|
|
||||||
public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
private Bundle myBundle;
|
private Bundle myBundle;
|
||||||
|
@ -50,86 +55,6 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
myContext = theContext;
|
myContext = theContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
|
||||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
|
||||||
Set<IIdType> addedResourceIds = new HashSet<IIdType>();
|
|
||||||
|
|
||||||
for (IBaseResource next : theResult) {
|
|
||||||
if (next.getIdElement().isEmpty() == false) {
|
|
||||||
addedResourceIds.add(next.getIdElement());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (IBaseResource nextBaseRes : theResult) {
|
|
||||||
IResource next = (IResource) nextBaseRes;
|
|
||||||
Set<String> containedIds = new HashSet<String>();
|
|
||||||
for (IResource nextContained : next.getContained().getContainedResources()) {
|
|
||||||
if (nextContained.getId().isEmpty() == false) {
|
|
||||||
containedIds.add(nextContained.getId().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
List<BaseResourceReferenceDt> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next, BaseResourceReferenceDt.class);
|
|
||||||
do {
|
|
||||||
List<IResource> addedResourcesThisPass = new ArrayList<IResource>();
|
|
||||||
|
|
||||||
for (BaseResourceReferenceDt nextRef : references) {
|
|
||||||
IResource nextRes = (IResource) nextRef.getResource();
|
|
||||||
if (nextRes != null) {
|
|
||||||
if (nextRes.getId().hasIdPart()) {
|
|
||||||
if (containedIds.contains(nextRes.getId().getValue())) {
|
|
||||||
// Don't add contained IDs as top level resources
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
IdDt id = nextRes.getId();
|
|
||||||
if (id.hasResourceType() == false) {
|
|
||||||
String resName = myContext.getResourceDefinition(nextRes).getName();
|
|
||||||
id = id.withResourceType(resName);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!addedResourceIds.contains(id)) {
|
|
||||||
addedResourceIds.add(id);
|
|
||||||
addedResourcesThisPass.add(nextRes);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Linked resources may themselves have linked resources
|
|
||||||
references = new ArrayList<BaseResourceReferenceDt>();
|
|
||||||
for (IResource iResource : addedResourcesThisPass) {
|
|
||||||
List<BaseResourceReferenceDt> newReferences = myContext.newTerser().getAllPopulatedChildElementsOfType(iResource, BaseResourceReferenceDt.class);
|
|
||||||
references.addAll(newReferences);
|
|
||||||
}
|
|
||||||
|
|
||||||
includedResources.addAll(addedResourcesThisPass);
|
|
||||||
|
|
||||||
} while (references.isEmpty() == false);
|
|
||||||
|
|
||||||
Entry entry = myBundle.addEntry().setResource(next);
|
|
||||||
if (next.getId().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getId().getValue());
|
|
||||||
}
|
|
||||||
BundleEntryTransactionMethodEnum httpVerb = ResourceMetadataKeyEnum.ENTRY_TRANSACTION_METHOD.get(next);
|
|
||||||
if (httpVerb != null) {
|
|
||||||
entry.getRequest().getMethodElement().setValueAsString(httpVerb.getCode());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Actually add the resources to the bundle
|
|
||||||
*/
|
|
||||||
for (IBaseResource next : includedResources) {
|
|
||||||
Entry entry = myBundle.addEntry();
|
|
||||||
entry.setResource((IResource) next).getSearch().setMode(SearchEntryModeEnum.INCLUDE);
|
|
||||||
if (next.getIdElement().hasBaseUrl()) {
|
|
||||||
entry.setFullUrl(next.getIdElement().getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||||
if (myBundle == null) {
|
if (myBundle == null) {
|
||||||
|
@ -282,44 +207,6 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults,
|
|
||||||
BundleTypeEnum theBundleType) {
|
|
||||||
myBundle = new Bundle();
|
|
||||||
|
|
||||||
myBundle.setId(UUID.randomUUID().toString());
|
|
||||||
|
|
||||||
ResourceMetadataKeyEnum.PUBLISHED.put(myBundle, InstantDt.withCurrentTime());
|
|
||||||
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_FHIR_BASE).setUrl(theServerBase);
|
|
||||||
myBundle.addLink().setRelation(Constants.LINK_SELF).setUrl(theCompleteUrl);
|
|
||||||
myBundle.getTypeElement().setValueAsString(theBundleType.getCode());
|
|
||||||
|
|
||||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
|
||||||
for (IBaseResource nextBaseRes : theResources) {
|
|
||||||
IResource next = (IResource) nextBaseRes;
|
|
||||||
Entry nextEntry = myBundle.addEntry();
|
|
||||||
|
|
||||||
nextEntry.setResource(next);
|
|
||||||
if (next.getId().isEmpty()) {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerbEnum.POST);
|
|
||||||
} else {
|
|
||||||
nextEntry.getRequest().setMethod(HTTPVerbEnum.PUT);
|
|
||||||
if (next.getId().isAbsolute()) {
|
|
||||||
nextEntry.getRequest().setUrl(next.getId());
|
|
||||||
} else {
|
|
||||||
String resourceType = myContext.getResourceDefinition(next).getName();
|
|
||||||
nextEntry.getRequest().setUrl(new IdDt(theServerBase, resourceType, next.getId().getIdPart(), next.getId().getVersionIdPart()).getValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
addResourcesForSearch(theResources);
|
|
||||||
}
|
|
||||||
|
|
||||||
myBundle.getTotalElement().setValue(theTotalResults);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void initializeWithBundleResource(IBaseResource theBundle) {
|
public void initializeWithBundleResource(IBaseResource theBundle) {
|
||||||
myBundle = (Bundle) theBundle;
|
myBundle = (Bundle) theBundle;
|
||||||
|
|
25
pom.xml
25
pom.xml
|
@ -601,7 +601,7 @@
|
||||||
<!--<hibernate_version>5.2.10.Final</hibernate_version>-->
|
<!--<hibernate_version>5.2.10.Final</hibernate_version>-->
|
||||||
<hibernate_version>5.4.4.Final</hibernate_version>
|
<hibernate_version>5.4.4.Final</hibernate_version>
|
||||||
<!-- Update lucene version when you update hibernate-search version -->
|
<!-- Update lucene version when you update hibernate-search version -->
|
||||||
<hibernate_search_version>5.11.1.Final</hibernate_search_version>
|
<hibernate_search_version>5.11.3.Final</hibernate_search_version>
|
||||||
<lucene_version>5.5.5</lucene_version>
|
<lucene_version>5.5.5</lucene_version>
|
||||||
<hibernate_validator_version>5.4.2.Final</hibernate_validator_version>
|
<hibernate_validator_version>5.4.2.Final</hibernate_validator_version>
|
||||||
<httpcore_version>4.4.11</httpcore_version>
|
<httpcore_version>4.4.11</httpcore_version>
|
||||||
|
@ -858,18 +858,6 @@
|
||||||
<!--<version>6.2.2.jre8</version>-->
|
<!--<version>6.2.2.jre8</version>-->
|
||||||
<version>7.0.0.jre8</version>
|
<version>7.0.0.jre8</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!--
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.sun.xml.bind</groupId>
|
|
||||||
<artifactId>jaxb-core</artifactId>
|
|
||||||
<version>${jaxb_core_version}</version>
|
|
||||||
</dependency>
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.sun.xml.bind</groupId>
|
|
||||||
<artifactId>jaxb-impl</artifactId>
|
|
||||||
<version>${jaxb_core_version}</version>
|
|
||||||
</dependency>
|
|
||||||
-->
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>javax.mail</groupId>
|
<groupId>javax.mail</groupId>
|
||||||
<artifactId>javax.mail-api</artifactId>
|
<artifactId>javax.mail-api</artifactId>
|
||||||
|
@ -1411,6 +1399,11 @@
|
||||||
<artifactId>xmlunit-core</artifactId>
|
<artifactId>xmlunit-core</artifactId>
|
||||||
<version>2.4.0</version>
|
<version>2.4.0</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>pl.allegro.tech</groupId>
|
||||||
|
<artifactId>embedded-elasticsearch</artifactId>
|
||||||
|
<version>2.10.0</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>xpp3</groupId>
|
<groupId>xpp3</groupId>
|
||||||
<artifactId>xpp3</artifactId>
|
<artifactId>xpp3</artifactId>
|
||||||
|
@ -1675,6 +1668,11 @@
|
||||||
<groupId>org.jacoco</groupId>
|
<groupId>org.jacoco</groupId>
|
||||||
<artifactId>jacoco-maven-plugin</artifactId>
|
<artifactId>jacoco-maven-plugin</artifactId>
|
||||||
<version>0.8.4</version>
|
<version>0.8.4</version>
|
||||||
|
<configuration>
|
||||||
|
<excludes>
|
||||||
|
<exclude>ca/uhn/fhir/model/dstu2/**/*.class</exclude>
|
||||||
|
</excludes>
|
||||||
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
<plugin>
|
<plugin>
|
||||||
<groupId>org.apache.maven.plugins</groupId>
|
<groupId>org.apache.maven.plugins</groupId>
|
||||||
|
@ -2397,7 +2395,6 @@
|
||||||
<module>hapi-fhir-jaxrsserver-base</module>
|
<module>hapi-fhir-jaxrsserver-base</module>
|
||||||
<module>hapi-fhir-jaxrsserver-example</module>
|
<module>hapi-fhir-jaxrsserver-example</module>
|
||||||
<module>hapi-fhir-jpaserver-base</module>
|
<module>hapi-fhir-jpaserver-base</module>
|
||||||
<module>hapi-fhir-jpaserver-elasticsearch</module>
|
|
||||||
<module>hapi-fhir-jpaserver-migrate</module>
|
<module>hapi-fhir-jpaserver-migrate</module>
|
||||||
<module>restful-server-example</module>
|
<module>restful-server-example</module>
|
||||||
<module>hapi-fhir-testpage-overlay</module>
|
<module>hapi-fhir-testpage-overlay</module>
|
||||||
|
|
|
@ -12,7 +12,8 @@
|
||||||
latest versions (dependent HAPI modules listed in brackets):
|
latest versions (dependent HAPI modules listed in brackets):
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
<ul>
|
<ul>
|
||||||
<li>Hibernate Core (Core): 5.4.2.Final -> 5.4.4.Final</li>
|
<li>Hibernate Core (JPA): 5.4.2.Final -> 5.4.4.Final</li>
|
||||||
|
<li>Hibernate Search (JPA): 5.11.1.Final -> 5.11.3.Final</li>
|
||||||
<li>Jackson Databind (JPA): 2.9.9 -> 2.9.10 (CVE-2019-16335, CVE-2019-14540)</li>
|
<li>Jackson Databind (JPA): 2.9.9 -> 2.9.10 (CVE-2019-16335, CVE-2019-14540)</li>
|
||||||
</ul>
|
</ul>
|
||||||
]]>
|
]]>
|
||||||
|
@ -40,9 +41,19 @@
|
||||||
only system level export is currently supported but others will follow.
|
only system level export is currently supported but others will follow.
|
||||||
]]>
|
]]>
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
<![CDATA[
|
||||||
|
<b>New Feature</b>:
|
||||||
|
Support for ElasticSearch has been added to the JPA server directly (i.e. without needing a separate
|
||||||
|
module) and a new class called "ElasticsearchHibernatePropertiesBuilder" has been added to facilitate
|
||||||
|
the creation of relevant properties. Instructions have been added to the hapi-fhir-jpaserver-starter
|
||||||
|
project to get started with Elasticsearch. It is likely we will switch our default recommendation
|
||||||
|
to Elastic in the future.
|
||||||
|
]]>
|
||||||
|
</action>
|
||||||
<action type="add" issue="1489">
|
<action type="add" issue="1489">
|
||||||
<![CDATA[
|
<![CDATA[
|
||||||
<b>Improovement</b>:
|
<b>Improvement</b>:
|
||||||
A significant performance improvement was made to the parsers (particularly the Json Parser)
|
A significant performance improvement was made to the parsers (particularly the Json Parser)
|
||||||
when serializing resources. This work yields improvements of 20-50% in raw encode speed when
|
when serializing resources. This work yields improvements of 20-50% in raw encode speed when
|
||||||
encoding large resources. Thanks to David Maplesden for the pull request!
|
encoding large resources. Thanks to David Maplesden for the pull request!
|
||||||
|
@ -90,11 +101,11 @@
|
||||||
The informational message returned in an OperationOutcome when a delete failed due to cascades not being enabled
|
The informational message returned in an OperationOutcome when a delete failed due to cascades not being enabled
|
||||||
contained an incorrect example. This has been corrected.
|
contained an incorrect example. This has been corrected.
|
||||||
</action>
|
</action>
|
||||||
<action type="fix">
|
<action type="fix">
|
||||||
In some cases, deleting a CodeSystem resource would fail because the underlying
|
In some cases, deleting a CodeSystem resource would fail because the underlying
|
||||||
codes were not correctly deleted from the terminology service tables. This is
|
codes were not correctly deleted from the terminology service tables. This is
|
||||||
fixed.
|
fixed.
|
||||||
</action>
|
</action>
|
||||||
<action type="change">
|
<action type="change">
|
||||||
Two foreign keys have been dropped from the HFJ_SEARCH_RESULT table used by the FHIR search query cache. These
|
Two foreign keys have been dropped from the HFJ_SEARCH_RESULT table used by the FHIR search query cache. These
|
||||||
constraints did not add value and caused unneccessary contention when used under high load.
|
constraints did not add value and caused unneccessary contention when used under high load.
|
||||||
|
@ -114,7 +125,7 @@
|
||||||
leaving the Bundle.entry.request.method blank in DSTU3 transactions and setting the request payload
|
leaving the Bundle.entry.request.method blank in DSTU3 transactions and setting the request payload
|
||||||
as a Binary resource containing a valid patch.
|
as a Binary resource containing a valid patch.
|
||||||
</action>
|
</action>
|
||||||
<action type="change" issue="1366">
|
<action type="change">
|
||||||
The HAPI FHIR CLI server now uses H2 as its database platform instead of Derby.
|
The HAPI FHIR CLI server now uses H2 as its database platform instead of Derby.
|
||||||
Note that this means that data in any existing installations will need to be
|
Note that this means that data in any existing installations will need to be
|
||||||
re-uploaded to the new database platform.
|
re-uploaded to the new database platform.
|
||||||
|
@ -218,10 +229,64 @@
|
||||||
handled by method implementations that did not have any <![CDATA[<code>@IncludeParam</code>]]> defined. This
|
handled by method implementations that did not have any <![CDATA[<code>@IncludeParam</code>]]> defined. This
|
||||||
is now corrected. Thanks to Tuomo Ala-Vannesluoma for reporting and providing a test case!
|
is now corrected. Thanks to Tuomo Ala-Vannesluoma for reporting and providing a test case!
|
||||||
</action>
|
</action>
|
||||||
|
<action type="add" issue="1366">
|
||||||
|
The ValueSet operation <![CDATA[<code>$expand</code>]]> has been optimized for large ValueSets. ValueSets are
|
||||||
|
now persistence-backed by the terminology tables, which are populated by a scheduled pre-expansion process.
|
||||||
|
A ValueSet previously stored in an existing FHIR repository will need to be re-created or updated to make
|
||||||
|
it a candidate for pre-expansion. ValueSets that have yet to be pre-expanded will continue to be expanded
|
||||||
|
in-memory.
|
||||||
|
</action>
|
||||||
|
<action type="add" issue="1431">
|
||||||
|
The ValueSet operation <![CDATA[<code>$validate-code</code>]]> has been optimized for large ValueSets.
|
||||||
|
Codes in ValueSets that have yet to be pre-expanded will continue to be validated in-memory.
|
||||||
|
</action>
|
||||||
|
<action type="add" issue="1447">
|
||||||
|
LOINC filenames for terminology upload are now configurable using the
|
||||||
|
<![CDATA[<code>loincupload.properties</code>]]> file.
|
||||||
|
</action>
|
||||||
|
<action type="add" issue="1451">
|
||||||
|
Support for the LOINC <![CDATA[<code>EXTERNAL_COPYRIGHT_NOTICE</code>]]> property and
|
||||||
|
<![CDATA[<code>copyright</code>]]> filter has been added.
|
||||||
|
</action>
|
||||||
|
<action type="add" issue="1453">
|
||||||
|
Support for the LOINC <![CDATA[<code>parent</code>]]> and <![CDATA[<code>child</code>]]> filters has been
|
||||||
|
added. Both filters can be used with either of the <![CDATA[<code>=</code>]]> or
|
||||||
|
<![CDATA[<code>in</code>]]> operators.
|
||||||
|
</action>
|
||||||
|
<action type="add" issue="1454">
|
||||||
|
Support for the LOINC <![CDATA[<code>ancestor</code>]]> and <![CDATA[<code>descendant</code>]]> filters has
|
||||||
|
been added. The <![CDATA[<code>descendant</code>]]> filter can be used with either of the
|
||||||
|
<![CDATA[<code>=</code>]]> or <![CDATA[<code>in</code>]]> operators. At present, the
|
||||||
|
<![CDATA[<code>ancestor</code>]]> filter can only be used with the <![CDATA[<code>=</code>]]> operator.
|
||||||
|
</action>
|
||||||
|
<action type="add" issue="1512">
|
||||||
|
Support for the LOINC <![CDATA[<code>ancestor</code>]]> filter with the <![CDATA[<code>in</code>]]>
|
||||||
|
operator has been added.
|
||||||
|
</action>
|
||||||
<action type="fix">
|
<action type="fix">
|
||||||
The JPA server failed to find codes defined in not-present codesystems in some cases, and reported
|
The JPA server failed to find codes defined in not-present codesystems in some cases, and reported
|
||||||
that the CodeSystem did not exist. This has been corrected.
|
that the CodeSystem did not exist. This has been corrected.
|
||||||
</action>
|
</action>
|
||||||
|
<action type="remove">
|
||||||
|
The method
|
||||||
|
<![CDATA[
|
||||||
|
<code>IVersionSpecificBundleFactory#initializeBundleFromResourceList</code>
|
||||||
|
]]>
|
||||||
|
has been deprecated, as it provided duplicate functionality to other methods and had an
|
||||||
|
outdated argument list based on the Bundle needs in DSTU1. We are not aware of any
|
||||||
|
public use of this API, please let us know if this deprecation causes any issues.
|
||||||
|
</action>
|
||||||
|
<action type="add" issue="1517">
|
||||||
|
Support for concept property values with a length exceeding 500 characters has been added in the terminology
|
||||||
|
tables. In particular, this was added to facilitate the LOINC EXTERNAL_COPYRIGHT_NOTICE property, for which
|
||||||
|
values can be quite long.
|
||||||
|
</action>
|
||||||
|
<action type="add">
|
||||||
|
The AuthorizationInterceptor has been enhanced so that a user can be authorized to
|
||||||
|
perform create operations specifically, without authorizing all write operations. Also,
|
||||||
|
conditional creates can now be authorized even if they are happening inside a FHIR
|
||||||
|
transaction.
|
||||||
|
</action>
|
||||||
</release>
|
</release>
|
||||||
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
|
<release version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
|
||||||
<action type="fix">
|
<action type="fix">
|
||||||
|
|
Loading…
Reference in New Issue