Make resource detection kind of case insensitive (to deal with some healthintersections responses)

This commit is contained in:
jamesagnew 2014-06-20 16:54:09 -04:00
parent f4b8f18a8a
commit 4d90955e75
11 changed files with 520 additions and 29 deletions

View File

@ -28,6 +28,7 @@ import java.util.List;
import java.util.Map;
import org.apache.commons.lang3.Validate;
import org.apache.commons.lang3.text.WordUtils;
import ca.uhn.fhir.model.api.IElement;
import ca.uhn.fhir.model.api.IResource;
@ -123,13 +124,24 @@ public class FhirContext {
*/
@SuppressWarnings("unchecked")
public RuntimeResourceDefinition getResourceDefinition(String theResourceName) {
Validate.notBlank(theResourceName, "Resource name must not be blank");
String resourceName = theResourceName;
/*
* TODO: this is a bit of a hack, really we should have a translation table
* based on a property file or something so that we can detect names like
* diagnosticreport
*/
if (Character.isLowerCase(resourceName.charAt(0))) {
resourceName = WordUtils.capitalize(resourceName);
}
Validate.notBlank(resourceName, "Resource name must not be blank");
RuntimeResourceDefinition retVal = myNameToElementDefinition.get(theResourceName);
RuntimeResourceDefinition retVal = myNameToElementDefinition.get(resourceName);
if (retVal == null) {
try {
String candidateName = Patient.class.getPackage().getName() + "." + theResourceName;
String candidateName = Patient.class.getPackage().getName() + "." + resourceName;
Class<?> clazz = Class.forName(candidateName);
if (IResource.class.isAssignableFrom(clazz)) {
retVal = scanResourceType((Class<? extends IResource>) clazz);

View File

@ -129,7 +129,12 @@ class ParserState<T> {
IResource resource = entry.getResource();
if (resource == null && id != null && isNotBlank(id.getResourceType())) {
resource = myContext.getResourceDefinition(id.getResourceType()).newInstance();
String resourceType = id.getResourceType();
RuntimeResourceDefinition def = myContext.getResourceDefinition(resourceType);
if (def == null) {
throw new DataFormatException("Entry references unknown resource type: " + resourceType);
}
resource = def.newInstance();
resource.setId(id);
entry.setResource(resource);
}

View File

@ -61,6 +61,7 @@ import org.thymeleaf.templateresolver.TemplateResolver;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.context.RuntimeResourceDefinition;
import ca.uhn.fhir.context.RuntimeSearchParam;
import ca.uhn.fhir.model.api.Bundle;
import ca.uhn.fhir.model.api.ExtensionDt;
import ca.uhn.fhir.model.api.IResource;
import ca.uhn.fhir.model.api.Include;
@ -193,7 +194,7 @@ public class RestfulTesterServlet extends HttpServlet {
}
if ("xml".equals(theReq.getParameter("encoding"))) {
client.setEncoding(EncodingEnum.XML);
} else if ("json".equals(theReq.getParameter("configEncoding"))) {
} else if ("json".equals(theReq.getParameter("encoding"))) {
client.setEncoding(EncodingEnum.JSON);
}
@ -370,6 +371,12 @@ public class RestfulTesterServlet extends HttpServlet {
}
}
// if ("xml".equals(theReq.getParameter("encoding"))) {
// query.encodedXml();
// }else if ("json".equals(theReq.getParameter("encoding"))) {
// query.encodedJson();
// }
query.where(new StringParam(nextName).matches().value(paramValue));
}
@ -454,19 +461,22 @@ public class RestfulTesterServlet extends HttpServlet {
EncodingEnum ctEnum = EncodingEnum.forContentType(mimeType);
String narrativeString = "";
String resultDescription;
StringBuilder resultDescription=new StringBuilder();
Bundle bundle = null;
if (ctEnum == null) {
resultSyntaxHighlighterClass = "brush: plain";
resultDescription = "Non-FHIR response";
resultDescription.append("Non-FHIR response");
} else {
switch (ctEnum) {
case JSON:
resultSyntaxHighlighterClass = "brush: jscript";
if (returnsResource) {
narrativeString = parseNarrative(ctEnum, resultBody);
resultDescription = "JSON encoded resource";
resultDescription.append( "JSON resource");
} else {
resultDescription = "JSON encoded bundle";
resultDescription.append( "JSON bundle");
bundle = myCtx.newJsonParser().parseBundle(resultBody);
}
break;
case XML:
@ -474,20 +484,24 @@ public class RestfulTesterServlet extends HttpServlet {
resultSyntaxHighlighterClass = "brush: xml";
if (returnsResource) {
narrativeString = parseNarrative(ctEnum, resultBody);
resultDescription = "XML encoded resource";
resultDescription.append( "XML resource");
} else {
resultDescription = "XML encoded bundle";
resultDescription.append( "XML bundle");
bundle = myCtx.newXmlParser().parseBundle(resultBody);
}
break;
}
}
resultDescription.append(" (").append(resultBody.length() + " bytes)");
Header[] requestHeaders = lastRequest != null ? applyHeaderFilters(lastRequest.getAllHeaders()) : new Header[0];
Header[] responseHeaders = lastResponse != null ? applyHeaderFilters(lastResponse.getAllHeaders()) : new Header[0];
theContext.setVariable("outcomeDescription", outcomeDescription);
theContext.setVariable("resultDescription", resultDescription);
theContext.setVariable("resultDescription", resultDescription.toString());
theContext.setVariable("action", action);
theContext.setVariable("bundle", bundle);
theContext.setVariable("resultStatus", resultStatus);
theContext.setVariable("requestUrl", requestUrl);
requestBody = StringEscapeUtils.escapeHtml4(requestBody);
@ -515,7 +529,7 @@ public class RestfulTesterServlet extends HttpServlet {
}
try {
ourLog.info("RequestURI: {}", theReq.getPathInfo());
ourLog.trace("RequestURI: {}", theReq.getPathInfo());
String resName = theReq.getPathInfo().substring(1);
if (myStaticResources.containsKey(resName)) {

View File

@ -866,7 +866,7 @@
<th:block th:text="${latencyMs} + 'ms'"/>
</div>
<table class="table table-bordered table-striped" id="requestTable">
<table class="table table-bordered table-striped requestTable" id="requestTable">
<colgroup>
<col class="col-xs-1" />
<col class="col-xs-7" />
@ -895,13 +895,13 @@
<td>Request Body</td>
<td valign="top" style="margin: 0px; padding: 0px;">
<pre class="requestBodyPre resultBodyPlaceholder" id="requestBodyPlaceholder">...loading...</pre>
<pre th:text="${requestBody}" th:class="${requestSyntaxHighlighterClass} + ' resultBodyPre pre-scrollable'" id="requestBodyActual" style="display: none;">{}</pre>
<pre th:text="${requestBody}" th:class="${requestSyntaxHighlighterClass} + ' resultBodyPre pre'" id="requestBodyActual" style="display: none;">{}</pre>
</td>
</tr>
</tbody>
</table>
<table class="table table-bordered table-striped" id="resultTable">
<table class="table table-bordered table-striped resultTable" id="resultTable">
<colgroup>
<col class="col-xs-1" />
<col class="col-xs-7" />
@ -924,9 +924,11 @@
</td>
</tr>
<tr th:if="${!#strings.isEmpty(resultBody)}">
<td rowspan="2">Result Body</td>
<td rowspan="2">
Result Body
<small th:text="${resultDescription}" style="font-weight: normal;"/>
</td>
<td>
<span th:text="${resultDescription}"/>
<button th:if="${resultBodyIsLong}" class="btn btn-info btn-sm" type="button" id="format-result-btn">
<span class="glyphicon glyphicon-eye-open"></span>
Colour
@ -937,15 +939,30 @@
document.getElementById('resultBodyActualPre').className='<th:block th:text="${resultSyntaxHighlighterClass}"/>';
document.getElementById('format-result-btn').disabled ='disabled';
SyntaxHighlighter.highlight();
lineWrap();
});
</script>
<th:block th:if="${bundle} != null and ${!bundle.linkNext.empty}">
<button class="btn btn-success btn-sm" type="button" id="page-next-btn" name="action" value="page">
<span class="glyphicon glyphicon-step-forward"></span>
Next Page
</button>
<script type="text/javascript" th:if="${resultBodyIsLong}">
$('#page-next-btn').click(function() {
var btn = $(this);
btn.button('loading');
btn.append($('<input />', { type: 'hidden', name: 'pageUrl', value: '<th:block th:text=""/>' }));
});
</script>
</th:block>
</td>
</tr>
<tr th:if="${!#strings.isEmpty(resultBody)}">
<td valign="top" style="margin: 0px; padding: 0px;">
<td valign="top" style="margin: 0px; padding: 0px; font-weight: normal;">
<pre class="resultBodyPre resultBodyPlaceholder" id="resultBodyPlaceholder">...loading...</pre>
<div id="resultBodyActual" class="resultBodyActual" style="display: none;">
<pre id="resultBodyActualPre" th:text="${resultBody}" th:class="(${resultBodyIsLong} ? '' : ${resultSyntaxHighlighterClass}) + ' resultBodyPre pre-scrollable'">{}</pre>
<pre id="resultBodyActualPre" th:text="${resultBody}" th:class="(${resultBodyIsLong} ? '' : ${resultSyntaxHighlighterClass}) + ' resultBodyPre pre'">{}</pre>
</div>
</td>
</tr>
@ -956,12 +973,12 @@
</tbody>
</table>
<script type="text/javascript">
<script type="text/javascript"><!--
$( document ).ready(function() {
var reswidth = $('#resultBodyPlaceholder').width();
var reswidth = $('#resultBodyPlaceholder').outerWidth(true);
var reqwidth = 0;
if ($('#requestBodyPlaceholder') != null) {
reqwidth = $('#requestBodyPlaceholder').width();
reqwidth = $('#requestBodyPlaceholder').outerWidth(true);
}
SyntaxHighlighter.all();
@ -976,7 +993,36 @@
$('#requestBodyActual').show();
}
});
</script>
function lineWrap(){
var wrap = function () {
var elems = document.getElementsByClassName('syntaxhighlighter');
for (var j = 0; j < elems.length; ++j) {
var sh = elems[j];
var gLines = sh.getElementsByClassName('gutter')[0].getElementsByClassName('line');
var cLines = sh.getElementsByClassName('code')[0].getElementsByClassName('line');
var stand = 15;
for (var i = 0; i < gLines.length; ++i) {
var h = $(cLines[i]).height();
if (h != stand) {
console.log(i);
gLines[i].setAttribute('style', 'height: ' + h + 'px !important;');
}
}
}
};
var whenReady = function () {
if ($('.syntaxhighlighter').length === 0) {
setTimeout(whenReady, 800);
} else {
wrap();
}
};
whenReady();
};
lineWrap();
$(window).resize(function(){lineWrap()});
--></script>
</div>

View File

@ -5,6 +5,7 @@
/* Move down content because we have a fixed navbar that is 50px tall */
body {
padding-top: 50px;
overflow-x: hidden;
}
label {
@ -83,8 +84,10 @@ DIV.navbarBreadcrumb:HOVER, A.navbarBreadcrumb:HOVER {
}
DIV.resultBodyActual {
/*
max-height: 400px;
overflow: scroll;
*/
}
PRE.resultBodyPre {
@ -92,6 +95,7 @@ PRE.resultBodyPre {
font-size: 0.8em;
border: none;
background-color: transparent;
overflow: visible;
}
/*
@ -103,6 +107,13 @@ PRE.resultBodyPre {
border-bottom: 1px solid #eee;
}
body .syntaxhighlighter .line {
white-space: pre-wrap !important; /* make code wrap */
}
.syntaxhighlight {
white-space: pre-wrap;
}
/*
* Sidebar
@ -185,6 +196,11 @@ PRE.resultBodyPre {
border-radius: 50%;
}
TABLE.resultTable TR TD:FIRST-CHILD,
TABLE.requestTable TR TD:FIRST-CHILD {
font-weight: bold;
}
PRE.resultBodyPlaceholder {
width:100%;
padding: 0px;
@ -204,8 +220,12 @@ PRE.resultBodyPlaceholder {
background-color: transparent !important;
}
.syntaxhighlighter {
overflow: visible !important;
}
.syntaxhighlighter div {
font-size: 0.9em !important;
font-size: 0.9em !important;
}
DIV.top-buffer {

View File

@ -592,6 +592,27 @@ public class JsonParserTest {
}
@Test
public void testParseBundleFromHI() throws DataFormatException, IOException {
String msg = IOUtils.toString(XmlParser.class.getResourceAsStream("/bundle.json"));
IParser p = ourCtx.newJsonParser();
Bundle bundle = p.parseBundle(msg);
String encoded = ourCtx.newXmlParser().setPrettyPrint(true).encodeBundleToString(bundle);
ourLog.info(encoded);
BundleEntry entry = bundle.getEntries().get(0);
Patient res = (Patient) entry.getResource();
assertEquals("444111234", res.getIdentifierFirstRep().getValue().getValue());
BundleEntry deletedEntry = bundle.getEntries().get(3);
assertEquals("2014-06-20T20:15:49Z", deletedEntry.getDeletedAt().getValueAsString());
}
/**
* This sample has extra elements in <searchParam> that are not actually a part of the spec any more..
*/

View File

@ -0,0 +1,370 @@
{
"resourceType" : "Bundle",
"title" : "History for Patient",
"id" : "urn:uuid:a0d5d4cd-387c-46c4-89f9-4b3060237f",
"link" : [
{
"href" : "http://fhir.healthintersections.com.au/open/",
"rel" : "fhir-base"
},
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740",
"rel" : "self"
},
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740&search-offset=0&_count=5",
"rel" : "first"
},
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740&search-offset=5&_count=5",
"rel" : "next"
},
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/_history?_prior=2014-06-20T20:22:09Z&_format=application/json+fhir&history-id=55eb80eb-ded2-434b-ae49-fe24f45740&search-offset=1775&_count=5",
"rel" : "last"
}
],
"updated" : "2014-06-20T20:22:09Z",
"totalResults" : "1779",
"entry" : [
{
"title" : "Patient \"84239339\" Version \"2\"",
"id" : "http://fhir.healthintersections.com.au/open/Patient/84239339",
"link" : [
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/84239339/_history/2",
"rel" : "self"
}
],
"updated" : "2014-06-20T20:18:52Z",
"author" : [
{
"name" : "199.71.174.200"
}
],
"published" : "2014-06-20T20:22:09Z",
"content" : {
"resourceType" : "Patient",
"text" : {
"status" : "generated",
"div" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear, Neville_test SSN:&#x0A; 444111234</div>"
},
"identifier" : [
{
"label" : "SSN",
"system" : "http://hl7.org/fhir/sid/us-ssn",
"value" : "444111234"
}
],
"name" : [
{
"use" : "official",
"family" : [
"Nuclear"
],
"given" : [
"Neville_test"
]
}
],
"telecom" : [
{
"system" : "phone",
"value" : "555-555-5001",
"use" : "work"
}
],
"gender" : {
"coding" : [
{
"system" : "http://hl7.org/fhir/v3/AdministrativeGender",
"code" : "M"
}
]
},
"address" : [
{
"use" : "home",
"line" : [
"6666 Home Street"
]
}
],
"managingOrganization" : {
"reference" : "Organization/hl7"
},
"active" : true
},
"summary" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear, Neville_test SSN:&#x0A; 444111234</div>"
},
{
"title" : "Patient \"84239340\" Version \"1\"",
"id" : "http://fhir.healthintersections.com.au/open/Patient/84239340",
"link" : [
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/84239340/_history/1",
"rel" : "self"
}
],
"updated" : "2014-06-20T20:18:16Z",
"author" : [
{
"name" : "199.71.174.200"
}
],
"published" : "2014-06-20T20:22:09Z",
"content" : {
"resourceType" : "Patient",
"text" : {
"status" : "generated",
"div" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear, Neville_test SSN:&#x0A; 444111234</div>"
},
"identifier" : [
{
"label" : "SSN",
"system" : "http://hl7.org/fhir/sid/us-ssn",
"value" : "444111234"
}
],
"name" : [
{
"use" : "official",
"family" : [
"Nuclear"
],
"given" : [
"Neville_test"
]
}
],
"telecom" : [
{
"system" : "phone",
"value" : "555-555-5001",
"use" : "work"
}
],
"gender" : {
"coding" : [
{
"system" : "http://hl7.org/fhir/v3/AdministrativeGender",
"code" : "M"
}
]
},
"address" : [
{
"use" : "home",
"line" : [
"6666 Home Street"
]
}
],
"managingOrganization" : {
"reference" : "Organization/hl7"
},
"active" : true
},
"summary" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear, Neville_test SSN:&#x0A; 444111234</div>"
},
{
"title" : "Patient \"84239339\" Version \"1\"",
"id" : "http://fhir.healthintersections.com.au/open/Patient/84239339",
"link" : [
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/84239339/_history/1",
"rel" : "self"
}
],
"updated" : "2014-06-20T20:17:41Z",
"author" : [
{
"name" : "199.71.174.200"
}
],
"published" : "2014-06-20T20:22:09Z",
"content" : {
"resourceType" : "Patient",
"text" : {
"status" : "generated",
"div" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear, Neville_test SSN:&#x0A; 444111234</div>"
},
"identifier" : [
{
"label" : "SSN",
"system" : "http://hl7.org/fhir/sid/us-ssn",
"value" : "444111234"
}
],
"name" : [
{
"use" : "official",
"family" : [
"Nuclear"
],
"given" : [
"Neville_test"
]
}
],
"telecom" : [
{
"system" : "phone",
"value" : "555-555-5001",
"use" : "work"
}
],
"gender" : {
"coding" : [
{
"system" : "http://hl7.org/fhir/v3/AdministrativeGender",
"code" : "M"
}
]
},
"address" : [
{
"use" : "home",
"line" : [
"6666 Home Street"
]
}
],
"managingOrganization" : {
"reference" : "Organization/hl7"
},
"active" : true
},
"summary" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear, Neville_test SSN:&#x0A; 444111234</div>"
},
{
"deleted" : "2014-06-20T20:15:49Z",
"id" : "http://fhir.healthintersections.com.au/open/84239337",
"link" : [
{
"href" : "http://fhir.healthintersections.com.au/open/patient/84239337/_history/2",
"rel" : "self"
}
],
"author" : [
{
"name" : "199.71.174.200"
}
]
},
{
"title" : "Patient \"84239338\" Version \"1\"",
"id" : "http://fhir.healthintersections.com.au/open/Patient/84239338",
"link" : [
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/84239338/_history/1",
"rel" : "self"
}
],
"updated" : "2014-06-20T19:53:53Z",
"author" : [
{
"name" : "199.212.7.70"
}
],
"category" : [
{
"scheme" : "http://hl7.org/fhir/tag",
"term" : "urn:happytag",
"label" : "This is a happy resource"
}
],
"published" : "2014-06-20T20:22:09Z",
"content" : {
"resourceType" : "Patient",
"identifier" : [
{
"system" : "foo:bar",
"value" : "12345"
}
],
"name" : [
{
"family" : [
"Smith"
],
"given" : [
"John"
]
}
]
},
"summary" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">--No Summary for this resource--</div>"
},
{
"title" : "Patient \"84239337\" Version \"1\"",
"id" : "http://fhir.healthintersections.com.au/open/Patient/84239337",
"link" : [
{
"href" : "http://fhir.healthintersections.com.au/open/Patient/84239337/_history/1",
"rel" : "self"
}
],
"updated" : "2014-06-20T14:31:09Z",
"author" : [
{
"name" : "199.71.174.200"
}
],
"published" : "2014-06-20T20:22:09Z",
"content" : {
"resourceType" : "Patient",
"text" : {
"status" : "generated",
"div" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear1, Neville1. SSN:&#x0A; 444111234</div>"
},
"identifier" : [
{
"label" : "SSN",
"system" : "http://hl7.org/fhir/sid/us-ssn",
"value" : "444111234"
}
],
"name" : [
{
"use" : "official",
"family" : [
"Nuclear1"
],
"given" : [
"Neville1"
]
}
],
"telecom" : [
{
"system" : "phone",
"value" : "555-555-5001",
"use" : "work"
}
],
"gender" : {
"coding" : [
{
"system" : "http://hl7.org/fhir/v3/AdministrativeGender",
"code" : "M"
}
]
},
"address" : [
{
"use" : "home",
"line" : [
"6666 Home Street"
]
}
],
"managingOrganization" : {
"reference" : "Organization/hl7"
},
"active" : true
},
"summary" : "<?xml version=\"1.0\" encoding=\"UTF-8\"?><div xmlns=\"http://www.w3.org/1999/xhtml\">Nuclear1, Neville1. SSN:&#x0A; 444111234</div>"
}
]
}

