Fix some broken unit tests and do a few documentation updates

This commit is contained in:
jamesagnew 2015-01-24 16:17:20 +01:00
parent e19e96db28
commit c36cbb893d
16 changed files with 150 additions and 77 deletions

View File

@ -16,7 +16,7 @@ public class FhirContextIntro {
@SuppressWarnings("unused")
public static void creatingContext() {
// START SNIPPET: creatingContext
FhirContext ctx = new FhirContext();
FhirContext ctx = FhirContext.forDstu1();
// END SNIPPET: creatingContext
}
@ -84,7 +84,7 @@ System.out.println(encoded);
public static void parseMsg() {
FhirContext ctx = new FhirContext(Patient.class, Observation.class);
FhirContext ctx = FhirContext.forDstu1();
//START SNIPPET: parseMsg
// The following is an example Patient resource

View File

@ -22,8 +22,10 @@ public class GenericClientExample {
public static void simpleExample() {
// START SNIPPET: simple
FhirContext ctx = new FhirContext();
String serverBase = "http://fhirtest.uhn.ca/base";
// We're connecting to a DSTU1 compliant server in this example
FhirContext ctx = FhirContext.forDstu1();
String serverBase = "http://fhirtest.uhn.ca/baseDstu1";
IGenericClient client = ctx.newRestfulGenericClient(serverBase);
// Perform a search

View File

@ -32,8 +32,7 @@ import org.hl7.fhir.instance.model.IBaseResource;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.annotation.ResourceDef;
import com.phloc.commons.url.URLValidator;
import ca.uhn.fhir.util.UrlUtil;
public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefinition<IBaseResource> {
@ -106,9 +105,9 @@ public class RuntimeResourceDefinition extends BaseRuntimeElementCompositeDefini
return "";
}
if (!URLValidator.isValid(profile)) {
if (!UrlUtil.isValid(profile)) {
String profileWithUrl = theServerBase + "/Profile/" + profile;
if (URLValidator.isValid(profileWithUrl)) {
if (UrlUtil.isValid(profileWithUrl)) {
return profileWithUrl;
}
}

View File

@ -146,11 +146,11 @@ public class RestfulClientFactory implements IRestfulClientFactory {
}
HttpClient httpClient = getHttpClient();
String serverBase = normalizeAndMaybeValidateServerBase(theServerBase, httpClient);
maybeValidateServerBase(theServerBase, httpClient);
ClientInvocationHandlerFactory invocationHandler = myInvocationHandlers.get(theClientType);
if (invocationHandler == null) {
invocationHandler = new ClientInvocationHandlerFactory(httpClient, myContext, serverBase, theClientType);
invocationHandler = new ClientInvocationHandlerFactory(httpClient, myContext, theServerBase, theClientType);
for (Method nextMethod : theClientType.getMethods()) {
BaseMethodBinding<?> binding = BaseMethodBinding.bindMethod(nextMethod, myContext, null);
invocationHandler.addBinding(nextMethod, binding);
@ -166,11 +166,11 @@ public class RestfulClientFactory implements IRestfulClientFactory {
@Override
public synchronized IGenericClient newGenericClient(String theServerBase) {
HttpClient httpClient = getHttpClient();
String serverBase = normalizeAndMaybeValidateServerBase(theServerBase, httpClient);
return new GenericClient(myContext, httpClient, serverBase);
maybeValidateServerBase(theServerBase, httpClient);
return new GenericClient(myContext, httpClient, theServerBase);
}
private String normalizeAndMaybeValidateServerBase(String theServerBase, HttpClient theHttpClient) {
private void maybeValidateServerBase(String theServerBase, HttpClient theHttpClient) {
String serverBase = theServerBase;
if (!serverBase.endsWith("/")) {
serverBase = serverBase + "/";
@ -187,7 +187,6 @@ public class RestfulClientFactory implements IRestfulClientFactory {
break;
}
return serverBase;
}
@Override

View File

@ -109,7 +109,6 @@ public class RestfulServer extends HttpServlet {
public RestfulServer(FhirContext theCtx) {
myFhirContext = theCtx;
myServerConformanceProvider = theCtx.getVersion().createServerConformanceProvider(this);
}
/**
@ -362,10 +361,10 @@ public class RestfulServer extends HttpServlet {
/**
* Returns the server conformance provider, which is the provider that is used to generate the server's conformance
* (metadata) statement.
* (metadata) statement if one has been explicitly defined.
* <p>
* By default, the ServerConformanceProvider for the declared version of FHIR is used, but this can be changed, or set to <code>null</code>
* if you do not wish to export a conformance statement.
* to use the appropriate one for the given FHIR version.
* </p>
*/
public Object getServerConformanceProvider() {
@ -775,7 +774,12 @@ public class RestfulServer extends HttpServlet {
}
findResourceMethods(getServerProfilesProvider());
findSystemMethods(getServerConformanceProvider());
Object confProvider = getServerConformanceProvider();
if (confProvider == null) {
confProvider = myFhirContext.getVersion().createServerConformanceProvider(this);
}
findSystemMethods(confProvider);
} catch (Exception ex) {
ourLog.error("An error occurred while loading request handlers!", ex);

View File

@ -84,4 +84,44 @@ public class UrlUtil {
return theExtensionUrl;
}
public static boolean isValid(String theUrl) {
if (theUrl == null || theUrl.length() < 8) {
return false;
}
String url = theUrl.toLowerCase();
if (url.charAt(0) != 'h') {
return false;
}
if (url.charAt(1) != 't') {
return false;
}
if (url.charAt(2) != 't') {
return false;
}
if (url.charAt(3) != 'p') {
return false;
}
int slashOffset;
if (url.charAt(4) == ':') {
slashOffset = 5;
} else if (url.charAt(4) == 's') {
if (url.charAt(5) != ':') {
return false;
}
slashOffset = 6;
} else {
return false;
}
if (url.charAt(slashOffset) != '/') {
return false;
}
if (url.charAt(slashOffset + 1) != '/') {
return false;
}
return true;
}
}

View File

@ -1,4 +1,4 @@
<div>
<th:block th:if="${not resource.name.empty}" th:text="${resource.name.value}"/>
<th:block th:if="${resource.name.empty}">Unknown Organization</th:block>
<th:block th:if="${not resource.nameElement.empty}" th:text="${resource.nameElement.value}"/>
<th:block th:if="${resource.nameElement.empty}">Unknown Organization</th:block>
</div>

View File

@ -6,6 +6,23 @@ import org.junit.Test;
public class UrlUtilTest {
@Test
public void testIsValid() {
assertTrue(UrlUtil.isValid("http://foo"));
assertTrue(UrlUtil.isValid("https://foo"));
assertTrue(UrlUtil.isValid("HTTP://Foo"));
assertTrue(UrlUtil.isValid("HTTPS://Foo"));
assertFalse(UrlUtil.isValid("file://foo"));
assertFalse(UrlUtil.isValid("://foo"));
assertFalse(UrlUtil.isValid("http:/ss"));
assertFalse(UrlUtil.isValid("http:/"));
assertFalse(UrlUtil.isValid("http:"));
assertFalse(UrlUtil.isValid("h"));
assertFalse(UrlUtil.isValid(""));
assertFalse(UrlUtil.isValid(null));
}
@Test
public void testConstructAbsoluteUrl() {
assertEquals("http://foo/bar/baz", UrlUtil.constructAbsoluteUrl(null, "http://foo/bar/baz"));

View File

@ -304,7 +304,7 @@ public class JsonParserTest {
String actual = ourCtx.newJsonParser().encodeBundleToString(bundle);
ourLog.info(actual);
String expected = "{\"resourceType\":\"Bundle\",\"entry\":[{\"deleted\":{\"type\":\"Patient\",\"resourceId\":\"111\",\"versionId\":\"222\",\"instant\":\"2011-01-01T12:12:22Z\"}}]";
String expected = "{\"resourceType\":\"Bundle\",\"entry\":[{\"deleted\":{\"type\":\"Patient\",\"resourceId\":\"111\",\"versionId\":\"222\",\"instant\":\"2011-01-01T12:12:22Z\"}}]}";
assertEquals(expected, actual);
}

View File

@ -21,11 +21,11 @@ import org.mockito.Matchers;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.model.dev.resource.Conformance;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.server.Constants;
public class ClientServerValidationTest {
public class ClientServerValidationTestDev {
private FhirContext myCtx;
private HttpClient myHttpClient;
@ -36,7 +36,7 @@ public class ClientServerValidationTest {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
myCtx = FhirContext.forDev();
myCtx = FhirContext.forDstu1();
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
}
@ -64,7 +64,7 @@ public class ClientServerValidationTest {
@Test
public void testServerReturnsWrongVersionDev() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.0.8");
conf.setFhirVersion("0.8.0");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);

View File

@ -3,17 +3,14 @@ package ca.uhn.fhir.rest.client;
import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.IOException;
import java.io.StringReader;
import java.nio.charset.Charset;
import org.apache.commons.io.IOUtils;
import org.apache.commons.io.input.ReaderInputStream;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.ProtocolVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpEntityEnclosingRequestBase;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicStatusLine;
@ -24,8 +21,6 @@ import org.junit.Test;
import org.mockito.ArgumentCaptor;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import com.google.common.base.Preconditions;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
import ca.uhn.fhir.model.api.TagList;
@ -41,8 +36,7 @@ import ca.uhn.fhir.rest.server.exceptions.PreconditionFailedException;
*/
public class ETagClientTest {
private static FhirContext myCtx;
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(GenericClientTest.class);
private static FhirContext ourCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@ -51,17 +45,12 @@ public class ETagClientTest {
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
private String extractBody(ArgumentCaptor<HttpUriRequest> capt, int count) throws IOException {
String body = IOUtils.toString(((HttpEntityEnclosingRequestBase) capt.getAllValues().get(count)).getEntity().getContent(), "UTF-8");
return body;
}
private String getResourceResult() {
//@formatter:off
String msg =
@ -78,9 +67,8 @@ public class ETagClientTest {
return msg;
}
private Patient getResource() {
return myCtx.newXmlParser().parseResource(Patient.class, getResourceResult());
return ourCtx.newXmlParser().parseResource(Patient.class, getResourceResult());
}
@Test
@ -103,7 +91,7 @@ public class ETagClientTest {
//@formatter:on
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
Patient response = client.read(Patient.class, new IdDt("Patient/1234"));
@ -128,10 +116,10 @@ public class ETagClientTest {
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_304_NOT_MODIFIED, "Not modified"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
//@formatter:off
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("")));
try {
@ -165,7 +153,6 @@ public class ETagClientTest {
}
@Test
public void testUpdateWithIfMatch() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -173,10 +160,10 @@ public class ETagClientTest {
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_200_OK, "OK"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
//@formatter:off
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("")));
client
@ -203,7 +190,6 @@ public class ETagClientTest {
}
@Test
public void testUpdateWithIfMatchWithPreconditionFailed() throws Exception {
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);
@ -211,10 +197,10 @@ public class ETagClientTest {
when(myHttpResponse.getStatusLine()).thenReturn(new BasicStatusLine(new ProtocolVersion("HTTP", 1, 1), Constants.STATUS_HTTP_412_PRECONDITION_FAILED, "Precondition Failed"));
when(myHttpResponse.getEntity().getContentType()).thenReturn(new BasicHeader("content-type", Constants.CT_FHIR_XML + "; charset=UTF-8"));
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
//@formatter:off
when(myHttpResponse.getEntity().getContent()).thenReturn(new ReaderInputStream(new StringReader("")));
try {
@ -261,15 +247,14 @@ public class ETagClientTest {
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")));
Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"),
new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
Header[] headers = new Header[] { new BasicHeader(Constants.HEADER_LAST_MODIFIED, "Wed, 15 Nov 1995 04:58:08 GMT"), new BasicHeader(Constants.HEADER_CONTENT_LOCATION, "http://foo.com/Patient/123/_history/2333"),
new BasicHeader(Constants.HEADER_CATEGORY, "http://foo/tagdefinition.html; scheme=\"http://hl7.org/fhir/tag\"; label=\"Some tag\"") };
when(myHttpResponse.getAllHeaders()).thenReturn(headers);
IGenericClient client = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
int count = 0;
Patient response = client.read().resource(Patient.class).withId(new IdDt("Patient/1234")).execute();
assertThat(response.getNameFirstRep().getFamilyAsSingleString(), StringContains.containsString("Cardinal"));
assertEquals("http://example.com/fhir/Patient/1234", capt.getAllValues().get(count++).getURI().toString());
@ -291,10 +276,9 @@ public class ETagClientTest {
}
@BeforeClass
public static void beforeClass() {
myCtx = new FhirContext();
ourCtx = new FhirContext();
}
}

View File

@ -4,7 +4,6 @@ import static org.junit.Assert.*;
import static org.mockito.Mockito.*;
import java.io.StringReader;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import org.apache.commons.io.input.ReaderInputStream;
@ -25,22 +24,23 @@ import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.dev.resource.Patient;
import ca.uhn.fhir.rest.server.Constants;
public class GenericClientTest {
private static FhirContext myCtx;
public class GenericClientTestDev {
private static FhirContext ourCtx;
private HttpClient myHttpClient;
private HttpResponse myHttpResponse;
@BeforeClass
public static void beforeClass() {
myCtx = FhirContext.forDev();
ourCtx = FhirContext.forDev();
}
@Before
public void before() {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
ourCtx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
}
@ -55,7 +55,7 @@ public class GenericClientTest {
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 = myCtx.newRestfulGenericClient("http://example.com/fhir");
IGenericClient client = ourCtx.newRestfulGenericClient("http://example.com/fhir");
//@formatter:off
Bundle response = client.search()

View File

@ -21,11 +21,11 @@ import org.mockito.Matchers;
import org.mockito.internal.stubbing.defaultanswers.ReturnsDeepStubs;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.model.dev.resource.Conformance;
import ca.uhn.fhir.model.dstu.resource.Conformance;
import ca.uhn.fhir.rest.client.exceptions.FhirClientConnectionException;
import ca.uhn.fhir.rest.server.Constants;
public class ClientServerValidationTestDstu1 {
public class ClientServerValidationTestDstu {
private FhirContext myCtx;
private HttpClient myHttpClient;
@ -36,12 +36,12 @@ public class ClientServerValidationTestDstu1 {
myHttpClient = mock(HttpClient.class, new ReturnsDeepStubs());
myHttpResponse = mock(HttpResponse.class, new ReturnsDeepStubs());
myCtx = FhirContext.forDstu1();
myCtx = FhirContext.forDev();
myCtx.getRestfulClientFactory().setHttpClient(myHttpClient);
}
@Test
public void testServerReturnsAppropriateVersion() throws Exception {
public void testServerReturnsAppropriateVersionDstu() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.4.0");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
@ -62,9 +62,9 @@ public class ClientServerValidationTestDstu1 {
}
@Test
public void testServerReturnsWrongVersion() throws Exception {
public void testServerReturnsWrongVersionDstu() throws Exception {
Conformance conf = new Conformance();
conf.setFhirVersion("0.8.0");
conf.setFhirVersion("0.0.8");
String msg = myCtx.newXmlParser().encodeResourceToString(conf);
ArgumentCaptor<HttpUriRequest> capt = ArgumentCaptor.forClass(HttpUriRequest.class);

View File

@ -560,7 +560,10 @@ public class ClientTest {
// TODO: remove the read annotation and make sure we get a sensible
// error message to tell the user why the method isn't working
ClientWithoutAnnotation client = new FhirContext().newRestfulClient(ClientWithoutAnnotation.class, "http://wildfhir.aegis.net/fhir");
FhirContext ctx = new FhirContext();
ctx.getRestfulClientFactory().setServerValidationModeEnum(ServerValidationModeEnum.NEVER);
ClientWithoutAnnotation client = ctx.newRestfulClient(ClientWithoutAnnotation.class, "http://wildfhir.aegis.net/fhir");
try {
client.read(new IdDt("8"));

View File

@ -80,7 +80,7 @@ public class TransactionClientTest {
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertEquals("http://foo/", post.getURI().toString());
assertEquals("http://foo", post.getURI().toString());
Bundle bundle = ctx.newXmlParser().parseBundle(new InputStreamReader(post.getEntity().getContent()));
ourLog.info(ctx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle));
@ -120,7 +120,7 @@ public class TransactionClientTest {
assertEquals(HttpPost.class, capt.getValue().getClass());
HttpPost post = (HttpPost) capt.getValue();
assertEquals("http://foo/", post.getURI().toString());
assertEquals("http://foo", post.getURI().toString());
Bundle bundle = ctx.newXmlParser().parseBundle(new InputStreamReader(post.getEntity().getContent()));
ourLog.info(ctx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle));

View File

@ -50,7 +50,22 @@
for instructions.
</p>
<subsection name="Introcuding the FHIR Context">
<subsection name="A Note on FHIR Versions">
<p>
Before discussing HAPI itself, a quick word about FHIR versions. FHIR
is not yet a finalized "1.0" standard. It is currently in the DSTU phase,
which means that it is changing in subtle and non-subtle ways between releases.
Before trying to use FHIR, you will need to determine which version of FHIR
you want to support in your application. Typically this would be the
latest version, but if you are looking to interact with an application which
already exists, you will probably want to implement the same version implemented
by that application.
</p>
</subsection>
<subsection name="Introducing the FHIR Context">
<p>
HAPI defines model classes for every resource type and datatype defined by the FHIR specification.
@ -61,11 +76,21 @@
<p>
We will come back to how to interact with these objects in a moment, but first
we need to see the FhirContext. The starting point to using HAPI is the
<a href="./apidocs/ca/uhn/fhir/context/FhirContext.html">FhirContext</a> object.
The following snippet shows how to create a context object, which is similar in
purpose to the
<a href="http://docs.oracle.com/javaee/5/api/javax/xml/bind/JAXBContext.html">JAXBContext</a>.
we need to create a
<a href="./apidocs/ca/uhn/fhir/context/FhirContext.html">FhirContext</a>.
FhirContext is the starting point to using HAPI, and acts as a factory for most
other parts of the API as well as a runtime cache of information that HAPI needs
to operate. Users of the JAXB API may find this class to be similar in purpose to
the
<a href="http://docs.oracle.com/javaee/5/api/javax/xml/bind/JAXBContext.html">JAXBContext</a>
class from that API.
</p>
<p>
Creating a FhirContext is as simple as instantiating one. A FhirContext instance is
specific to a given version of the FHIR specification, so it is recommended that you
use one of the factory methods indicating the FHIR version you wish to support in your
application, as shown in the following snippet:
</p>
<macro name="snippet">