Merge branch 'master' into 674_everything_improvements for #674
This commit is contained in:
commit
cebe881a15
|
@ -0,0 +1,90 @@
|
|||
package ca.uhn.fhir.rest.client.interceptor;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
/*
|
||||
* #%L
|
||||
* HAPI FHIR - Core Library
|
||||
* %%
|
||||
* Copyright (C) 2014 - 2017 University Health Network
|
||||
* %%
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* #L%
|
||||
*/
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
|
||||
import org.apache.commons.codec.binary.Base64;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import ca.uhn.fhir.rest.client.IClientInterceptor;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpRequest;
|
||||
import ca.uhn.fhir.rest.client.api.IHttpResponse;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
||||
/**
|
||||
* This interceptor adds an arbitrary header to requests made by this client. Both the
|
||||
* header name and the header value are specified by the calling code.
|
||||
*/
|
||||
public class SimpleRequestHeaderInterceptor implements IClientInterceptor {
|
||||
|
||||
private String myHeaderName;
|
||||
private String myHeaderValue;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SimpleRequestHeaderInterceptor() {
|
||||
this(null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public SimpleRequestHeaderInterceptor(String theHeaderName, String theHeaderValue) {
|
||||
super();
|
||||
myHeaderName = theHeaderName;
|
||||
myHeaderValue = theHeaderValue;
|
||||
}
|
||||
|
||||
public String getHeaderName() {
|
||||
return myHeaderName;
|
||||
}
|
||||
|
||||
public String getHeaderValue() {
|
||||
return myHeaderValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptRequest(IHttpRequest theRequest) {
|
||||
if (isNotBlank(getHeaderName())) {
|
||||
theRequest.addHeader(getHeaderName(), getHeaderValue());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void interceptResponse(IHttpResponse theResponse) throws IOException {
|
||||
// nothing
|
||||
}
|
||||
|
||||
public void setHeaderName(String theHeaderName) {
|
||||
myHeaderName = theHeaderName;
|
||||
}
|
||||
|
||||
public void setHeaderValue(String theHeaderValue) {
|
||||
myHeaderValue = theHeaderValue;
|
||||
}
|
||||
|
||||
}
|
|
@ -39,6 +39,7 @@ import java.util.Map.Entry;
|
|||
import java.util.Set;
|
||||
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
import org.apache.http.NameValuePair;
|
||||
import org.hl7.fhir.dstu3.model.Bundle;
|
||||
|
@ -79,6 +80,7 @@ import ca.uhn.fhir.jpa.util.DeleteConflict;
|
|||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.parser.DataFormatException;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||
import ca.uhn.fhir.rest.api.RequestTypeEnum;
|
||||
import ca.uhn.fhir.rest.api.RestOperationTypeEnum;
|
||||
import ca.uhn.fhir.rest.method.BaseMethodBinding;
|
||||
|
@ -408,7 +410,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
String matchUrl = nextReqEntry.getRequest().getIfNoneExist();
|
||||
outcome = resourceDao.create(res, matchUrl, false, theRequestDetails);
|
||||
if (nextResourceId != null) {
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
}
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
if (outcome.getCreated() == false) {
|
||||
|
@ -474,7 +476,7 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
}
|
||||
}
|
||||
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res);
|
||||
handleTransactionCreateOrUpdateOutcome(idSubstitutions, idToPersistedOutcome, nextResourceId, outcome, nextRespEntry, resourceType, res, theRequestDetails);
|
||||
entriesToProcess.put(nextRespEntry, outcome.getEntity());
|
||||
break;
|
||||
}
|
||||
|
@ -646,10 +648,8 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
return response;
|
||||
}
|
||||
|
||||
|
||||
|
||||
private static void handleTransactionCreateOrUpdateOutcome(Map<IdType, IdType> idSubstitutions, Map<IdType, DaoMethodOutcome> idToPersistedOutcome, IdType nextResourceId, DaoMethodOutcome outcome,
|
||||
BundleEntryComponent newEntry, String theResourceType, IBaseResource theRes) {
|
||||
BundleEntryComponent newEntry, String theResourceType, IBaseResource theRes, ServletRequestDetails theRequestDetails) {
|
||||
IdType newId = (IdType) outcome.getId().toUnqualifiedVersionless();
|
||||
IdType resourceId = isPlaceholder(nextResourceId) ? nextResourceId : nextResourceId.toUnqualifiedVersionless();
|
||||
if (newId.equals(resourceId) == false) {
|
||||
|
@ -668,6 +668,19 @@ public class FhirSystemDaoDstu3 extends BaseHapiFhirSystemDao<Bundle, Meta> {
|
|||
newEntry.getResponse().setStatus(toStatusString(Constants.STATUS_HTTP_200_OK));
|
||||
}
|
||||
newEntry.getResponse().setLastModified(((Resource) theRes).getMeta().getLastUpdated());
|
||||
|
||||
if (theRequestDetails != null) {
|
||||
if (outcome.getResource() != null) {
|
||||
String prefer = theRequestDetails.getHeader(Constants.HEADER_PREFER);
|
||||
PreferReturnEnum preferReturn = RestfulServerUtils.parsePreferHeader(prefer);
|
||||
if (preferReturn != null) {
|
||||
if (preferReturn == PreferReturnEnum.REPRESENTATION) {
|
||||
newEntry.setResource((Resource) outcome.getResource());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static boolean isPlaceholder(IdType theId) {
|
||||
|
|
|
@ -1181,6 +1181,23 @@ public class FhirResourceDaoDstu3SearchNoFtTest extends BaseJpaDstu3Test {
|
|||
assertThat(patients, (hasItems(id1a, id1b)));
|
||||
assertThat(patients, not(hasItems(id2)));
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.GREATERTHAN_OR_EQUALS, beforeR2)));
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
|
||||
assertThat(patients, not(hasItems(id1a, id1b)));
|
||||
assertThat(patients, (hasItems(id2)));
|
||||
}
|
||||
{
|
||||
SearchParameterMap params = new SearchParameterMap();
|
||||
params.setLastUpdated(new DateRangeParam(new DateParam(ParamPrefixEnum.LESSTHAN_OR_EQUALS, beforeR2)));
|
||||
List<IIdType> patients = toUnqualifiedVersionlessIds(myPatientDao.search(params));
|
||||
assertThat(patients, (hasItems(id1a, id1b)));
|
||||
assertThat(patients, not(hasItems(id2)));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
|
|
@ -1370,6 +1370,53 @@ public class ResourceProviderDstu3Test extends BaseResourceProviderDstu3Test {
|
|||
ourLog.info(ids.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByLastUpdated() throws Exception {
|
||||
String methodName = "testSearchByLastUpdated";
|
||||
|
||||
Patient p = new Patient();
|
||||
p.addName().setFamily(methodName+"1");
|
||||
IIdType pid1 = ourClient.create().resource(p).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
Thread.sleep(10);
|
||||
long time1 = System.currentTimeMillis();
|
||||
Thread.sleep(10);
|
||||
|
||||
Patient p2 = new Patient();
|
||||
p2.addName().setFamily(methodName+"2");
|
||||
IIdType pid2 = ourClient.create().resource(p2).execute().getId().toUnqualifiedVersionless();
|
||||
|
||||
HttpGet get = new HttpGet(ourServerBase + "/Patient?_lastUpdated=lt" + new InstantType(new Date(time1)).getValueAsString());
|
||||
CloseableHttpResponse response = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
ourLog.info(output);
|
||||
List<IIdType> ids = toUnqualifiedVersionlessIds(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
||||
ourLog.info(ids.toString());
|
||||
assertThat(ids, containsInAnyOrder(pid1));
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
get = new HttpGet(ourServerBase + "/Patient?_lastUpdated=gt" + new InstantType(new Date(time1)).getValueAsString());
|
||||
response = ourHttpClient.execute(get);
|
||||
try {
|
||||
assertEquals(200, response.getStatusLine().getStatusCode());
|
||||
String output = IOUtils.toString(response.getEntity().getContent(), StandardCharsets.UTF_8);
|
||||
IOUtils.closeQuietly(response.getEntity().getContent());
|
||||
ourLog.info(output);
|
||||
List<IIdType> ids = toUnqualifiedVersionlessIds(myFhirCtx.newXmlParser().parseResource(Bundle.class, output));
|
||||
ourLog.info(ids.toString());
|
||||
assertThat(ids, containsInAnyOrder(pid2));
|
||||
} finally {
|
||||
response.close();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testEverythingPatientType() throws Exception {
|
||||
String methodName = "testEverythingPatientType";
|
||||
|
|
|
@ -60,6 +60,7 @@ import ca.uhn.fhir.jpa.rp.dstu3.OrganizationResourceProvider;
|
|||
import ca.uhn.fhir.jpa.rp.dstu3.PatientResourceProvider;
|
||||
import ca.uhn.fhir.jpa.testutil.RandomServerPortProvider;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.SimpleRequestHeaderInterceptor;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.rest.server.FifoMemoryPagingProvider;
|
||||
|
@ -80,6 +81,7 @@ public class SystemProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SystemProviderDstu3Test.class);
|
||||
private static Server ourServer;
|
||||
private static String ourServerBase;
|
||||
private SimpleRequestHeaderInterceptor mySimpleHeaderInterceptor;
|
||||
|
||||
@Test
|
||||
public void testTransactionWithInlineConditionalUrl() throws Exception {
|
||||
|
@ -237,10 +239,17 @@ public class SystemProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
myRestServer.setDefaultResponseEncoding(EncodingEnum.XML);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void before() {
|
||||
mySimpleHeaderInterceptor = new SimpleRequestHeaderInterceptor();
|
||||
ourClient.registerInterceptor(mySimpleHeaderInterceptor);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@After
|
||||
public void after() {
|
||||
myRestServer.setUseBrowserFriendlyContentTypes(true);
|
||||
ourClient.unregisterInterceptor(mySimpleHeaderInterceptor);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
|
@ -632,6 +641,44 @@ public class SystemProviderDstu3Test extends BaseJpaDstu3Test {
|
|||
assertEquals(0, respSub.getEntry().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionCreateWithPreferHeader() throws Exception {
|
||||
|
||||
Patient p = new Patient();
|
||||
p.setActive(true);
|
||||
|
||||
Bundle req;
|
||||
Bundle resp;
|
||||
|
||||
// No prefer header
|
||||
req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||
resp = ourClient.transaction().withBundle(req).execute();
|
||||
assertEquals(null, resp.getEntry().get(0).getResource());
|
||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||
|
||||
// Prefer return=minimal
|
||||
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
||||
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_MINIMAL);
|
||||
req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||
resp = ourClient.transaction().withBundle(req).execute();
|
||||
assertEquals(null, resp.getEntry().get(0).getResource());
|
||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||
|
||||
// Prefer return=representation
|
||||
mySimpleHeaderInterceptor.setHeaderName(Constants.HEADER_PREFER);
|
||||
mySimpleHeaderInterceptor.setHeaderValue(Constants.HEADER_PREFER_RETURN + "=" + Constants.HEADER_PREFER_RETURN_REPRESENTATION);
|
||||
req = new Bundle();
|
||||
req.setType(BundleType.TRANSACTION);
|
||||
req.addEntry().setResource(p).getRequest().setMethod(HTTPVerb.POST).setUrl("Patient");
|
||||
resp = ourClient.transaction().withBundle(req).execute();
|
||||
assertEquals(Patient.class, resp.getEntry().get(0).getResource().getClass());
|
||||
assertEquals("201 Created", resp.getEntry().get(0).getResponse().getStatus());
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClassClearContext() throws Exception {
|
||||
ourServer.stop();
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.apache.http.ProtocolVersion;
|
|||
import org.apache.http.client.ClientProtocolException;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
|
||||
import org.apache.http.client.methods.HttpGet;
|
||||
import org.apache.http.client.methods.HttpPut;
|
||||
import org.apache.http.client.methods.HttpUriRequest;
|
||||
import org.apache.http.entity.ContentType;
|
||||
|
@ -60,6 +61,7 @@ import ca.uhn.fhir.parser.CustomTypeDstu3Test.MyCustomPatient;
|
|||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.PreferReturnEnum;
|
||||
import ca.uhn.fhir.rest.client.SearchClientDstu3Test.ILocationClient;
|
||||
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
|
||||
import ca.uhn.fhir.rest.client.exceptions.NonFhirResponseException;
|
||||
import ca.uhn.fhir.rest.client.interceptor.CookieInterceptor;
|
||||
|
@ -178,6 +180,8 @@ public class GenericClientDstu3Test {
|
|||
assertThat(oo.getText().getDivAsString(), containsString("OK!"));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testPatchJsonByIdType() throws Exception {
|
||||
OperationOutcome conf = new OperationOutcome();
|
||||
|
@ -1191,6 +1195,36 @@ public class GenericClientDstu3Test {
|
|||
// assertEquals("FAM", resp.getNameFirstRep().getFamilyAsSingleString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchWithNullParameters() throws Exception {
|
||||
final String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
|
||||
|
||||
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), 200, "OK"));
|
||||
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_JSON + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getEntity().getContent()).then(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
int idx = 0;
|
||||
|
||||
DateTimeDt now = DateTimeDt.withCurrentTime();
|
||||
String dateString = now.getValueAsString().substring(0, 10);
|
||||
|
||||
client.search()
|
||||
.forResource("Patient")
|
||||
.where(Patient.NAME.matches().value((String)null))
|
||||
.returnBundle(Bundle.class)
|
||||
.execute();
|
||||
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(idx).getURI().toString());
|
||||
idx++;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSearchByDate() throws Exception {
|
||||
final String msg = "{\"resourceType\":\"Bundle\",\"id\":null,\"base\":\"http://localhost:57931/fhir/contextDev\",\"total\":1,\"link\":[{\"relation\":\"self\",\"url\":\"http://localhost:57931/fhir/contextDev/Patient?identifier=urn%3AMultiFhirVersionTest%7CtestSubmitPatient01&_format=json\"}],\"entry\":[{\"resource\":{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}]}";
|
||||
|
|
|
@ -43,7 +43,6 @@ import ca.uhn.fhir.rest.annotation.Sort;
|
|||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.client.api.IRestfulClient;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.StringParam;
|
||||
import ca.uhn.fhir.rest.server.Constants;
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
|
|
|
@ -32,6 +32,11 @@
|
|||
Fix HTTP 500 error in JPA server if a numeric search parameter was supplied with no value, e.g.
|
||||
<![CDATA[<code>GET /Observation?value-quantity=</code>]]>
|
||||
</action>
|
||||
<action type="add">
|
||||
JPA server transaction processing now honours the Prefer header and includes
|
||||
created and updated resource bodies in the response bundle if it is set
|
||||
appropriately.
|
||||
</action>
|
||||
<action type="add">
|
||||
Optimize queries in JPA server remove a few redundant select columns when performing
|
||||
searches. This provides a slight speed increase in some cases.
|
||||
|
|
Loading…
Reference in New Issue