Merge branch 'master' of github.com:jamesagnew/hapi-fhir

This commit is contained in:
James Agnew 2015-09-11 16:13:57 -04:00
commit 08d4ebddb7
25 changed files with 1049 additions and 373 deletions

View File

@ -60,24 +60,11 @@ public interface IGenericClient extends IRestfulClient {
@Deprecated
BaseConformance conformance();
/**
* Retrieves the server's conformance statement
*/
IFetchConformanceUntyped fetchConformance();
/**
* Fluent method for the "create" operation, which creates a new resource instance on the server
*/
ICreate create();
/**
* Fluent method for the "meta" operations, which can be used to get, add and remove tags and other
* Meta elements from a resource or across the server.
*
* @since 1.1
*/
IMeta meta();
/**
* Implementation of the "type create" method.
*
@ -121,6 +108,11 @@ public interface IGenericClient extends IRestfulClient {
@Deprecated
MethodOutcome delete(Class<? extends IResource> theType, String theId);
/**
* Retrieves the server's conformance statement
*/
IFetchConformanceUntyped fetchConformance();
/**
* Force the client to fetch the server's conformance statement and validate that it is appropriate for this client.
*
@ -179,6 +171,13 @@ public interface IGenericClient extends IRestfulClient {
@Deprecated
<T extends IResource> Bundle history(Class<T> theType, String theId, DateTimeDt theSince, Integer theLimit);
/**
* Loads the previous/next bundle of resources from a paged set, using the link specified in the "link type=next" tag within the atom bundle.
*
* @see Bundle#getLinkNext()
*/
IGetPage loadPage();
// /**
// * Implementation of the "instance read" method. This method will only ever do a "read" for the latest version of a
// * given resource instance, even if the ID passed in contains a version. If you wish to request a specific version
@ -198,11 +197,12 @@ public interface IGenericClient extends IRestfulClient {
// <T extends IBaseResource> T read(Class<T> theType, IdDt theId);
/**
* Loads the previous/next bundle of resources from a paged set, using the link specified in the "link type=next" tag within the atom bundle.
* Fluent method for the "meta" operations, which can be used to get, add and remove tags and other
* Meta elements from a resource or across the server.
*
* @see Bundle#getLinkNext()
* @since 1.1
*/
IGetPage loadPage();
IMeta meta();
/**
* Implementation of the FHIR "extended operations" action
@ -295,11 +295,6 @@ public interface IGenericClient extends IRestfulClient {
*/
ITransaction transaction();
/**
* Validate a resource
*/
IValidate validate();
/**
* Implementation of the "transaction" method.
*
@ -345,6 +340,11 @@ public interface IGenericClient extends IRestfulClient {
*/
MethodOutcome update(String theId, IResource theResource);
/**
* Validate a resource
*/
IValidate validate();
/**
* Implementation of the "type validate" method.
*

View File

@ -421,17 +421,8 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
public static class QualifierDetails {
private String myColonQualifier;
private String myDotQualifier;
public String getColonQualifier() {
return myColonQualifier;
}
public String getDotQualifier() {
return myDotQualifier;
}
public boolean passes(Set<String> theQualifierWhitelist, Set<String> theQualifierBlacklist) {
if (theQualifierWhitelist != null) {
if (!theQualifierWhitelist.contains(".*")) {
@ -445,7 +436,9 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
}
}
}
if (!theQualifierWhitelist.contains(":*")) {
/*
* This was removed Sep 9 2015, as I don't see any way it could possibly be triggered.
if (!theQualifierWhitelist.contains(SearchParameter.QUALIFIER_ANY_TYPE)) {
if (myColonQualifier != null) {
if (!theQualifierWhitelist.contains(myColonQualifier)) {
return false;
@ -456,6 +449,7 @@ public class SearchMethodBinding extends BaseResourceReturningMethodBinding {
}
}
}
*/
}
if (theQualifierBlacklist != null) {
if (myDotQualifier != null) {

View File

@ -136,7 +136,7 @@ public class SearchParameter extends BaseQueryParameter {
private List<Class<? extends IResource>> myDeclaredTypes;
private String myDescription;
private String myName;
private IParamBinder myParamBinder;
private IParamBinder<?> myParamBinder;
private RestSearchParameterTypeEnum myParamType;
private Set<String> myQualifierBlacklist;
private Set<String> myQualifierWhitelist;
@ -271,7 +271,7 @@ public class SearchParameter extends BaseQueryParameter {
this.myRequired = required;
}
@SuppressWarnings({ "unchecked" })
@SuppressWarnings({ "unchecked", "unused" })
public void setType(final Class<?> type, Class<? extends Collection<?>> theInnerCollectionType, Class<? extends Collection<?>> theOuterCollectionType) {
this.myType = type;
if (IQueryParameterType.class.isAssignableFrom(type)) {

View File

@ -50,8 +50,6 @@ public abstract class BaseAndListParam<T extends IQueryParameterOr<?>> implement
}
}
public abstract RestSearchParameterTypeEnum getSearchParamType();
abstract T newInstance();
@Override

View File

@ -1,7 +1,6 @@
package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.model.api.IQueryParameterType;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import net.sourceforge.cobertura.CoverageIgnore;
/*
@ -41,11 +40,6 @@ public class CompositeAndListParam<A extends IQueryParameterType, B extends IQue
return new CompositeOrListParam<A,B>(myLeftType, myRightType);
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.COMPOSITE;
}
@CoverageIgnore
@Override
public CompositeAndListParam<A, B> addAnd(CompositeOrListParam<A, B> theValue) {

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import net.sourceforge.cobertura.CoverageIgnore;
/*
@ -31,11 +30,6 @@ public class DateAndListParam extends BaseAndListParam<DateOrListParam> {
return new DateOrListParam();
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.DATE;
}
@CoverageIgnore
@Override
public DateAndListParam addAnd(DateOrListParam theValue) {

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import net.sourceforge.cobertura.CoverageIgnore;
/*
@ -31,11 +30,6 @@ public class NumberAndListParam extends BaseAndListParam<NumberOrListParam> {
return new NumberOrListParam();
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.NUMBER;
}
@CoverageIgnore
@Override
public NumberAndListParam addAnd(NumberOrListParam theValue) {

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import net.sourceforge.cobertura.CoverageIgnore;
/*
@ -31,11 +30,6 @@ public class QuantityAndListParam extends BaseAndListParam<QuantityOrListParam>
return new QuantityOrListParam();
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.QUANTITY;
}
@CoverageIgnore
@Override
public QuantityAndListParam addAnd(QuantityOrListParam theValue) {

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import net.sourceforge.cobertura.CoverageIgnore;
/*
@ -31,11 +30,6 @@ public class ReferenceAndListParam extends BaseAndListParam<ReferenceOrListParam
return new ReferenceOrListParam();
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.REFERENCE;
}
@CoverageIgnore
@Override
public ReferenceAndListParam addAnd(ReferenceOrListParam theValue) {

View File

@ -31,11 +31,6 @@ public class StringAndListParam extends BaseAndListParam<StringOrListParam> {
return new StringOrListParam();
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.STRING;
}
@CoverageIgnore
@Override
public StringAndListParam addAnd(StringOrListParam theValue) {

View File

@ -31,11 +31,6 @@ public class TokenAndListParam extends BaseAndListParam<TokenOrListParam> {
return new TokenOrListParam();
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.TOKEN;
}
@CoverageIgnore
@Override
public TokenAndListParam addAnd(TokenOrListParam theValue) {

View File

@ -1,6 +1,5 @@
package ca.uhn.fhir.rest.param;
import ca.uhn.fhir.rest.method.RestSearchParameterTypeEnum;
import net.sourceforge.cobertura.CoverageIgnore;
/*
@ -31,11 +30,6 @@ public class UriAndListParam extends BaseAndListParam<UriOrListParam> {
return new UriOrListParam();
}
@Override
public RestSearchParameterTypeEnum getSearchParamType() {
return RestSearchParameterTypeEnum.URI;
}
@CoverageIgnore
@Override
public UriAndListParam addAnd(UriOrListParam theValue) {

View File

@ -187,6 +187,11 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Build-Time>${maven.build.timestamp}</Build-Time>
</manifestEntries>
</archive>
<overlays>
<overlay>
<groupId>ca.uhn.hapi.fhir</groupId>

View File

@ -198,6 +198,11 @@
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Build-Time>${maven.build.timestamp}</Build-Time>
</manifestEntries>
</archive>
<overlays>
<overlay>
<groupId>ca.uhn.hapi.fhir</groupId>

View File

@ -20,14 +20,15 @@ package ca.uhn.fhir.rest.server.provider;
* #L%
*/
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.jar.Manifest;
import ca.uhn.fhir.parser.DataFormatException;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
@ -121,7 +122,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher);
retVal.setDate(DateTimeDt.withCurrentTime());
retVal.setDate(conformanceDate());
retVal.setFhirVersion("0.0.82-3059"); // TODO: pull from model
retVal.setAcceptUnknown(false); // TODO: make this configurable - this is a fairly big effort since the parser needs to be modified to actually allow it
@ -213,6 +214,33 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return retVal;
}
private DateTimeDt conformanceDate() {
String buildDate = getBuildDateFromManifest();
if (buildDate != null) {
try {
return new DateTimeDt(buildDate);
} catch (DataFormatException e) {
// fall through
}
}
return DateTimeDt.withCurrentTime();
}
private String getBuildDateFromManifest() {
if (myRestfulServer != null && myRestfulServer.getServletContext() != null) {
InputStream inputStream = myRestfulServer.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF");
if (inputStream != null) {
try {
Manifest manifest = new Manifest(inputStream);
return manifest.getMainAttributes().getValue("Build-Time");
} catch (IOException e) {
// fall through
}
}
}
return null;
}
private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
includes.addAll(searchMethodBinding.getIncludes());

View File

@ -201,7 +201,6 @@ public class GenericClientTest {
count++;
}
@Test
public void testCreateWithTag() throws Exception {
@ -627,6 +626,32 @@ public class GenericClientTest {
assertEquals("name=" + longValue, string);
}
@Test
public void testLoadPageAndReturnDstu1Bundle() throws Exception {
String msg = getPatientFeedWithOneResult();
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
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.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
IGenericClient client = ourCtx.newRestfulGenericClient("http://foo");
//@formatter:off
client
.loadPage()
.byUrl("http://example.com/page1")
.andReturnDstu1Bundle()
.execute();
//@formatter:on
assertEquals("http://example.com/page1", capt.getValue().getURI().toString());
}
@Test
public void testSearchByCompartment() throws Exception {
@ -720,41 +745,12 @@ public class GenericClientTest {
.include(Patient.INCLUDE_MANAGINGORGANIZATION)
.sort().ascending(Patient.BIRTHDATE)
.sort().descending(Patient.NAME)
.sort().defaultOrder(Patient.ADDRESS)
.limitTo(123)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_count=123&_format=json", capt.getValue().getURI().toString());
}
@SuppressWarnings("unused")
@Test
public void testSearchIncludeRecursive() throws Exception {
String msg = getPatientFeedWithOneResult();
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.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.include(Patient.INCLUDE_MANAGINGORGANIZATION)
.include(Patient.INCLUDE_LINK_OTHER.asRecursive())
.include(Patient.INCLUDE_ALL.asNonRecursive())
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), containsString("http://example.com/fhir/Patient?"));
assertThat(capt.getValue().getURI().toString(), containsString("_include=" + Patient.INCLUDE_MANAGINGORGANIZATION.getValue()));
assertThat(capt.getValue().getURI().toString(), containsString("_include%3Arecurse=" + Patient.INCLUDE_LINK_OTHER.getValue()));
assertThat(capt.getValue().getURI().toString(), containsString("_include=*"));
assertEquals("http://example.com/fhir/Patient?birthdate=%3C%3D2012-01-22&birthdate=%3E2011-01-01&_include=Patient.managingOrganization&_sort%3Aasc=birthdate&_sort%3Adesc=name&_sort=address&_count=123&_format=json", capt.getValue().getURI().toString());
}
@ -910,35 +906,6 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchWithEscapedParameters() throws Exception {
String msg = getPatientFeedWithOneResult();
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.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().values("NE,NE", "NE,NE"))
.where(Patient.NAME.matchesExactly().values("E$E"))
.where(Patient.NAME.matches().values("NE\\NE"))
.where(Patient.NAME.matchesExactly().values("E|E"))
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), containsString("%3A"));
assertEquals("http://example.com/fhir/Patient?name=NE\\,NE,NE\\,NE&name=NE\\\\NE&name:exact=E\\$E&name:exact=E\\|E", UrlUtil.unescape(capt.getValue().getURI().toString()));
}
@SuppressWarnings("unused")
@Test
public void testSearchByString() throws Exception {
@ -1025,6 +992,7 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchByToken() throws Exception {
@ -1121,6 +1089,36 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchIncludeRecursive() throws Exception {
String msg = getPatientFeedWithOneResult();
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.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource(Patient.class)
.include(Patient.INCLUDE_MANAGINGORGANIZATION)
.include(Patient.INCLUDE_LINK_OTHER.asRecursive())
.include(Patient.INCLUDE_ALL.asNonRecursive())
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), containsString("http://example.com/fhir/Patient?"));
assertThat(capt.getValue().getURI().toString(), containsString("_include=" + Patient.INCLUDE_MANAGINGORGANIZATION.getValue()));
assertThat(capt.getValue().getURI().toString(), containsString("_include%3Arecurse=" + Patient.INCLUDE_LINK_OTHER.getValue()));
assertThat(capt.getValue().getURI().toString(), containsString("_include=*"));
}
@SuppressWarnings("unused")
@Test
public void testSearchUsingGetSearch() throws Exception {
@ -1243,6 +1241,34 @@ public class GenericClientTest {
}
@SuppressWarnings("unused")
@Test
public void testSearchWithEscapedParameters() throws Exception {
String msg = getPatientFeedWithOneResult();
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.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().values("NE,NE", "NE,NE"))
.where(Patient.NAME.matchesExactly().values("E$E"))
.where(Patient.NAME.matches().values("NE\\NE"))
.where(Patient.NAME.matchesExactly().values("E|E"))
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), containsString("%3A"));
assertEquals("http://example.com/fhir/Patient?name=NE\\,NE,NE\\,NE&name=NE\\\\NE&name:exact=E\\$E&name:exact=E\\|E", UrlUtil.unescape(capt.getValue().getURI().toString()));
}
@SuppressWarnings("unused")
@Test
public void testSearchWithInternalServerError() throws Exception {
@ -1515,6 +1541,32 @@ public class GenericClientTest {
count++;
}
@Test
public void testValidateNonFluent() throws Exception {
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDetails("OOOK");
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
when(myHttpClient.execute(capt.capture())).thenReturn(myHttpResponse);
when(myHttpResponse.getAllHeaders()).thenReturn(new Header[] { });
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader(ourCtx.newXmlParser().encodeResourceToString(oo)), Charset.forName("UTF-8")));
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), 200, "OK"));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Patient p1 = new Patient();
p1.addIdentifier("foo:bar", "12345");
p1.addName().addFamily("Smith").addGiven("John");
MethodOutcome resp = client.validate(p1);
assertEquals("http://example.com/fhir/Patient/_validate", capt.getValue().getURI().toString());
oo = (OperationOutcome) resp.getOperationOutcome();
assertEquals("OOOK", oo.getIssueFirstRep().getDetails().getValue());
}
@Test
public void testVReadWithAbsoluteUrl() throws Exception {

View File

@ -15,25 +15,6 @@ import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
public class DateRangeParamTest {
private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException {
DateRangeParam p = new DateRangeParam();
List<QualifiedParamList> tokens = new ArrayList<QualifiedParamList>();
tokens.add(QualifiedParamList.singleton(null, theLower));
if (theUpper != null) {
tokens.add(QualifiedParamList.singleton(null, theUpper));
}
p.setValuesAsQueryTokens(tokens);
return p;
}
public static Date parse(String theString) throws ParseException {
return ourFmt.parse(theString);
}
public static Date parseM1(String theString) throws ParseException {
return new Date(ourFmt.parse(theString).getTime() - 1L);
}
private static SimpleDateFormat ourFmt;
static {
@ -44,6 +25,36 @@ public class DateRangeParamTest {
return new DateRangeParam(new DateParam(theString));
}
@Test
public void testAddAnd() {
assertEquals(1, new DateAndListParam().addAnd(new DateOrListParam()).getValuesAsQueryTokens().size());
assertEquals(1, new NumberAndListParam().addAnd(new NumberOrListParam()).getValuesAsQueryTokens().size());
assertEquals(1, new ReferenceAndListParam().addAnd(new ReferenceOrListParam()).getValuesAsQueryTokens().size());
assertEquals(1, new QuantityAndListParam().addAnd(new QuantityOrListParam()).getValuesAsQueryTokens().size());
assertEquals(1, new UriAndListParam().addAnd(new UriOrListParam()).getValuesAsQueryTokens().size());
assertEquals(1, new StringAndListParam().addAnd(new StringOrListParam()).getValuesAsQueryTokens().size());
}
@Test
public void testAndList() {
assertNotNull(new DateAndListParam().newInstance());
assertNotNull(new NumberAndListParam().newInstance());
assertNotNull(new ReferenceAndListParam().newInstance());
assertNotNull(new QuantityAndListParam().newInstance());
assertNotNull(new UriAndListParam().newInstance());
assertNotNull(new StringAndListParam().newInstance());
}
@Test
public void testAndOr() {
assertEquals(1, new DateOrListParam().addOr(new DateParam()).getValuesAsQueryTokens().size());
assertEquals(1, new NumberOrListParam().addOr(new NumberParam()).getValuesAsQueryTokens().size());
assertEquals(1, new ReferenceOrListParam().addOr(new ReferenceParam()).getValuesAsQueryTokens().size());
assertEquals(1, new QuantityOrListParam().addOr(new QuantityParam()).getValuesAsQueryTokens().size());
assertEquals(1, new UriOrListParam().addOr(new UriParam()).getValuesAsQueryTokens().size());
assertEquals(1, new StringOrListParam().addOr(new StringParam()).getValuesAsQueryTokens().size());
}
@Test
public void testDay() throws Exception {
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01", "<2011-01-02").getLowerBoundAsInstant());
@ -80,6 +91,16 @@ public class DateRangeParamTest {
assertEquals(parseM1("2011-01-02 00:00:00.0000"), create("2011-01-01").getUpperBoundAsInstant());
}
@Test
public void testOrList() {
assertNotNull(new DateOrListParam().newInstance());
assertNotNull(new NumberOrListParam().newInstance());
assertNotNull(new ReferenceOrListParam().newInstance());
assertNotNull(new QuantityOrListParam().newInstance());
assertNotNull(new UriOrListParam().newInstance());
assertNotNull(new StringOrListParam().newInstance());
}
@Test
public void testSecond() throws Exception {
assertEquals(parse("2011-01-01 00:00:00.0000"), create(">=2011-01-01T00:00:00", "<2011-01-01T01:00:00").getLowerBoundAsInstant());
@ -98,4 +119,23 @@ public class DateRangeParamTest {
assertEquals(parseM1("2014-01-01 00:00:00.0000"), create(">2011", "<=2013").getUpperBoundAsInstant());
}
private static DateRangeParam create(String theLower, String theUpper) throws InvalidRequestException {
DateRangeParam p = new DateRangeParam();
List<QualifiedParamList> tokens = new ArrayList<QualifiedParamList>();
tokens.add(QualifiedParamList.singleton(null, theLower));
if (theUpper != null) {
tokens.add(QualifiedParamList.singleton(null, theUpper));
}
p.setValuesAsQueryTokens(tokens);
return p;
}
public static Date parse(String theString) throws ParseException {
return ourFmt.parse(theString);
}
public static Date parseM1(String theString) throws ParseException {
return new Date(ourFmt.parse(theString).getTime() - 1L);
}
}

View File

@ -123,6 +123,7 @@ public class DateRangeParamSearchTest {
return retVal;
}
@Override
public Class<? extends IResource> getResourceType() {
return Patient.class;

View File

@ -19,24 +19,17 @@ package ca.uhn.fhir.rest.server.provider.dstu2;
* limitations under the License.
* #L%
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import static org.apache.commons.lang3.StringUtils.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.IdentityHashMap;
import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.jar.Manifest;
import javax.servlet.http.HttpServletRequest;
import ca.uhn.fhir.parser.DataFormatException;
import org.apache.commons.lang3.StringUtils;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
@ -76,7 +69,6 @@ import ca.uhn.fhir.rest.server.Constants;
import ca.uhn.fhir.rest.server.IServerConformanceProvider;
import ca.uhn.fhir.rest.server.ResourceBinding;
import ca.uhn.fhir.rest.server.RestfulServer;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
/**
@ -173,7 +165,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher);
retVal.setDate(DateTimeDt.withCurrentTime());
retVal.setDate(conformanceDate());
retVal.setFhirVersion("1.0.0"); // TODO: pull from model
retVal.setAcceptUnknown(UnknownContentCodeEnum.UNKNOWN_EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser
// needs to be modified to actually allow it
@ -304,6 +296,33 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return retVal;
}
private DateTimeDt conformanceDate() {
String buildDate = getBuildDateFromManifest();
if (buildDate != null) {
try {
return new DateTimeDt(buildDate);
} catch (DataFormatException e) {
// fall through
}
}
return DateTimeDt.withCurrentTime();
}
private String getBuildDateFromManifest() {
if (myRestfulServer != null && myRestfulServer.getServletContext() != null) {
InputStream inputStream = myRestfulServer.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF");
if (inputStream != null) {
try {
Manifest manifest = new Manifest(inputStream);
return manifest.getMainAttributes().getValue("Build-Time");
} catch (IOException e) {
// fall through
}
}
}
return null;
}
private void handleDynamicSearchMethodBinding(RestResource resource, RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
includes.addAll(searchMethodBinding.getIncludes());

View File

@ -0,0 +1,228 @@
package ca.uhn.fhir.parser;
import java.util.ArrayList;
import java.util.List;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.annotation.Child;
import ca.uhn.fhir.model.api.annotation.Description;
import ca.uhn.fhir.model.api.annotation.Extension;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import ca.uhn.fhir.model.dstu2.composite.QuantityDt;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.primitive.DateTimeDt;
import ca.uhn.fhir.model.primitive.StringDt;
import ca.uhn.fhir.util.ElementUtil;
public class CustomTypeTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomTypeTest.class);
@Test
public void testEncode() {
FhirContext ctx = FhirContext.forDstu2();
MyCustomPatient patient = new MyCustomPatient();
patient.addIdentifier().setSystem("urn:system").setValue("1234");
patient.addName().addFamily("Rossi").addGiven("Mario");
patient.setInsulinLevel(new QuantityDt());
patient.setGlucoseLevel(new QuantityDt());
patient.setHbA1c(new QuantityDt());
patient.setBloodPressure(new QuantityDt());
patient.setCholesterol(new QuantityDt());
patient.setWeight(new StringDt("80 kg"));
patient.setWeight(new StringDt("185 cm"));
patient.setCheckDates(new ArrayList<DateTimeDt>());
patient.getCheckDates().add(new DateTimeDt("2014-01-26T11:11:11"));
IParser p = ctx.newXmlParser().setPrettyPrint(true);
String messageString = p.encodeResourceToString(patient);
ourLog.info(messageString);
}
@ResourceDef(name = "Patient")
public static class MyCustomPatient extends Patient {
private static final long serialVersionUID = 1L;
@Child(name = "bloodPressure") // once every 3 month. The average target is 130/80 mmHg or less
@Extension(url = "http://example.com/BloodPressure", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's blood pressure")
private QuantityDt myBloodPressure;
// Dates of periodic tests
@Child(name = "CheckDates", max = Child.MAX_UNLIMITED)
@Extension(url = "http://example.com/diabetes2", definedLocally = false, isModifier = true)
@Description(shortDefinition = "Dates of periodic tests")
private List<DateTimeDt> myCheckDates;
@Child(name = "cholesterol") // once a year. The target is triglycerides =< 2 mmol/l e cholesterol =< 4 mmol/l
@Extension(url = "http://example.com/Cholesterol", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's cholesterol")
private QuantityDt myCholesterol;
@Child(name = "glucoseLevel") // fingerprick test
@Extension(url = "http://example.com/Glucose", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's blood glucose")
private QuantityDt myGlucoseLevel;
// Periodic Tests
@Child(name = "hbA1c") // once every 6 month. The average target is 53 mmol/mol (or 7%) or less.
@Extension(url = "http://example.com/HbA1c", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's glucose")
private QuantityDt myHbA1c;
@Child(name = "Height")
@Extension(url = "http://example.com/Height", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The patient's height in cm")
private StringDt myHeight;
@Child(name = "insulinLevel") // Normal range is [43,208] pmol/l
@Extension(url = "http://example.com/Insuline", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The value of the patient's insulin")
private QuantityDt myInsulinLevel;
// Other parameters
@Child(name = "weight")
@Extension(url = "http://example.com/Weight", definedLocally = false, isModifier = false)
@Description(shortDefinition = "The patient's weight in Kg")
private StringDt myWeight;
public QuantityDt Cholesterol() {
if (myCholesterol == null) {
myCholesterol = new QuantityDt();
}
myCholesterol.getValue();
myCholesterol.getSystem();
myCholesterol.getCode();
return myCholesterol;
}
public QuantityDt getBloodPressure() {
if (myBloodPressure == null) {
myBloodPressure = new QuantityDt();
}
myBloodPressure.getValue();
myBloodPressure.getSystem();
myBloodPressure.getCode();
return myBloodPressure;
}
public List<DateTimeDt> getCheckDates() {
if (myCheckDates == null) {
myCheckDates = new ArrayList<DateTimeDt>();
}
return myCheckDates;
}
public QuantityDt getGlucoseLevel() {
if (myGlucoseLevel == null) {
myGlucoseLevel = new QuantityDt();
}
myGlucoseLevel.getValue();
myGlucoseLevel.getSystem();
myGlucoseLevel.getCode();
return myGlucoseLevel;
}
public QuantityDt getHbA1c() {
if (myHbA1c == null) {
myHbA1c = new QuantityDt();
}
myHbA1c.getValue();
myHbA1c.getSystem();
myHbA1c.getCode();
return myHbA1c;
}
public StringDt getHeight() {
if (myHeight == null) {
myHeight = new StringDt();
}
return myHeight;
}
public QuantityDt getInsulinLevel() {
if (myInsulinLevel == null) {
myInsulinLevel = new QuantityDt();
}
myInsulinLevel.getValue();
myInsulinLevel.getSystem();
myInsulinLevel.getCode();
return myInsulinLevel;
}
public StringDt getWeight() {
if (myWeight == null) {
myWeight = new StringDt();
}
return myWeight;
}
@Override
public boolean isEmpty() {
return super.isEmpty() && ElementUtil.isEmpty(myInsulinLevel, myGlucoseLevel, myHbA1c, myBloodPressure, myCholesterol, myWeight, myHeight, myCheckDates);
}
public void setBloodPressure(QuantityDt bloodPressure) {
myBloodPressure = bloodPressure;
myBloodPressure.setValue(110);
myBloodPressure.setSystem("http://unitsofmeasure.org");
myBloodPressure.setCode("mmHg");
}
public void setCheckDates(List<DateTimeDt> theCheckDates) {
myCheckDates = theCheckDates;
myCheckDates.add(new DateTimeDt("2010-01-02"));
}
public void setCholesterol(QuantityDt cholesterol) {
myCholesterol = cholesterol;
myCholesterol.setValue(2);
myCholesterol.setSystem("http://unitsofmeasure.org");
myCholesterol.setCode("mmol/l");
}
public void setGlucoseLevel(QuantityDt glucoseLevel) {
myGlucoseLevel = glucoseLevel;
myGlucoseLevel.setValue(95);
myGlucoseLevel.setSystem("http://unitsofmeasure.org");
myGlucoseLevel.setCode("mg/dl");
}
public void setHbA1c(QuantityDt hba1c) {
myHbA1c = hba1c;
myHbA1c.setValue(48);
myHbA1c.setSystem("http://unitsofmeasure.org");
myHbA1c.setCode("mmol/mol");
}
public void setHeight(StringDt height) {
myHeight = height;
}
// Setter/Getter methods
public void setInsulinLevel(QuantityDt insulinLevel) {
myInsulinLevel = insulinLevel;
myInsulinLevel.setValue(125);
myInsulinLevel.setSystem("http://unitsofmeasure.org");
myInsulinLevel.setCode("pmol/l");
}
public void setWeight(StringDt weight) {
myWeight = weight;
}
}
}

View File

@ -15,6 +15,7 @@ import java.io.InputStream;
import java.io.StringReader;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.commons.io.IOUtils;
@ -44,15 +45,18 @@ 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.composite.MetaDt;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
import ca.uhn.fhir.model.dstu2.resource.Conformance;
import ca.uhn.fhir.model.dstu2.resource.Observation;
import ca.uhn.fhir.model.dstu2.resource.OperationOutcome;
import ca.uhn.fhir.model.dstu2.resource.Parameters;
import ca.uhn.fhir.model.dstu2.resource.Patient;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Entry;
import ca.uhn.fhir.model.dstu2.resource.Bundle.Link;
import ca.uhn.fhir.model.primitive.DateDt;
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.model.primitive.UriDt;
import ca.uhn.fhir.parser.IParser;
import ca.uhn.fhir.parser.XmlParserDstu2Test;
import ca.uhn.fhir.rest.api.MethodOutcome;
@ -102,6 +106,41 @@ public class GenericClientDstu2Test {
return msg;
}
@Test
@SuppressWarnings("deprecation")
public void testConformance() throws Exception {
IParser p = ourCtx.newXmlParser();
Conformance conf = new Conformance();
conf.setCopyright("COPY");
final String respString = p.encodeResourceToString(conf);
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.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
//@formatter:off
Conformance resp = (Conformance)client.conformance();
//@formatter:on
assertEquals("http://example.com/fhir/metadata", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("COPY", resp.getCopyright());
assertEquals("GET", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
}
@Test
public void testCreate() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -183,6 +222,74 @@ public class GenericClientDstu2Test {
}
@SuppressWarnings("deprecation")
@Test
public void testCreateNonFluent() throws Exception {
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().getContent()).then(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.create(p);
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://example.com/fhir/Patient", capt.getAllValues().get(idx).getURI().toString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
}
@SuppressWarnings("deprecation")
@Test
public void testUpdateNonFluent() throws Exception {
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().getContent()).then(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
Patient p = new Patient();
p.addName().addFamily("FOOFAMILY");
client.update(new IdDt("Patient/123"), p);
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(idx).getURI().toString());
assertEquals("PUT", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
client.update("123", p);
assertEquals(1, capt.getAllValues().get(idx).getHeaders(Constants.HEADER_CONTENT_TYPE).length);
assertEquals(EncodingEnum.XML.getResourceContentType() + Constants.HEADER_SUFFIX_CT_UTF_8, capt.getAllValues().get(idx).getFirstHeader(Constants.HEADER_CONTENT_TYPE).getValue());
assertThat(extractBody(capt, idx), containsString("<family value=\"FOOFAMILY\"/>"));
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(idx).getURI().toString());
assertEquals("PUT", capt.getAllValues().get(idx).getRequestLine().getMethod());
idx++;
}
@Test
public void testCreatePrefer() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -277,6 +384,35 @@ public class GenericClientDstu2Test {
}
@SuppressWarnings("deprecation")
@Test
public void testDeleteNonFluent() throws Exception {
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().getContent()).then(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(""), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
client.delete(Patient.class, new IdDt("Patient/123"));
assertEquals("DELETE", capt.getAllValues().get(idx).getMethod());
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(idx).getURI().toString());
idx++;
client.delete(Patient.class, "123");
assertEquals("DELETE", capt.getAllValues().get(idx).getMethod());
assertEquals("http://example.com/fhir/Patient/123", capt.getAllValues().get(idx).getURI().toString());
idx++;
}
@Test
public void testHistory() throws Exception {
@ -309,6 +445,31 @@ public class GenericClientDstu2Test {
assertEquals(1, response.getEntry().size());
idx++;
//@formatter:off
response = client
.history()
.onServer()
.andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.since((Date)null)
.count(null)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.getEntry().size());
idx++;
//@formatter:off
response = client
.history()
.onServer()
.andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.since(new InstantDt())
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.getEntry().size());
idx++;
//@formatter:off
response = client
.history()
@ -330,7 +491,32 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient/123/_history", capt.getAllValues().get(idx).getURI().toString());
assertEquals(1, response.getEntry().size());
idx++;
}
//@formatter:off
response = client
.history()
.onInstance(new IdDt("Patient", "123"))
.andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.count(123)
.since(new InstantDt("2001-01-02T11:22:33Z"))
.execute();
//@formatter:on
assertThat(capt.getAllValues().get(idx).getURI().toString(), either(equalTo("http://example.com/fhir/Patient/123/_history?_since=2001-01-02T11:22:33Z&_count=123")).or(equalTo("http://example.com/fhir/Patient/123/_history?_count=123&_since=2001-01-02T11:22:33Z")));
assertEquals(1, response.getEntry().size());
idx++;
//@formatter:off
response = client
.history()
.onInstance(new IdDt("Patient", "123"))
.andReturnBundle(ca.uhn.fhir.model.dstu2.resource.Bundle.class)
.since(new InstantDt("2001-01-02T11:22:33Z").getValue())
.execute();
//@formatter:on
assertThat(capt.getAllValues().get(idx).getURI().toString(), containsString("_since=2001-01"));
assertEquals(1, response.getEntry().size());
idx++;
}
@Test
public void testMetaAdd() throws Exception {
@ -373,46 +559,6 @@ public class GenericClientDstu2Test {
}
@Test
public void testMetaDelete() throws Exception {
IParser p = ourCtx.newXmlParser();
MetaDt inMeta = new MetaDt().addProfile("urn:profile:in");
Parameters outParams = new Parameters();
outParams.addParameter().setName("meta").setValue(new MetaDt().addProfile("urn:profile:out"));
final String respString = p.encodeResourceToString(outParams);
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.getEntity().getContent()).thenAnswer(new Answer<ReaderInputStream>() {
@Override
public ReaderInputStream answer(InvocationOnMock theInvocation) throws Throwable {
return new ReaderInputStream(new StringReader(respString), Charset.forName("UTF-8"));
}
});
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int idx = 0;
//@formatter:off
MetaDt resp = client
.meta()
.delete()
.onResource(new IdDt("Patient/123"))
.meta(inMeta)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient/123/$meta-delete", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("urn:profile:out", resp.getProfile().get(0).getValue());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"meta\"/><valueMeta><profile value=\"urn:profile:in\"/></valueMeta></parameter></Parameters>", extractBody(capt, idx));
idx++;
}
@Test
public void testMetaGet() throws Exception {
@ -670,8 +816,9 @@ public class GenericClientDstu2Test {
Parameters outParams = client.operation().onInstance(new IdDt("Patient", "18066")).named("$everything").withParameters(inParams).execute();
/*
* Note that the $everything operation returns a Bundle instead of a Parameters resource. The client operation methods return a Parameters instance however, so HAPI creates a Parameters object
* with a single parameter containing the value.
* Note that the $everything operation returns a Bundle instead of a Parameters resource. The client operation
* methods return a Parameters instance however, so HAPI creates a Parameters object with a single parameter
* containing the value.
*/
ca.uhn.fhir.model.dstu2.resource.Bundle responseBundle = (ca.uhn.fhir.model.dstu2.resource.Bundle) outParams.getParameter().get(0).getResource();
@ -985,6 +1132,68 @@ public class GenericClientDstu2Test {
}
@Test
public void testReadByUri() throws Exception {
Patient patient = new Patient();
patient.addName().addFamily("FAM");
final String input = ourCtx.newXmlParser().encodeResourceToString(patient);
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");
Patient response;
int idx = 0;
response = (Patient) client.read(new UriDt("http://domain2.example.com/base/Patient/123"));
assertEquals("http://domain2.example.com/base/Patient/123", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("FAM", response.getName().get(0).getFamily().get(0).getValue());
}
@Test
public void testReadFluentByUri() throws Exception {
Patient patient = new Patient();
patient.addName().addFamily("FAM");
final String input = ourCtx.newXmlParser().encodeResourceToString(patient);
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");
Patient response;
int idx = 0;
response = (Patient)client
.read()
.resource(Patient.class)
.withUrl(new IdDt("http://domain2.example.com/base/Patient/123"))
.execute();
assertEquals("http://domain2.example.com/base/Patient/123", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("FAM", response.getName().get(0).getFamily().get(0).getValue());
}
@Test
public void testReadUpdatedHeaderDoesntOverwriteResourceValue() throws Exception {
@ -1031,109 +1240,6 @@ public class GenericClientDstu2Test {
assertEquals("2015-06-22T15:48:57.554-04:00", ResourceMetadataKeyEnum.UPDATED.get(response).getValueAsString());
}
@Test
public void testSearchByString() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?name=james", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testSearchWithProfileAndSecurity() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.withProfile("http://foo1")
.withProfile("http://foo2")
.withSecurity("system1", "code1")
.withSecurity("system2", "code2")
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_security=system1%7Ccode1&_security=system2%7Ccode2&_profile=http%3A%2F%2Ffoo1&_profile=http%3A%2F%2Ffoo2", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testSearchWithSummaryParam() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.summaryMode(SummaryEnum.FALSE)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?name=james&_summary=false", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testSearchWithElementsParam() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.elementsSubset("name", "identifier")
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), either(equalTo("http://example.com/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient?name=james&_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testReadWithElementsParam() throws Exception {
String msg = "{\"resourceType\":\"Patient\",\"id\":\"1\",\"meta\":{\"versionId\":\"1\",\"lastUpdated\":\"2014-12-20T18:41:29.706-05:00\"},\"identifier\":[{\"system\":\"urn:MultiFhirVersionTest\",\"value\":\"testSubmitPatient01\"}]}}";
@ -1159,7 +1265,6 @@ public class GenericClientDstu2Test {
}
@Test
public void testReadWithSummaryParamHtml() throws Exception {
String msg = "<div>HELP IM A DIV</div>";
@ -1186,6 +1291,29 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchByString() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?name=james", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
/**
* See #191
@ -1219,6 +1347,31 @@ public class GenericClientDstu2Test {
assertEquals("Observation", link.getUrl());
}
@Test
public void testSearchWithElementsParam() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.elementsSubset("name", "identifier")
.execute();
//@formatter:on
assertThat(capt.getValue().getURI().toString(), either(equalTo("http://example.com/fhir/Patient?name=james&_elements=name%2Cidentifier")).or(equalTo("http://example.com/fhir/Patient?name=james&_elements=identifier%2Cname")));
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testSearchWithLastUpdated() throws Exception {
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\"}]}}]}";
@ -1244,6 +1397,33 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchWithProfileAndSecurity() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.withProfile("http://foo1")
.withProfile("http://foo2")
.withSecurity("system1", "code1")
.withSecurity("system2", "code2")
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?_security=system1%7Ccode1&_security=system2%7Ccode2&_profile=http%3A%2F%2Ffoo1&_profile=http%3A%2F%2Ffoo2", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@SuppressWarnings("unused")
@Test
public void testSearchWithReverseInclude() throws Exception {
@ -1270,6 +1450,31 @@ public class GenericClientDstu2Test {
}
@Test
public void testSearchWithSummaryParam() throws Exception {
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()).thenReturn(new ReaderInputStream(new StringReader(msg), Charset.forName("UTF-8")));
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()
.forResource("Patient")
.where(Patient.NAME.matches().value("james"))
.summaryMode(SummaryEnum.FALSE)
.execute();
//@formatter:on
assertEquals("http://example.com/fhir/Patient?name=james&_summary=false", capt.getValue().getURI().toString());
assertEquals(Patient.class, response.getEntries().get(0).getResource().getClass());
}
@Test
public void testTransactionWithListOfResources() throws Exception {
@ -1537,7 +1742,7 @@ public class GenericClientDstu2Test {
public void testValidateFluent() throws Exception {
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDetails("FOOBAR");
oo.addIssue().setDiagnostics("FOOBAR");
final String msg = ourCtx.newXmlParser().encodeResourceToString(oo);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -1562,21 +1767,17 @@ public class GenericClientDstu2Test {
response = client.validate().resource(p).execute();
assertEquals("http://example.com/fhir/Patient/$validate", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",
extractBody(capt, idx));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDetailsElement().getValue());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
response = client.validate().resource(ourCtx.newXmlParser().encodeResourceToString(p)).execute();
assertEquals("http://example.com/fhir/Patient/$validate?_format=xml", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",
extractBody(capt, idx));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDetailsElement().getValue());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
response = client.validate().resource(ourCtx.newJsonParser().encodeResourceToString(p)).execute();
@ -1584,7 +1785,7 @@ public class GenericClientDstu2Test {
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals("{\"resourceType\":\"Parameters\",\"parameter\":[{\"name\":\"resource\",\"resource\":{\"resourceType\":\"Patient\",\"name\":[{\"given\":[\"GIVEN\"]}]}}]}", extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDetailsElement().getValue());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
response = client.validate().resource(ourCtx.newJsonParser().encodeResourceToString(p)).prettyPrint().execute();
@ -1592,7 +1793,7 @@ public class GenericClientDstu2Test {
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertThat(extractBody(capt, idx), containsString("\"resourceType\":\"Parameters\",\n"));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDetailsElement().getValue());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
}
@ -1600,7 +1801,7 @@ public class GenericClientDstu2Test {
public void testValidateNonFluent() throws Exception {
OperationOutcome oo = new OperationOutcome();
oo.addIssue().setDetails("FOOBAR");
oo.addIssue().setDiagnostics("FOOBAR");
final String msg = ourCtx.newXmlParser().encodeResourceToString(oo);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -1628,11 +1829,9 @@ public class GenericClientDstu2Test {
assertEquals("http://example.com/fhir/Patient/$validate", capt.getAllValues().get(idx).getURI().toASCIIString());
assertEquals("POST", capt.getAllValues().get(idx).getRequestLine().getMethod());
assertEquals(
"<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>",
extractBody(capt, idx));
assertEquals("<Parameters xmlns=\"http://hl7.org/fhir\"><parameter><name value=\"resource\"/><resource><Patient xmlns=\"http://hl7.org/fhir\"><name><given value=\"GIVEN\"/></name></Patient></resource></parameter></Parameters>", extractBody(capt, idx));
assertNotNull(response.getOperationOutcome());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDetailsElement().getValue());
assertEquals("FOOBAR", toOo(response.getOperationOutcome()).getIssueFirstRep().getDiagnosticsElement().getValue());
idx++;
}

View File

@ -7,6 +7,7 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertThat;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -21,6 +22,7 @@ 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.Before;
import org.junit.BeforeClass;
import org.junit.Test;
@ -29,7 +31,10 @@ 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.RequiredParam;
import ca.uhn.fhir.rest.annotation.Search;
import ca.uhn.fhir.rest.param.DateAndListParam;
import ca.uhn.fhir.rest.param.ReferenceParam;
import ca.uhn.fhir.util.PatternMatcher;
import ca.uhn.fhir.util.PortUtil;
@ -42,10 +47,72 @@ public class SearchDstu2Test {
private static FhirContext ourCtx = FhirContext.forDstu2();
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;
private static String ourLastMethod;
private static DateAndListParam ourLastDateAndList;
@Before
public void before() {
ourLastMethod = null;
ourLastDateAndList = null;
}
@Test
public void testSearchWhitelist01Failing() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWhitelist01&ref=value");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchDateAndList() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?searchDateAndList=2001,2002&searchDateAndList=2003,2004");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals("searchDateAndList", ourLastMethod);
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().size());
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().size());
assertEquals(2, ourLastDateAndList.getValuesAsQueryTokens().get(1).getValuesAsQueryTokens().size());
assertEquals("2001", ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(0).getValueAsString());
assertEquals("2002", ourLastDateAndList.getValuesAsQueryTokens().get(0).getValuesAsQueryTokens().get(1).getValueAsString());
}
@Test
public void testSearchBlacklist01Failing() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchBlacklist01&ref.black1=value");
HttpResponse status = ourClient.execute(httpGet);
String responseContent = IOUtils.toString(status.getEntity().getContent());
IOUtils.closeQuietly(status.getEntity().getContent());
ourLog.info(responseContent);
assertEquals(400, status.getStatusLine().getStatusCode());
}
@Test
public void testSearchBlacklist01Passing() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchBlacklist01&ref.white1=value");
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());
assertEquals("searchBlacklist01", ourLastMethod);
}
@Test
public void testSearchWhitelist01Passing() throws Exception {
HttpGet httpGet = new HttpGet("http://localhost:" + ourPort + "/Patient?_query=searchWhitelist01&ref.white1=value");
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());
assertEquals("searchWhitelist01", ourLastMethod);
}
@Test
public void testEncodeConvertsReferencesToRelative() throws Exception {
@ -145,6 +212,34 @@ public class SearchDstu2Test {
return Patient.class;
}
//@formatter:off
@Search(queryName="searchWhitelist01")
public List<Patient> searchWhitelist01(
@RequiredParam(chainWhitelist="white1", name = "ref") ReferenceParam theParam) {
ourLastMethod = "searchWhitelist01";
return Collections.emptyList();
}
//@formatter:on
//@formatter:off
@Search()
public List<Patient> searchDateAndList(
@RequiredParam(name = "searchDateAndList") DateAndListParam theParam) {
ourLastMethod = "searchDateAndList";
ourLastDateAndList = theParam;
return Collections.emptyList();
}
//@formatter:on
//@formatter:off
@Search(queryName="searchBlacklist01")
public List<Patient> searchBlacklist01(
@RequiredParam(chainBlacklist="black1", name = "ref") ReferenceParam theParam) {
ourLastMethod = "searchBlacklist01";
return Collections.emptyList();
}
//@formatter:on
@Search(queryName="searchWithBundleProvider")
public IBundleProvider searchWithBundleProvider() {
return new IBundleProvider() {

View File

@ -21,6 +21,11 @@ package org.hl7.fhir.instance.conf;
*/
import static org.apache.commons.lang3.StringUtils.isNotBlank;
import java.io.IOException;
import java.io.InputStream;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@ -34,6 +39,7 @@ import java.util.Map.Entry;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.jar.Manifest;
import javax.servlet.http.HttpServletRequest;
@ -79,12 +85,16 @@ import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import ca.uhn.fhir.rest.server.exceptions.ResourceNotFoundException;
/**
* Server FHIR Provider which serves the conformance statement for a RESTful server implementation
* Server FHIR Provider which serves the conformance statement for a RESTful
* server implementation
*
* <p>
* Note: This class is safe to extend, but it is important to note that the same instance of {@link Conformance} is always returned unless
* {@link #setCache(boolean)} is called with a value of <code>false</code>. This means that if you are adding anything to the returned conformance instance on
* each call you should call <code>setCache(false)</code> in your provider constructor.
* Note: This class is safe to extend, but it is important to note that the same
* instance of {@link Conformance} is always returned unless
* {@link #setCache(boolean)} is called with a value of <code>false</code>. This
* means that if you are adding anything to the returned conformance instance on
* each call you should call <code>setCache(false)</code> in your provider
* constructor.
* </p>
*/
public class ServerConformanceProvider implements IServerConformanceProvider<Conformance> {
@ -162,8 +172,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
/**
* Gets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null
* (although this is not enforced). The value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
* Gets the value of the "publisher" that will be placed in the generated
* conformance statement. As this is a mandatory element, the value should not
* be null (although this is not enforced). The value defaults to
* "Not provided" but may be set to null, which will cause this element to be
* omitted.
*/
public String getPublisher() {
return myPublisher;
@ -179,7 +192,7 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
Conformance retVal = new Conformance();
retVal.setPublisher(myPublisher);
retVal.setDate(new Date());
retVal.setDate(conformanceDate());
retVal.setFhirVersion("1.0.0"); // TODO: pull from model
retVal.setAcceptUnknown(UnknownContentCode.EXTENSIONS); // TODO: make this configurable - this is a fairly big effort since the parser
// needs to be modified to actually allow it
@ -211,7 +224,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
TreeSet<String> includes = new TreeSet<String>();
// Map<String, Conformance.RestResourceSearchParam> nameToSearchParam = new HashMap<String,
// Map<String, Conformance.RestResourceSearchParam> nameToSearchParam =
// new HashMap<String,
// Conformance.RestResourceSearchParam>();
for (BaseMethodBinding<?> nextMethodBinding : nextEntry.getValue()) {
if (nextMethodBinding.getRestOperationType() != null) {
@ -315,6 +329,34 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
return retVal;
}
private Date conformanceDate() {
String buildDate = getBuildDateFromManifest();
if (buildDate != null) {
DateFormat dateFormat = new SimpleDateFormat();
try {
return dateFormat.parse(buildDate);
} catch (ParseException e) {
// fall through
}
}
return new Date();
}
private String getBuildDateFromManifest() {
if (myRestfulServer != null && myRestfulServer.getServletContext() != null) {
InputStream inputStream = myRestfulServer.getServletContext().getResourceAsStream("/META-INF/MANIFEST.MF");
if (inputStream != null) {
try {
Manifest manifest = new Manifest(inputStream);
return manifest.getMainAttributes().getValue("Build-Time");
} catch (IOException e) {
// fall through
}
}
}
return null;
}
private void handleDynamicSearchMethodBinding(ConformanceRestResourceComponent resource,
RuntimeResourceDefinition def, TreeSet<String> includes, DynamicSearchMethodBinding searchMethodBinding) {
includes.addAll(searchMethodBinding.getIncludes());
@ -339,7 +381,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
String nextParamDescription = nextParameter.getDescription();
/*
* If the parameter has no description, default to the one from the resource
* If the parameter has no description, default to the one from the
* resource
*/
if (StringUtils.isBlank(nextParamDescription)) {
RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName);
@ -382,9 +425,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
// query = new OperationDefinition();
// operation.setDefinition(new ResourceReferenceDt(query));
// query.getDescriptionElement().setValue(searchMethodBinding.getDescription());
// query.addUndeclaredExtension(false, ExtensionConstants.QUERY_RETURN_TYPE, new CodeDt(resourceName));
// query.addUndeclaredExtension(false,
// ExtensionConstants.QUERY_RETURN_TYPE, new CodeDt(resourceName));
// for (String nextInclude : searchMethodBinding.getIncludes()) {
// query.addUndeclaredExtension(false, ExtensionConstants.QUERY_ALLOWED_INCLUDE, new StringDt(nextInclude));
// query.addUndeclaredExtension(false,
// ExtensionConstants.QUERY_ALLOWED_INCLUDE, new StringDt(nextInclude));
// }
// }
@ -402,7 +447,8 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
String nextParamDescription = nextParameter.getDescription();
/*
* If the parameter has no description, default to the one from the resource
* If the parameter has no description, default to the one from the
* resource
*/
if (StringUtils.isBlank(nextParamDescription)) {
RuntimeSearchParam paramDef = def.getSearchParam(nextParamUnchainedName);
@ -535,9 +581,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
/**
* Sets the cache property (default is true). If set to true, the same response will be returned for each invocation.
* Sets the cache property (default is true). If set to true, the same
* response will be returned for each invocation.
* <p>
* See the class documentation for an important note if you are extending this class
* See the class documentation for an important note if you are extending this
* class
* </p>
*/
public void setCache(boolean theCache) {
@ -545,8 +593,11 @@ public class ServerConformanceProvider implements IServerConformanceProvider<Con
}
/**
* Sets the value of the "publisher" that will be placed in the generated conformance statement. As this is a mandatory element, the value should not be null
* (although this is not enforced). The value defaults to "Not provided" but may be set to null, which will cause this element to be omitted.
* Sets the value of the "publisher" that will be placed in the generated
* conformance statement. As this is a mandatory element, the value should not
* be null (although this is not enforced). The value defaults to
* "Not provided" but may be set to null, which will cause this element to be
* omitted.
*/
public void setPublisher(String thePublisher) {
myPublisher = thePublisher;

View File

@ -196,6 +196,9 @@
</licenses>
<properties>
<!-- configure timestamp in MANIFEST.MF for maven-war-provider -->
<maven.build.timestamp.format>yyyy-MM-dd'T'HH:mm:ss'Z'</maven.build.timestamp.format>
<!-- This property is used in some of the site documentation where the version is shown, so that we can deploy the site even if the project is on a snapshot version. -->
<hapi_stable_version>1.1</hapi_stable_version>

View File

@ -178,6 +178,10 @@
words, if this parameter is found, the response won't be returned as
HTML even if the request is detected as coming from a browser.
</action>
<action type="add">
RestfulServer now supports dynamically adding and removing resource providers
at runtime. Thanks to Bill Denton for adding this.
</action>
</release>
<release version="1.1" date="2015-07-13">
<action type="add">