View File

@ -1,5 +1,4 @@
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding//src/test/java/ca/uhn/fhir/jpa/test/Upload.java=UTF-8

View File

@ -68,7 +68,7 @@ public class JpaTestApp {
RestfulTesterServlet testerServlet = new RestfulTesterServlet();
String base = "http://localhost:" + myPort + "/fhir/context";
// base = "http://fhir.healthintersections.com.au/open";
base = "http://fhir.healthintersections.com.au/open";
testerServlet.setServerBase(base);
ServletHolder handler = new ServletHolder();
handler.setName("Tester");

View File

@ -6,6 +6,7 @@ import java.util.Collection;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
import ca.uhn.fhir.jpa.provider.JpaConformanceProvider;
import ca.uhn.fhir.jpa.provider.JpaSystemProvider;
import ca.uhn.fhir.rest.server.IResourceProvider;
import ca.uhn.fhir.rest.server.RestfulServer;
@ -40,6 +41,9 @@ public class TestRestfulServer extends RestfulServer {
JpaSystemProvider sp = new JpaSystemProvider(systemDao);
setPlainProviders(sp);
JpaConformanceProvider confProvider = new JpaConformanceProvider(this, systemDao);
setServerConformanceProvider(confProvider);
setUseBrowserFriendlyContentTypes(true);
}

View File

@ -1,8 +1,8 @@
package ca.uhn.fhirtest;
import ca.uhn.fhir.rest.server.tester.RestfulServerTesterServlet;
import ca.uhn.fhir.rest.server.tester.RestfulTesterServlet;
public class TesterServlet extends RestfulServerTesterServlet {
public class TesterServlet extends RestfulTesterServlet {
private static final long serialVersionUID = 1L;