Server should include lastUpdated in search responses if one is supplied
by the implementation. Also automatically include in this in JPA server
This commit is contained in:
parent
ccc49e975f
commit
70d4abdf06
|
@ -65,6 +65,16 @@
|
|||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<artifactId>maven-jar-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<id>default-jar</id>
|
||||
<!-- put the default-jar in the none phase to skip it from being created -->
|
||||
<phase>none</phase>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
|
|
@ -44,8 +44,10 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.annotation.ResourceDef;
|
||||
import ca.uhn.fhir.model.base.resource.BaseOperationOutcome;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
|
@ -307,11 +309,14 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
|
||||
if (getMethodReturnType() == MethodReturnTypeEnum.BUNDLE_RESOURCE) {
|
||||
IBaseResource resource;
|
||||
InstantDt lastUpdated;
|
||||
if (resultObj instanceof IBundleProvider) {
|
||||
IBundleProvider result = (IBundleProvider) resultObj;
|
||||
resource = result.getResources(0, 1).get(0);
|
||||
lastUpdated = result.getPublished();
|
||||
} else {
|
||||
resource = (IResource) resultObj;
|
||||
lastUpdated = ResourceMetadataKeyEnum.UPDATED.get((IResource) resource);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -319,7 +324,7 @@ abstract class BaseResourceReturningMethodBinding extends BaseMethodBinding<Obje
|
|||
*/
|
||||
IVersionSpecificBundleFactory bundleFactory = theServer.getFhirContext().newBundleFactory();
|
||||
bundleFactory.initializeWithBundleResource(resource);
|
||||
bundleFactory.addRootPropertiesToBundle(null, theRequest.getFhirServerBase(), linkSelf, count, getResponseBundleType());
|
||||
bundleFactory.addRootPropertiesToBundle(null, theRequest.getFhirServerBase(), linkSelf, count, getResponseBundleType(), lastUpdated);
|
||||
|
||||
for (int i = theServer.getInterceptors().size() - 1; i >= 0; i--) {
|
||||
IServerInterceptor next = theServer.getInterceptors().get(i);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package ca.uhn.fhir.rest.method;
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
import static org.apache.commons.lang3.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.PushbackReader;
|
||||
|
@ -500,10 +501,17 @@ public class MethodUtil {
|
|||
try {
|
||||
headerDateValue = DateUtils.parseDate(headerValue);
|
||||
if (resource instanceof IResource) {
|
||||
IResource iResource = (IResource) resource;
|
||||
InstantDt existing = ResourceMetadataKeyEnum.UPDATED.get(iResource);
|
||||
if (existing == null || existing.isEmpty()) {
|
||||
InstantDt lmValue = new InstantDt(headerDateValue);
|
||||
((IResource) resource).getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, lmValue);
|
||||
iResource.getResourceMetadata().put(ResourceMetadataKeyEnum.UPDATED, lmValue);
|
||||
}
|
||||
} else if (resource instanceof IAnyResource) {
|
||||
((IAnyResource) resource).getMeta().setLastUpdated(headerDateValue);
|
||||
IAnyResource anyResource = (IAnyResource) resource;
|
||||
if (anyResource.getMeta().getLastUpdated() == null) {
|
||||
anyResource.getMeta().setLastUpdated(headerDateValue);
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
ourLog.warn("Unable to parse date string '{}'. Error is: {}", headerValue, e.toString());
|
||||
|
|
|
@ -20,6 +20,8 @@ package ca.uhn.fhir.rest.server;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
import static org.apache.commons.lang3.StringUtils.isNotBlank;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -42,6 +44,7 @@ import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
|||
import ca.uhn.fhir.model.base.composite.BaseResourceReferenceDt;
|
||||
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.valueset.BundleEntrySearchModeEnum;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
|
||||
|
@ -201,7 +204,7 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
||||
|
||||
if (theServer.getPagingProvider() != null) {
|
||||
int limit;
|
||||
|
@ -221,11 +224,15 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType) {
|
||||
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, InstantDt theLastUpdated) {
|
||||
if (myBundle.getAuthorName().isEmpty()) {
|
||||
myBundle.getAuthorName().setValue(theAuthor);
|
||||
}
|
||||
|
||||
if (myBundle.getUpdated().isEmpty() && isNotBlank(theLastUpdated.getValueAsString())) {
|
||||
myBundle.getUpdated().setValueAsString(theLastUpdated.getValueAsString());
|
||||
}
|
||||
|
||||
if (myBundle.getBundleId().isEmpty()) {
|
||||
myBundle.getBundleId().setValue(UUID.randomUUID().toString());
|
||||
}
|
||||
|
@ -301,7 +308,7 @@ public class Dstu1BundleFactory implements IVersionSpecificBundleFactory {
|
|||
List<IBaseResource> addedResourcesThisPass = new ArrayList<IBaseResource>();
|
||||
|
||||
for (BaseResourceReferenceDt nextRef : references) {
|
||||
IBaseResource nextRefRes = (IBaseResource) nextRef.getResource();
|
||||
IBaseResource nextRefRes = nextRef.getResource();
|
||||
if (nextRefRes != null) {
|
||||
if (nextRefRes.getIdElement().hasIdPart()) {
|
||||
if (containedIds.contains(nextRefRes.getIdElement().getValue())) {
|
||||
|
|
|
@ -27,6 +27,7 @@ import org.hl7.fhir.instance.model.api.IBaseResource;
|
|||
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.valueset.BundleTypeEnum;
|
||||
|
||||
/**
|
||||
|
@ -37,7 +38,7 @@ public interface IVersionSpecificBundleFactory {
|
|||
|
||||
void addResourcesToBundle(List<IBaseResource> theResult, BundleTypeEnum theBundleType, String theServerBase, BundleInclusionRule theBundleInclusionRule, Set<Include> theIncludes);
|
||||
|
||||
void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType);
|
||||
void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, InstantDt theLastUpdated);
|
||||
|
||||
void initializeBundleFromBundleProvider(RestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint,
|
||||
int theOffset, Integer theCount, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes);
|
||||
|
|
|
@ -0,0 +1,28 @@
|
|||
package ca.uhn.fhir.model.api;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
|
||||
public class InstantDtTest {
|
||||
|
||||
@Test
|
||||
public void testParseHandlesMillis() {
|
||||
InstantDt dt = new InstantDt();
|
||||
dt.setValueAsString("2015-06-22T15:44:32.831-04:00");
|
||||
Date date = dt.getValue();
|
||||
|
||||
InstantDt dt2 = new InstantDt();
|
||||
dt2.setValue(date);
|
||||
dt2.setTimeZoneZulu(true);
|
||||
String string = dt2.getValueAsString();
|
||||
|
||||
assertEquals("2015-06-22T19:44:32.831Z", string);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -1,8 +1,6 @@
|
|||
package ca.uhn.fhir.jpa.dao;
|
||||
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.SQLNonTransientConnectionException;
|
||||
|
||||
import org.junit.AfterClass;
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
|
|||
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
|
||||
import ca.uhn.fhir.rest.server.exceptions.UnprocessableEntityException;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public class FhirResourceDaoDstu1Test extends BaseJpaTest {
|
||||
|
||||
private static ClassPathXmlApplicationContext ourCtx;
|
||||
|
|
|
@ -75,7 +75,6 @@ import ca.uhn.fhir.model.primitive.UriDt;
|
|||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.api.SortOrderEnum;
|
||||
import ca.uhn.fhir.rest.api.SortSpec;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.param.CompositeParam;
|
||||
import ca.uhn.fhir.rest.param.DateParam;
|
||||
import ca.uhn.fhir.rest.param.DateRangeParam;
|
||||
|
|
|
@ -5,10 +5,15 @@ import static org.hamcrest.Matchers.emptyString;
|
|||
import static org.hamcrest.Matchers.endsWith;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.startsWith;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
import java.io.InputStream;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
@ -28,9 +33,9 @@ import ca.uhn.fhir.model.api.IResource;
|
|||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.base.composite.BaseCodingDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.CodingDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.MetaDt;
|
||||
import ca.uhn.fhir.model.dstu2.composite.ResourceReferenceDt;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||
|
|
|
@ -83,6 +83,7 @@ import ca.uhn.fhir.narrative.DefaultThymeleafNarrativeGenerator;
|
|||
import ca.uhn.fhir.rest.api.MethodOutcome;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.ServerValidationModeEnum;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
import ca.uhn.fhir.rest.gclient.IQuery;
|
||||
import ca.uhn.fhir.rest.gclient.StringClientParam;
|
||||
import ca.uhn.fhir.rest.gclient.TokenClientParam;
|
||||
|
@ -808,9 +809,12 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
|
|||
|
||||
InstantDt updated = ResourceMetadataKeyEnum.UPDATED.get(found);
|
||||
assertNotNull(updated);
|
||||
assertNotNull(updated.getValue());
|
||||
assertTrue(updated.getValue().after(before));
|
||||
assertTrue(updated.getValue().before(after));
|
||||
Date value = updated.getValue();
|
||||
assertNotNull(value);
|
||||
ourLog.info(value.getTime()+"");
|
||||
ourLog.info(before.getTime()+"");
|
||||
assertTrue(value.after(before));
|
||||
assertTrue(value.before(after));
|
||||
}
|
||||
|
||||
|
||||
|
@ -1120,7 +1124,7 @@ public class ResourceProviderDstu2Test extends BaseJpaTest {
|
|||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setSocketTimeout(1200 * 1000);
|
||||
ourClient = ourCtx.newRestfulGenericClient(ourServerBase);
|
||||
// ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
ourClient.registerInterceptor(new LoggingInterceptor(true));
|
||||
|
||||
PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(5000, TimeUnit.MILLISECONDS);
|
||||
HttpClientBuilder builder = HttpClientBuilder.create();
|
||||
|
|
|
@ -23,6 +23,7 @@ package ca.uhn.fhir.rest.server.provider.dstu2;
|
|||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
@ -158,16 +159,14 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType) {
|
||||
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, InstantDt theLastUpdated) {
|
||||
|
||||
if (myBundle.getId().isEmpty()) {
|
||||
myBundle.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
if (ResourceMetadataKeyEnum.PUBLISHED.get(myBundle) == null) {
|
||||
InstantDt published = new InstantDt();
|
||||
published.setToCurrentTimeInLocalTimeZone();
|
||||
ResourceMetadataKeyEnum.PUBLISHED.put(myBundle, published);
|
||||
if (ResourceMetadataKeyEnum.UPDATED.get(myBundle) == null) {
|
||||
ResourceMetadataKeyEnum.UPDATED.put(myBundle, theLastUpdated);
|
||||
}
|
||||
|
||||
if (!hasLink(Constants.LINK_SELF, myBundle) && isNotBlank(theCompleteUrl)) {
|
||||
|
@ -197,13 +196,18 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromBundleProvider(RestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl, boolean thePrettyPrint, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
||||
public void initializeBundleFromBundleProvider(RestfulServer theServer, IBundleProvider theResult, EncodingEnum theResponseEncoding, String theServerBase, String theCompleteUrl,
|
||||
boolean thePrettyPrint, int theOffset, Integer theLimit, String theSearchId, BundleTypeEnum theBundleType, Set<Include> theIncludes) {
|
||||
int numToReturn;
|
||||
String searchId = null;
|
||||
List<IBaseResource> resourceList;
|
||||
if (theServer.getPagingProvider() == null) {
|
||||
numToReturn = theResult.size();
|
||||
if (numToReturn > 0) {
|
||||
resourceList = theResult.getResources(0, numToReturn);
|
||||
} else {
|
||||
resourceList = Collections.emptyList();
|
||||
}
|
||||
RestfulServerUtils.validateResourceListNotNull(resourceList);
|
||||
|
||||
} else {
|
||||
|
@ -246,7 +250,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
addResourcesToBundle(new ArrayList<IBaseResource>(resourceList), theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
||||
|
||||
if (theServer.getPagingProvider() != null) {
|
||||
int limit;
|
||||
|
@ -255,11 +259,13 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
|
||||
if (searchId != null) {
|
||||
if (theOffset + numToReturn < theResult.size()) {
|
||||
myBundle.addLink().setRelation(Constants.LINK_NEXT).setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint));
|
||||
myBundle.addLink().setRelation(Constants.LINK_NEXT)
|
||||
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, theOffset + numToReturn, numToReturn, theResponseEncoding, thePrettyPrint));
|
||||
}
|
||||
if (theOffset > 0) {
|
||||
int start = Math.max(0, theOffset - limit);
|
||||
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS).setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint));
|
||||
myBundle.addLink().setRelation(Constants.LINK_PREVIOUS)
|
||||
.setUrl(RestfulServerUtils.createPagingLink(theIncludes, theServerBase, searchId, start, limit, theResponseEncoding, thePrettyPrint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -276,7 +282,8 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void initializeBundleFromResourceList(String theAuthor, List<? extends IBaseResource> theResources, String theServerBase, String theCompleteUrl, int theTotalResults, BundleTypeEnum theBundleType) {
|
||||
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());
|
||||
|
@ -289,7 +296,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
|
||||
if (theBundleType.equals(BundleTypeEnum.TRANSACTION)) {
|
||||
for (IBaseResource nextBaseRes : theResources) {
|
||||
IResource next = (IResource)nextBaseRes;
|
||||
IResource next = (IResource) nextBaseRes;
|
||||
Entry nextEntry = myBundle.addEntry();
|
||||
|
||||
nextEntry.setResource(next);
|
||||
|
@ -323,7 +330,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
for (IBaseResource nextBaseRes : theResult) {
|
||||
IResource next = (IResource)nextBaseRes;
|
||||
IResource next = (IResource) nextBaseRes;
|
||||
Set<String> containedIds = new HashSet<String>();
|
||||
for (IResource nextContained : next.getContained().getContainedResources()) {
|
||||
if (nextContained.getId().isEmpty() == false) {
|
||||
|
@ -401,7 +408,7 @@ public class Dstu2BundleFactory implements IVersionSpecificBundleFactory {
|
|||
public List<IBaseResource> toListOfResources() {
|
||||
ArrayList<IBaseResource> retVal = new ArrayList<IBaseResource>();
|
||||
for (Entry next : myBundle.getEntry()) {
|
||||
if (next.getResource()!=null) {
|
||||
if (next.getResource() != null) {
|
||||
retVal.add(next.getResource());
|
||||
} else if (next.getTransactionResponse().getLocationElement().isEmpty() == false) {
|
||||
IdDt id = new IdDt(next.getTransactionResponse().getLocation());
|
||||
|
|
|
@ -1,7 +1,16 @@
|
|||
package ca.uhn.fhir.parser;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.emptyOrNullString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertArrayEquals;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.io.StringReader;
|
||||
import java.util.ArrayList;
|
||||
|
@ -57,7 +66,6 @@ import ca.uhn.fhir.model.primitive.IdDt;
|
|||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.model.primitive.StringDt;
|
||||
import ca.uhn.fhir.rest.client.IGenericClient;
|
||||
import ca.uhn.fhir.rest.client.interceptor.LoggingInterceptor;
|
||||
|
||||
public class XmlParserDstu2Test {
|
||||
private static final FhirContext ourCtx = FhirContext.forDstu2();
|
||||
|
@ -95,6 +103,30 @@ public class XmlParserDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseMetaUpdatedDate() {
|
||||
//@formatter:off
|
||||
String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <id value=\"e2ee823b-ee4d-472d-b79d-495c23f16b99\"/>\n" +
|
||||
" <meta>\n" +
|
||||
" <lastUpdated value=\"2015-06-22T15:48:57.554-04:00\"/>\n" +
|
||||
" </meta>\n" +
|
||||
" <type value=\"searchset\"/>\n" +
|
||||
" <base value=\"http://localhost:58109/fhir/context\"/>\n" +
|
||||
" <total value=\"0\"/>\n" +
|
||||
" <link>\n" +
|
||||
" <relation value=\"self\"/>\n" +
|
||||
" <url value=\"http://localhost:58109/fhir/context/Patient?_pretty=true\"/>\n" +
|
||||
" </link>\n" +
|
||||
"</Bundle>";
|
||||
//@formatter:on
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle b = ourCtx.newXmlParser().parseResource(ca.uhn.fhir.model.dstu2.resource.Bundle.class, input);
|
||||
|
||||
InstantDt updated = ResourceMetadataKeyEnum.UPDATED.get(b);
|
||||
assertEquals("2015-06-22T15:48:57.554-04:00", updated.getValueAsString());
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testContainedResourceInExtensionUndeclared() {
|
||||
Patient p = new Patient();
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
package ca.uhn.fhir.rest.client;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
@ -13,6 +17,7 @@ import java.util.List;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
|
@ -34,6 +39,7 @@ import org.mockito.stubbing.Answer;
|
|||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.Include;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Observation;
|
||||
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Parameters;
|
||||
|
@ -258,6 +264,56 @@ public class GenericClientDstu2Test {
|
|||
idx++;
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadUpdatedHeaderDoesntOverwriteResourceValue() throws Exception {
|
||||
|
||||
//@formatter:off
|
||||
final String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <id value=\"e2ee823b-ee4d-472d-b79d-495c23f16b99\"/>\n" +
|
||||
" <meta>\n" +
|
||||
" <lastUpdated value=\"2015-06-22T15:48:57.554-04:00\"/>\n" +
|
||||
" </meta>\n" +
|
||||
" <type value=\"searchset\"/>\n" +
|
||||
" <base value=\"http://localhost:58109/fhir/context\"/>\n" +
|
||||
" <total value=\"0\"/>\n" +
|
||||
" <link>\n" +
|
||||
" <relation value=\"self\"/>\n" +
|
||||
" <url value=\"http://localhost:58109/fhir/context/Patient?_pretty=true\"/>\n" +
|
||||
" </link>\n" +
|
||||
"</Bundle>";
|
||||
//@formatter:on
|
||||
|
||||
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_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {
|
||||
new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Sat, 20 Jun 2015 19:32:17 GMT")
|
||||
});
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(input), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
ca.uhn.fhir.model.dstu2.resource.Bundle response;
|
||||
|
||||
//@formatter:off
|
||||
response = client
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.returnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
assertEquals("2015-06-22T15:48:57.554-04:00", ResourceMetadataKeyEnum.UPDATED.get(response).getValueAsString());
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testOperationAsGetWithInParameters() throws Exception {
|
||||
IParser p = ourCtx.newXmlParser();
|
||||
|
|
|
@ -2,10 +2,12 @@ package ca.uhn.fhir.rest.server;
|
|||
|
||||
import static org.hamcrest.Matchers.containsString;
|
||||
import static org.hamcrest.Matchers.not;
|
||||
import static org.hamcrest.Matchers.stringContainsInOrder;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertThat;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
|
@ -17,6 +19,7 @@ import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
|
|||
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.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.Test;
|
||||
|
@ -25,6 +28,7 @@ import ca.uhn.fhir.context.FhirContext;
|
|||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Bundle;
|
||||
import ca.uhn.fhir.model.dstu2.resource.Patient;
|
||||
import ca.uhn.fhir.model.primitive.InstantDt;
|
||||
import ca.uhn.fhir.rest.annotation.Search;
|
||||
import ca.uhn.fhir.util.PatternMatcher;
|
||||
import ca.uhn.fhir.util.PortUtil;
|
||||
|
@ -39,6 +43,8 @@ public class SearchDstu2Test {
|
|||
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(SearchDstu2Test.class);
|
||||
private static int ourPort;
|
||||
|
||||
private static InstantDt ourReturnPublished;
|
||||
|
||||
private static Server ourServer;
|
||||
|
||||
@Test
|
||||
|
@ -58,18 +64,6 @@ public class SearchDstu2Test {
|
|||
assertNull(status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultBundleHasUuid() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWithRef");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, PatternMatcher.pattern("id value..[0-9a-f-]+\\\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEncodeConvertsReferencesToRelativeJson() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWithRef&_format=json");
|
||||
|
@ -87,6 +81,31 @@ public class SearchDstu2Test {
|
|||
assertNull(status.getFirstHeader(Constants.HEADER_CONTENT_LOCATION));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultBundleHasUuid() throws Exception {
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWithRef");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertEquals(200, status.getStatusLine().getStatusCode());
|
||||
assertThat(responseContent, PatternMatcher.pattern("id value..[0-9a-f-]+\\\""));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testResultBundleHasUpdateTime() throws Exception {
|
||||
ourReturnPublished = new InstantDt("2011-02-03T11:22:33Z");
|
||||
|
||||
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWithBundleProvider&_pretty=true");
|
||||
HttpResponse status = ourClient.execute(httpGet);
|
||||
String responseContent = IOUtils.toString(status.getEntity().getContent());
|
||||
IOUtils.closeQuietly(status.getEntity().getContent());
|
||||
ourLog.info(responseContent);
|
||||
|
||||
assertThat(responseContent, stringContainsInOrder("<lastUpdated value=\"2011-02-03T11:22:33Z\"/>"));
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() throws Exception {
|
||||
ourServer.stop();
|
||||
|
@ -115,12 +134,43 @@ public class SearchDstu2Test {
|
|||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Created by dsotnikov on 2/25/2014.
|
||||
*/
|
||||
public static class DummyPatientResourceProvider implements IResourceProvider {
|
||||
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
@Search(queryName="searchWithBundleProvider")
|
||||
public IBundleProvider searchWithBundleProvider() {
|
||||
return new IBundleProvider() {
|
||||
|
||||
@Override
|
||||
public InstantDt getPublished() {
|
||||
return ourReturnPublished;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<IBaseResource> getResources(int theFromIndex, int theToIndex) {
|
||||
throw new IllegalStateException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer preferredPageSize() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Search(queryName="searchWithRef")
|
||||
public Patient searchWithRef() {
|
||||
Patient patient = new Patient();
|
||||
|
@ -129,11 +179,6 @@ public class SearchDstu2Test {
|
|||
return patient;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<? extends IResource> getResourceType() {
|
||||
return Patient.class;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -157,14 +157,17 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType) {
|
||||
public void addRootPropertiesToBundle(String theAuthor, String theServerBase, String theCompleteUrl, Integer theTotalResults, BundleTypeEnum theBundleType, InstantDt theLastUpdated) {
|
||||
|
||||
if (myBundle.getId().isEmpty()) {
|
||||
myBundle.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
|
||||
InstantDt published = new InstantDt();
|
||||
published.setToCurrentTimeInLocalTimeZone();
|
||||
if (myBundle.getMeta().getLastUpdated() == null) {
|
||||
InstantType instantType = new InstantType();
|
||||
instantType.setValueAsString(theLastUpdated.getValueAsString());
|
||||
myBundle.getMeta().setLastUpdatedElement(instantType);
|
||||
}
|
||||
|
||||
if (!hasLink(Constants.LINK_SELF, myBundle) && isNotBlank(theCompleteUrl)) {
|
||||
myBundle.addLink().setRelation("self").setUrl(theCompleteUrl);
|
||||
|
@ -243,7 +246,7 @@ public class Dstu2Hl7OrgBundleFactory implements IVersionSpecificBundleFactory {
|
|||
}
|
||||
|
||||
addResourcesToBundle(resourceList, theBundleType, theServerBase, theServer.getBundleInclusionRule(), theIncludes);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType);
|
||||
addRootPropertiesToBundle(null, theServerBase, theCompleteUrl, theResult.size(), theBundleType, theResult.getPublished());
|
||||
|
||||
if (theServer.getPagingProvider() != null) {
|
||||
int limit;
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.List;
|
|||
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.io.input.ReaderInputStream;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.ProtocolVersion;
|
||||
|
@ -59,10 +60,61 @@ public class GenericClientDstu2Hl7OrgTest {
|
|||
public void before() {
|
||||
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
|
||||
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
|
||||
ourCtx.getRestfulClientFactory().setServerValidationMode(ServerValidationModeEnum.NEVER);
|
||||
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void testReadUpdatedHeaderDoesntOverwriteResourceValue() throws Exception {
|
||||
|
||||
//@formatter:off
|
||||
final String input = "<Bundle xmlns=\"http://hl7.org/fhir\">\n" +
|
||||
" <id value=\"e2ee823b-ee4d-472d-b79d-495c23f16b99\"/>\n" +
|
||||
" <meta>\n" +
|
||||
" <lastUpdated value=\"2015-06-22T15:48:57.554-04:00\"/>\n" +
|
||||
" </meta>\n" +
|
||||
" <type value=\"searchset\"/>\n" +
|
||||
" <base value=\"http://localhost:58109/fhir/context\"/>\n" +
|
||||
" <total value=\"0\"/>\n" +
|
||||
" <link>\n" +
|
||||
" <relation value=\"self\"/>\n" +
|
||||
" <url value=\"http://localhost:58109/fhir/context/Patient?_pretty=true\"/>\n" +
|
||||
" </link>\n" +
|
||||
"</Bundle>";
|
||||
//@formatter:on
|
||||
|
||||
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_XML + "; charset=UTF-8"));
|
||||
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] {
|
||||
new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Sat, 20 Jun 2015 19:32:17 GMT")
|
||||
});
|
||||
when(myHttpResponse.getEntity().getContent()).thenAnswer(new Answer<InputStream>() {
|
||||
@Override
|
||||
public InputStream answer(InvocationOnMock theInvocation) throws Throwable {
|
||||
return new ReaderInputStream(new StringReader(input), Charset.forName("UTF-8"));
|
||||
}
|
||||
});
|
||||
|
||||
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
|
||||
|
||||
org.hl7.fhir.instance.model.Bundle response;
|
||||
|
||||
//@formatter:off
|
||||
response = client
|
||||
.search()
|
||||
.forResource(Patient.class)
|
||||
.returnBundle(org.hl7.fhir.instance.model.Bundle.class)
|
||||
.execute();
|
||||
//@formatter:on
|
||||
|
||||
assertEquals("2015-06-22T15:48:57.554-04:00", response.getMeta().getLastUpdatedElement().getValueAsString());
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
@Test
|
||||
public void testSearchWithReverseInclude() throws Exception {
|
||||
|
|
|
@ -123,6 +123,13 @@
|
|||
JPA server now supports sorting on reference parameters. Thanks to
|
||||
Vishal Kachroo for reporting that this wasn't working!
|
||||
</action>
|
||||
<action type="fix">
|
||||
Prevent Last-Updated header in responses coming back to the client from
|
||||
overwriting the 'lastUpdated' value in the meta element in DSTU2
|
||||
resources. This is important because 'lastUpdated' can have more
|
||||
precision than the equivalent header, but the client previously
|
||||
gave the header priority.
|
||||
</action>
|
||||
</release>
|
||||
<release version="1.0" date="2015-May-8">
|
||||
<action type="add">
|
||||
|
|
Loading…
Reference in New Issue