Merge remote-tracking branch 'remotes/origin/master' into im_20200728_term_multi_version_support
This commit is contained in:
commit
796d2923e0
|
@ -567,6 +567,10 @@ public abstract class BaseClient implements IRestfulClient {
|
|||
|
||||
@Override
|
||||
public T invokeClient(String theResponseMimeType, InputStream theResponseInputStream, int theResponseStatusCode, Map<String, List<String>> theHeaders) throws BaseServerResponseException {
|
||||
if (theResponseStatusCode == Constants.STATUS_HTTP_204_NO_CONTENT) {
|
||||
return null;
|
||||
}
|
||||
|
||||
EncodingEnum respType = EncodingEnum.forContentType(theResponseMimeType);
|
||||
if (respType == null) {
|
||||
if (myAllowHtmlResponse && theResponseMimeType.toLowerCase().contains(Constants.CT_HTML) && myReturnType != null) {
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 2049
|
||||
title: A potential NPE in the JPA server was fixed. This error could be triggered by searching for resources with
|
||||
unresolvable references. Thanks to Anders Havn for the pull request!
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: fix
|
||||
issue: 2050
|
||||
title: An issue was fixed where multiple JPA server updates to the same resource within the same
|
||||
database transaction would fail with a database constraint error.
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
type: add
|
||||
issue: 2051
|
||||
title: The FHIR Client will now accept an HTTP 204 NO CONTENT as a response to a write operation such
|
||||
as a create/update/transaction/etc.
|
|
@ -1057,7 +1057,7 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
entity.setLanguage(((IAnyResource) theResource).getLanguageElement().getValue());
|
||||
}
|
||||
|
||||
newParams.setParamsOn(entity);
|
||||
newParams.populateResourceTableSearchParamsPresentFlags(entity);
|
||||
entity.setIndexStatus(INDEX_STATUS_INDEXED);
|
||||
populateFullTextFields(myContext, theResource, entity);
|
||||
}
|
||||
|
@ -1206,6 +1206,8 @@ public abstract class BaseHapiFhirDao<T extends IBaseResource> extends BaseStora
|
|||
// Synchronize search param indexes
|
||||
AddRemoveCount searchParamAddRemoveCount = myDaoSearchParamSynchronizer.synchronizeSearchParamsToDatabase(newParams, entity, existingParams);
|
||||
|
||||
newParams.populateResourceTableParamCollections(entity);
|
||||
|
||||
// Interceptor broadcast: JPA_PERFTRACE_INFO
|
||||
if (!searchParamAddRemoveCount.isEmpty()) {
|
||||
if (JpaInterceptorBroadcaster.hasHooks(Pointcut.JPA_PERFTRACE_INFO, myInterceptorBroadcaster, theRequest)) {
|
||||
|
|
|
@ -745,6 +745,9 @@ public class SearchBuilder implements ISearchBuilder {
|
|||
q.setParameter("target_pids", ResourcePersistentId.toLongList(nextPartition));
|
||||
List<Long> results = q.getResultList();
|
||||
for (Long resourceLink : results) {
|
||||
if (resourceLink == null) {
|
||||
continue;
|
||||
}
|
||||
if (theReverseMode) {
|
||||
pidsToInclude.add(new ResourcePersistentId(resourceLink));
|
||||
} else {
|
||||
|
|
|
@ -887,6 +887,30 @@ public class FhirResourceDaoR4Test extends BaseJpaR4Test {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateThenUpdateInSameTransaction() {
|
||||
Patient initialPatient = new Patient();
|
||||
IIdType id = myPatientDao.create(initialPatient).getId().toUnqualifiedVersionless();
|
||||
|
||||
runInTransaction(() -> {
|
||||
Patient p = new Patient();
|
||||
p.setId(id);
|
||||
p.setActive(true);
|
||||
p.addName().setFamily("FAMILY");
|
||||
myPatientDao.update(p);
|
||||
|
||||
p = new Patient();
|
||||
p.setId(id);
|
||||
p.setActive(false);
|
||||
p.addName().setFamily("FAMILY2");
|
||||
myPatientDao.update(p);
|
||||
});
|
||||
|
||||
assertEquals(1, myPatientDao.search(SearchParameterMap.newSynchronous("name", new StringParam("family2"))).size());
|
||||
assertEquals(1, myPatientDao.search(SearchParameterMap.newSynchronous("active", new TokenParam("false"))).size());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCreateSummaryFails() {
|
||||
Patient p = new Patient();
|
||||
|
|
|
@ -33,7 +33,6 @@ import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
|||
import ca.uhn.fhir.rest.server.interceptor.BaseValidatingInterceptor;
|
||||
import ca.uhn.fhir.rest.server.interceptor.RequestValidatingInterceptor;
|
||||
import ca.uhn.fhir.util.HapiExtensions;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import ca.uhn.fhir.validation.IValidatorModule;
|
||||
import com.google.common.base.Charsets;
|
||||
|
@ -76,6 +75,7 @@ import org.hl7.fhir.dstu3.model.DocumentReference;
|
|||
import org.hl7.fhir.dstu3.model.Encounter;
|
||||
import org.hl7.fhir.dstu3.model.Encounter.EncounterLocationComponent;
|
||||
import org.hl7.fhir.dstu3.model.Encounter.EncounterStatus;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations;
|
||||
import org.hl7.fhir.dstu3.model.Enumerations.AdministrativeGender;
|
||||
import org.hl7.fhir.dstu3.model.Extension;
|
||||
import org.hl7.fhir.dstu3.model.IdType;
|
||||
|
@ -96,6 +96,7 @@ import org.hl7.fhir.dstu3.model.Organization;
|
|||
import org.hl7.fhir.dstu3.model.Parameters;
|
||||
import org.hl7.fhir.dstu3.model.Patient;
|
||||
import org.hl7.fhir.dstu3.model.Period;
|
||||
import org.hl7.fhir.dstu3.model.PlanDefinition;
|
||||
import org.hl7.fhir.dstu3.model.Practitioner;
|
||||
import org.hl7.fhir.dstu3.model.ProcedureRequest;
|
||||
import org.hl7.fhir.dstu3.model.Quantity;
|
||||
|
@ -103,6 +104,7 @@ import org.hl7.fhir.dstu3.model.Questionnaire;
|
|||
import org.hl7.fhir.dstu3.model.Questionnaire.QuestionnaireItemType;
|
||||
import org.hl7.fhir.dstu3.model.QuestionnaireResponse;
|
||||
import org.hl7.fhir.dstu3.model.Reference;
|
||||
import org.hl7.fhir.dstu3.model.RelatedArtifact;
|
||||
import org.hl7.fhir.dstu3.model.StringType;
|
||||
import org.hl7.fhir.dstu3.model.StructureDefinition;
|
||||
import org.hl7.fhir.dstu3.model.Subscription;
|
||||
|
@ -112,7 +114,6 @@ import org.hl7.fhir.dstu3.model.UnsignedIntType;
|
|||
import org.hl7.fhir.dstu3.model.ValueSet;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.instance.model.api.IIdType;
|
||||
import org.junit.jupiter.api.AfterAll;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Disabled;
|
||||
|
@ -138,6 +139,7 @@ import java.util.HashSet;
|
|||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
import java.util.UUID;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
@ -362,6 +364,45 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(bundle));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithIncludeAllWithNotResolvableReference() {
|
||||
// Arrange
|
||||
myDaoConfig.setAllowExternalReferences(true);
|
||||
|
||||
Patient patient = new Patient();
|
||||
patient.addName().setFamily(UUID.randomUUID().toString());
|
||||
IIdType createdPatientId = ourClient.create().resource(patient).execute().getId();
|
||||
|
||||
RelatedArtifact relatedArtifactInternalReference = new RelatedArtifact();
|
||||
relatedArtifactInternalReference.setDisplay(UUID.randomUUID().toString());
|
||||
relatedArtifactInternalReference.setType(RelatedArtifact.RelatedArtifactType.PREDECESSOR);
|
||||
relatedArtifactInternalReference.setResource(new Reference(createdPatientId.toUnqualifiedVersionless()));
|
||||
|
||||
RelatedArtifact relatedArtifactExternalReference = new RelatedArtifact();
|
||||
relatedArtifactExternalReference.setDisplay(UUID.randomUUID().toString());
|
||||
relatedArtifactExternalReference.setType(RelatedArtifact.RelatedArtifactType.PREDECESSOR);
|
||||
relatedArtifactExternalReference.setResource(new Reference("http://not-local-host.dk/hapi-fhir-jpaserver/fhir/Patient/2"));
|
||||
|
||||
PlanDefinition planDefinition = new PlanDefinition();
|
||||
planDefinition.setStatus(Enumerations.PublicationStatus.ACTIVE);
|
||||
planDefinition.setName(UUID.randomUUID().toString());
|
||||
planDefinition.setRelatedArtifact(Arrays.asList(relatedArtifactInternalReference, relatedArtifactExternalReference));
|
||||
IIdType createdPlanDefinitionId = ourClient.create().resource(planDefinition).execute().getId();
|
||||
|
||||
// Act
|
||||
Bundle returnedBundle = ourClient.search()
|
||||
.forResource(PlanDefinition.class)
|
||||
.include(PlanDefinition.INCLUDE_ALL)
|
||||
.where(PlanDefinition.NAME.matches().value(planDefinition.getName()))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
|
||||
// Assert
|
||||
assertEquals(returnedBundle.getEntry().size(), 2);
|
||||
assertEquals(createdPlanDefinitionId, genResourcesOfType(returnedBundle, PlanDefinition.class).get(0).getIdElement());
|
||||
assertEquals(createdPatientId, genResourcesOfType(returnedBundle, Patient.class).get(0).getIdElement());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBundleCreateWithTypeTransaction() throws Exception {
|
||||
IGenericClient client = ourClient;
|
||||
|
|
|
@ -105,26 +105,30 @@ public final class ResourceIndexedSearchParams {
|
|||
return myLinks;
|
||||
}
|
||||
|
||||
public void setParamsOn(ResourceTable theEntity) {
|
||||
theEntity.setParamsString(myStringParams);
|
||||
public void populateResourceTableSearchParamsPresentFlags(ResourceTable theEntity) {
|
||||
theEntity.setParamsStringPopulated(myStringParams.isEmpty() == false);
|
||||
theEntity.setParamsToken(myTokenParams);
|
||||
theEntity.setParamsTokenPopulated(myTokenParams.isEmpty() == false);
|
||||
theEntity.setParamsNumber(myNumberParams);
|
||||
theEntity.setParamsNumberPopulated(myNumberParams.isEmpty() == false);
|
||||
theEntity.setParamsQuantity(myQuantityParams);
|
||||
theEntity.setParamsQuantityPopulated(myQuantityParams.isEmpty() == false);
|
||||
theEntity.setParamsDate(myDateParams);
|
||||
theEntity.setParamsDatePopulated(myDateParams.isEmpty() == false);
|
||||
theEntity.setParamsUri(myUriParams);
|
||||
theEntity.setParamsUriPopulated(myUriParams.isEmpty() == false);
|
||||
theEntity.setParamsCoords(myCoordsParams);
|
||||
theEntity.setParamsCoordsPopulated(myCoordsParams.isEmpty() == false);
|
||||
theEntity.setParamsCompositeStringUniquePresent(myCompositeStringUniques.isEmpty() == false);
|
||||
theEntity.setResourceLinks(myLinks);
|
||||
theEntity.setHasLinks(myLinks.isEmpty() == false);
|
||||
}
|
||||
|
||||
|
||||
public void populateResourceTableParamCollections(ResourceTable theEntity) {
|
||||
theEntity.setParamsString(myStringParams);
|
||||
theEntity.setParamsToken(myTokenParams);
|
||||
theEntity.setParamsNumber(myNumberParams);
|
||||
theEntity.setParamsQuantity(myQuantityParams);
|
||||
theEntity.setParamsDate(myDateParams);
|
||||
theEntity.setParamsUri(myUriParams);
|
||||
theEntity.setParamsCoords(myCoordsParams);
|
||||
theEntity.setResourceLinks(myLinks);
|
||||
}
|
||||
|
||||
void setUpdatedTime(Date theUpdateTime) {
|
||||
setUpdatedTime(myStringParams, theUpdateTime);
|
||||
setUpdatedTime(myNumberParams, theUpdateTime);
|
||||
|
|
|
@ -2397,33 +2397,6 @@ public class GenericClientDstu2Test {
|
|||
assertEquals("Patient/2/_history/2", response.getEntry().get(1).getResponse().getLocation());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionHandle204NoBody() throws Exception {
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle bundle = new Bundle();
|
||||
bundle.setType(BundleTypeEnum.TRANSACTION);
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle.Entry entry = bundle.addEntry();
|
||||
entry.setResource(new Patient());
|
||||
entry.getRequest().setMethod(HTTPVerbEnum.PUT);
|
||||
|
||||
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_204_NO_CONTENT, ""));
|
||||
when(myHttpResponse.getEntity() ).thenReturn(null);
|
||||
|
||||
try {
|
||||
client.transaction().withBundle(bundle).execute();
|
||||
fail("Should throw an exception");
|
||||
} catch (NonFhirResponseException e) {
|
||||
assertEquals(Constants.STATUS_HTTP_204_NO_CONTENT, e.getStatusCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateConditional() throws Exception {
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
|
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.rest.param.DateRangeParam;
|
|||
import ca.uhn.fhir.rest.param.ParamPrefixEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.NotImplementedOperationException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnclassifiedServerFailureException;
|
||||
import ca.uhn.fhir.util.TransactionBuilder;
|
||||
import ca.uhn.fhir.util.UrlUtil;
|
||||
import com.google.common.base.Charsets;
|
||||
import com.helger.commons.io.stream.StringInputStream;
|
||||
|
@ -36,6 +37,7 @@ import org.apache.http.client.methods.HttpPut;
|
|||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.message.BasicHeader;
|
||||
import org.apache.http.message.BasicStatusLine;
|
||||
import org.hl7.fhir.instance.model.api.IBaseBundle;
|
||||
import org.hl7.fhir.instance.model.api.IPrimitiveType;
|
||||
import org.hl7.fhir.r4.model.Binary;
|
||||
import org.hl7.fhir.r4.model.BooleanType;
|
||||
|
@ -2106,6 +2108,31 @@ public class GenericClientR4Test extends BaseGenericClientR4Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionWithResponseHttp204NoContent() throws IOException {
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
|
||||
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
|
||||
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 204, "No Content"));
|
||||
when(myHttpResponse.getEntity()).thenReturn(null);
|
||||
when(myHttpResponse.getAllHeaders()).thenAnswer(new Answer<Header[]>() {
|
||||
@Override
|
||||
public Header[] answer(InvocationOnMock theInvocation) {
|
||||
return new Header[0];
|
||||
}
|
||||
});
|
||||
|
||||
TransactionBuilder builder = new TransactionBuilder(ourCtx);
|
||||
builder.addCreateEntry(new Patient().setActive(true));
|
||||
|
||||
IBaseBundle outcome = client.transaction().withBundle(builder.getBundle()).execute();
|
||||
assertNull(outcome);
|
||||
|
||||
assertEquals("http://example.com/fhir", capt.getAllValues().get(0).getURI().toASCIIString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdateById() throws Exception {
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
|
|
Loading…
Reference in New Issue