Improvements to AutohrizationInterceptor create handling
This commit is contained in:
parent
aeef8c1ab5
commit
066c9a7fb7
|
@ -29,6 +29,7 @@ import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
|||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
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 java.io.Serializable;
|
||||
|
@ -629,5 +630,5 @@ public abstract class ResourceMetadataKeyEnum<T> implements Serializable {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -46,12 +46,14 @@ public class BundleUtil {
|
|||
private final RequestTypeEnum myRequestType;
|
||||
private final IBaseResource myResource;
|
||||
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();
|
||||
myRequestType = theRequestType;
|
||||
myUrl = theUrl;
|
||||
myResource = theResource;
|
||||
myConditionalUrl = theConditionalUrl;
|
||||
}
|
||||
|
||||
public RequestTypeEnum getRequestType() {
|
||||
|
@ -62,6 +64,10 @@ public class BundleUtil {
|
|||
return myResource;
|
||||
}
|
||||
|
||||
public String getConditionalUrl() {
|
||||
return myConditionalUrl;
|
||||
}
|
||||
|
||||
public String getUrl() {
|
||||
return myUrl;
|
||||
}
|
||||
|
@ -190,19 +196,21 @@ public class BundleUtil {
|
|||
BaseRuntimeChildDefinition resourceChild = entryChildElem.getChildByName("resource");
|
||||
BaseRuntimeChildDefinition requestChild = entryChildElem.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");
|
||||
|
||||
for (IBase nextEntry : entries) {
|
||||
IBaseResource resource = null;
|
||||
String url = null;
|
||||
RequestTypeEnum requestType = null;
|
||||
String conditionalUrl = null;
|
||||
|
||||
for (IBase next : resourceChild.getAccessor().getValues(nextEntry)) {
|
||||
resource = (IBaseResource) next;
|
||||
}
|
||||
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();
|
||||
}
|
||||
for (IBase nextUrl : methodChild.getAccessor().getValues(nextRequest)) {
|
||||
|
@ -211,13 +219,29 @@ public class BundleUtil {
|
|||
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
|
||||
* order in the original bundle.
|
||||
*/
|
||||
retVal.add(new BundleEntryParts(requestType, url, resource));
|
||||
retVal.add(new BundleEntryParts(requestType, url, resource, conditionalUrl));
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -1540,53 +1540,6 @@ public class GenericOkHttpClientDstu2Test {
|
|||
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
|
||||
public void testTransactionWithString() throws Exception {
|
||||
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.model.api.IQueryParameterType;
|
||||
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.resource.BaseOperationOutcome;
|
||||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.UriDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleEntryTransactionMethodEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.*;
|
||||
|
@ -2046,7 +2049,35 @@ public class GenericClient extends BaseClient implements IGenericClient {
|
|||
@Override
|
||||
public ITransactionTyped<List<IBaseResource>> withResources(List<? extends IBaseResource> theResources) {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1722,7 +1722,7 @@ public class GenericJaxRsClientDstu2Test {
|
|||
|
||||
Patient p2 = new Patient(); // Yes ID
|
||||
p2.addName().addFamily("PATIENT2");
|
||||
p2.setId("Patient/2");
|
||||
p2.setId("http://example.com/Patient/2");
|
||||
input.add(p2);
|
||||
|
||||
|
||||
|
@ -1740,7 +1740,7 @@ public class GenericJaxRsClientDstu2Test {
|
|||
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());
|
||||
assertEquals("http://example.com/Patient/2", requestBundle.getEntry().get(1).getFullUrl());
|
||||
|
||||
p1 = (Patient) response.get(0);
|
||||
assertEquals(new IdDt("Patient/1/_history/1"), p1.getId().toUnqualified());
|
||||
|
|
|
@ -1758,7 +1758,7 @@ public class GenericJaxRsClientDstu3Test {
|
|||
|
||||
Patient p2 = new Patient(); // Yes ID
|
||||
p2.addName().setFamily("PATIENT2");
|
||||
p2.setId("Patient/2");
|
||||
p2.setId("http://example.com/Patient/2");
|
||||
input.add(p2);
|
||||
|
||||
//@formatter:off
|
||||
|
@ -1776,7 +1776,7 @@ public class GenericJaxRsClientDstu3Test {
|
|||
assertEquals(2, requestBundle.getEntry().size());
|
||||
assertEquals(HTTPVerb.POST, requestBundle.getEntry().get(0).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);
|
||||
assertEquals(new IdType("Patient/1/_history/1"), p1.getIdElement());
|
||||
|
|
|
@ -42,14 +42,6 @@ public final class MetadataKeyCurrentlyReindexing extends ResourceMetadataKeySup
|
|||
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
|
||||
public void put(IAnyResource theResource, Boolean theObject) {
|
||||
theResource.setUserData(IDao.CURRENTLY_REINDEXING.name(), theObject);
|
||||
|
|
|
@ -4,21 +4,20 @@ import ca.uhn.fhir.jpa.interceptor.CascadingDeleteInterceptor;
|
|||
import ca.uhn.fhir.model.primitive.IdDt;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.server.exceptions.AuthenticationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ForbiddenOperationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.ResourceGoneException;
|
||||
import ca.uhn.fhir.rest.server.interceptor.auth.AuthorizationInterceptor;
|
||||
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.rest.server.interceptor.auth.*;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.apache.http.client.methods.CloseableHttpResponse;
|
||||
import org.apache.http.client.methods.HttpDelete;
|
||||
import org.apache.http.client.methods.HttpPost;
|
||||
import org.apache.http.entity.ContentType;
|
||||
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.r4.model.*;
|
||||
import org.hl7.fhir.r4.model.Observation.ObservationStatus;
|
||||
|
@ -156,7 +155,22 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
|||
@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();
|
||||
}
|
||||
});
|
||||
|
@ -177,19 +191,16 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
|||
Bundle response = ourClient.transaction().withBundle(request).execute();
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(response));
|
||||
|
||||
try {
|
||||
ourClient.update().resource(patient).execute();
|
||||
fail();
|
||||
} catch (ForbiddenOperationException e) {
|
||||
assertEquals("HTTP 403 Forbidden: Access denied by default policy (no applicable rules)", e.getMessage());
|
||||
}
|
||||
// Subsequent calls also shouldn't fail
|
||||
ourClient.transaction().withBundle(request).execute();
|
||||
ourClient.transaction().withBundle(request).execute();
|
||||
}
|
||||
|
||||
// Create a patient (blocked)
|
||||
// Create a patient with wrong identifier (blocked)
|
||||
{
|
||||
Patient patient = new Patient();
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("100");
|
||||
patient.addName().setFamily("Tester").addGiven("Raghad");
|
||||
patient.addIdentifier().setSystem("http://uhn.ca/mrns").setValue("101");
|
||||
patient.addName().setFamily("Tester").addGiven("Fozzie");
|
||||
|
||||
Bundle request = new Bundle();
|
||||
request.setType(Bundle.BundleType.TRANSACTION);
|
||||
|
@ -197,12 +208,31 @@ public class AuthorizationInterceptorResourceProviderR4Test extends BaseResource
|
|||
.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));
|
||||
.setIfNoneExist("Patient?identifier=http://uhn.ca/mrns|101");
|
||||
|
||||
try {
|
||||
ourClient.update().resource(patient).execute();
|
||||
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());
|
||||
|
|
|
@ -73,6 +73,7 @@ public abstract class RequestDetails {
|
|||
private Map<Object, Object> myUserData;
|
||||
private IBaseResource myResource;
|
||||
private String myRequestId;
|
||||
private String myFixedConditionalUrl;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
|
@ -81,6 +82,14 @@ public abstract class RequestDetails {
|
|||
myInterceptorBroadcaster = theInterceptorBroadcaster;
|
||||
}
|
||||
|
||||
public String getFixedConditionalUrl() {
|
||||
return myFixedConditionalUrl;
|
||||
}
|
||||
|
||||
public void setFixedConditionalUrl(String theFixedConditionalUrl) {
|
||||
myFixedConditionalUrl = theFixedConditionalUrl;
|
||||
}
|
||||
|
||||
public String getRequestId() {
|
||||
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
|
||||
*/
|
||||
public String getConditionalUrl(RestOperationTypeEnum theOperationType) {
|
||||
if (myFixedConditionalUrl != null) {
|
||||
return myFixedConditionalUrl;
|
||||
}
|
||||
switch (theOperationType) {
|
||||
case CREATE:
|
||||
String retVal = this.getHeader(Constants.HEADER_IF_NONE_EXIST);
|
||||
|
|
|
@ -108,8 +108,17 @@ public interface IAuthRuleBuilderRule {
|
|||
*/
|
||||
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
|
||||
*/
|
||||
IAuthRuleBuilderGraphQL graphQL();
|
||||
|
||||
}
|
||||
|
|
|
@ -253,6 +253,14 @@ public class RuleBuilder implements IAuthRuleBuilder {
|
|||
return myWriteRuleBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAuthRuleBuilderRuleOp create() {
|
||||
if (myWriteRuleBuilder == null) {
|
||||
myWriteRuleBuilder = new RuleBuilderRuleOp(RuleOpEnum.CREATE);
|
||||
}
|
||||
return myWriteRuleBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IAuthRuleBuilderGraphQL graphQL() {
|
||||
return new RuleBuilderGraphQL();
|
||||
|
|
|
@ -207,6 +207,19 @@ class RuleImplOp extends BaseRule /* implements IAuthRule */ {
|
|||
return null;
|
||||
}
|
||||
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:
|
||||
if (theOperation == RestOperationTypeEnum.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);
|
||||
|
||||
theRequestDetails.setFixedConditionalUrl(previousFixedConditionalUrl);
|
||||
|
||||
if (newVerdict == null) {
|
||||
continue;
|
||||
} else if (verdict == null) {
|
||||
|
|
|
@ -33,5 +33,6 @@ enum RuleOpEnum {
|
|||
DELETE,
|
||||
OPERATION,
|
||||
GRAPHQL,
|
||||
CREATE,
|
||||
PATCH
|
||||
}
|
||||
|
|
|
@ -51,90 +51,6 @@ public class Dstu2_1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
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
|
||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||
ensureBundle();
|
||||
|
|
|
@ -50,86 +50,6 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
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
|
||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||
ensureBundle();
|
||||
|
|
|
@ -2231,25 +2231,27 @@ public class GenericClientDstu2Test {
|
|||
|
||||
Patient p2 = new Patient(); // Yes ID
|
||||
p2.addName().addFamily("PATIENT2");
|
||||
p2.setId("Patient/2");
|
||||
p2.setId("http://foo.com/Patient/2");
|
||||
input.add(p2);
|
||||
|
||||
//@formatter:off
|
||||
List<IBaseResource> response = client.transaction()
|
||||
.withResources(input)
|
||||
.encodedJson()
|
||||
.prettyPrint()
|
||||
.execute();
|
||||
//@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());
|
||||
|
||||
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);
|
||||
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());
|
||||
assertEquals("http://foo.com/Patient/2", requestBundle.getEntry().get(1).getFullUrl());
|
||||
assertEquals("application/json+fhir", capt.getAllValues().get(0).getFirstHeader("content-type").getValue().replaceAll(";.*", ""));
|
||||
|
||||
p1 = (Patient) response.get(0);
|
||||
|
|
|
@ -51,93 +51,6 @@ public class Dstu3BundleFactory implements IVersionSpecificBundleFactory {
|
|||
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
|
||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||
|
|
|
@ -23,17 +23,16 @@ package ca.uhn.fhir.rest.server.provider.dstu2hl7org;
|
|||
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.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.Constants;
|
||||
import ca.uhn.fhir.rest.api.IVersionSpecificBundleFactory;
|
||||
import ca.uhn.fhir.rest.server.RestfulServerUtils;
|
||||
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.BundleLinkComponent;
|
||||
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 java.util.*;
|
||||
|
@ -51,8 +50,12 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
myContext = theContext;
|
||||
}
|
||||
|
||||
private void addResourcesForSearch(List<? extends IBaseResource> theResult) {
|
||||
List<IBaseResource> includedResources = new ArrayList<IBaseResource>();
|
||||
@Override
|
||||
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>();
|
||||
|
||||
for (IBaseResource next : theResult) {
|
||||
|
@ -61,22 +64,28 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
}
|
||||
|
||||
for (IBaseResource nextBaseRes : theResult) {
|
||||
IDomainResource next = (IDomainResource) nextBaseRes;
|
||||
for (IBaseResource next : theResult) {
|
||||
|
||||
Set<String> containedIds = new HashSet<String>();
|
||||
for (IBaseResource nextContained : next.getContained()) {
|
||||
if (nextContained.getIdElement().isEmpty() == false) {
|
||||
containedIds.add(nextContained.getIdElement().getValue());
|
||||
|
||||
if (next instanceof DomainResource) {
|
||||
for (Resource nextContained : ((DomainResource) next).getContained()) {
|
||||
if (isNotBlank(nextContained.getId())) {
|
||||
containedIds.add(nextContained.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
List<IBaseReference> references = myContext.newTerser().getAllPopulatedChildElementsOfType(next,
|
||||
IBaseReference.class);
|
||||
List<ResourceReferenceInfo> references = myContext.newTerser().getAllResourceReferences(next);
|
||||
do {
|
||||
List<IBaseResource> addedResourcesThisPass = new ArrayList<IBaseResource>();
|
||||
List<IAnyResource> addedResourcesThisPass = new ArrayList<IAnyResource>();
|
||||
|
||||
for (IBaseReference nextRef : references) {
|
||||
IBaseResource nextRes = (IBaseResource) nextRef.getResource();
|
||||
for (ResourceReferenceInfo nextRefInfo : references) {
|
||||
if (theBundleInclusionRule != null && !theBundleInclusionRule.shouldIncludeReferencedResource(nextRefInfo, theIncludes)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
IAnyResource nextRes = (IAnyResource) nextRefInfo.getResourceReference().getResource();
|
||||
if (nextRes != null) {
|
||||
if (nextRes.getIdElement().hasIdPart()) {
|
||||
if (containedIds.contains(nextRes.getIdElement().getValue())) {
|
||||
|
@ -99,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);
|
||||
|
||||
// Linked resources may themselves have linked resources
|
||||
references = new ArrayList<ResourceReferenceInfo>();
|
||||
for (IBaseResource iResource : addedResourcesThisPass) {
|
||||
references = new ArrayList<>();
|
||||
for (IAnyResource iResource : addedResourcesThisPass) {
|
||||
List<ResourceReferenceInfo> newReferences = myContext.newTerser().getAllResourceReferences(iResource);
|
||||
references.addAll(newReferences);
|
||||
}
|
||||
} while (references.isEmpty() == false);
|
||||
|
||||
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
|
||||
*/
|
||||
for (IBaseResource next : includedResources) {
|
||||
myBundle.addEntry().setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||
for (IAnyResource next : includedResources) {
|
||||
BundleEntryComponent entry = myBundle.addEntry();
|
||||
entry.setResource((Resource) next).getSearch().setMode(SearchEntryMode.INCLUDE);
|
||||
populateBundleEntryFullUrl(next, entry);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -228,7 +180,7 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
myBundle.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
if (myBundle.getMeta().getLastUpdated() == null) {
|
||||
if (myBundle.getMeta().getLastUpdated() == null && theLastUpdated != null) {
|
||||
InstantType instantType = new InstantType();
|
||||
instantType.setValueAsString(theLastUpdated.getValueAsString());
|
||||
myBundle.getMeta().setLastUpdatedElement(instantType);
|
||||
|
@ -280,16 +232,19 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
myBundle = (Bundle) theBundle;
|
||||
}
|
||||
|
||||
private void populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
||||
private IIdType populateBundleEntryFullUrl(IBaseResource next, BundleEntryComponent entry) {
|
||||
IIdType idElement = null;
|
||||
if (next.getIdElement().hasBaseUrl()) {
|
||||
entry.setFullUrl(next.getIdElement().toVersionless().getValue());
|
||||
idElement = next.getIdElement();
|
||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||
} else {
|
||||
if (isNotBlank(myBase) && next.getIdElement().hasIdPart()) {
|
||||
IIdType id = next.getIdElement().toVersionless();
|
||||
id = id.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
||||
entry.setFullUrl(id.getValue());
|
||||
idElement = next.getIdElement();
|
||||
idElement = idElement.withServerBase(myBase, myContext.getResourceDefinition(next).getName());
|
||||
entry.setFullUrl(idElement.toVersionless().getValue());
|
||||
}
|
||||
}
|
||||
return idElement;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -629,7 +629,7 @@ public class GenericClientDstu2Hl7OrgTest {
|
|||
|
||||
Patient p2 = new Patient(); // Yes ID
|
||||
p2.addName().addFamily("PATIENT2");
|
||||
p2.setId("Patient/2");
|
||||
p2.setId("http://example.com/Patient/2");
|
||||
input.add(p2);
|
||||
|
||||
//@formatter:off
|
||||
|
@ -647,7 +647,7 @@ public class GenericClientDstu2Hl7OrgTest {
|
|||
assertEquals(2, requestBundle.getEntry().size());
|
||||
assertEquals("POST", requestBundle.getEntry().get(0).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);
|
||||
assertEquals(new IdType("Patient/1/_history/1"), p1.getIdElement().toUnqualified());
|
||||
|
|
|
@ -52,93 +52,6 @@ public class R4BundleFactory implements IVersionSpecificBundleFactory {
|
|||
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
|
||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||
ensureBundle();
|
||||
|
|
|
@ -52,93 +52,6 @@ public class R5BundleFactory implements IVersionSpecificBundleFactory {
|
|||
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
|
||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||
ensureBundle();
|
||||
|
|
|
@ -55,86 +55,6 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
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
|
||||
public void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes) {
|
||||
if (myBundle == null) {
|
||||
|
|
|
@ -281,6 +281,12 @@
|
|||
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 version="4.0.3" date="2019-09-03" description="Igloo (Point Release)">
|
||||
<action type="fix">
|
||||
|
|
Loading…
Reference in New Issue