Fix a few parsing issues and add multi server support to tester
This commit is contained in:
parent
4cd7ff16fb
commit
50d68d6090
|
@ -56,6 +56,10 @@
|
|||
<action type="add">
|
||||
Add support for paging responses from RESTful servers.
|
||||
</action>
|
||||
<action type="fix">
|
||||
Don't fail on narrative blocks in JSON resources with only an XML declaration but no content (these are
|
||||
produced by the Health Intersections server)
|
||||
</action>
|
||||
</release>
|
||||
</body>
|
||||
</document>
|
||||
|
|
|
@ -80,6 +80,10 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
if (!val.startsWith("<")) {
|
||||
val = "<div>" + val + "</div>";
|
||||
}
|
||||
if (val.startsWith("<?") && val.endsWith("?>")) {
|
||||
myValue = null;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
ArrayList<XMLEvent> value = new ArrayList<XMLEvent>();
|
||||
|
@ -99,7 +103,7 @@ public class XhtmlDt extends BasePrimitive<List<XMLEvent>> {
|
|||
setValue(value);
|
||||
|
||||
} catch (XMLStreamException e) {
|
||||
throw new DataFormatException("String does not appear to be valid XML/XHTML: "+e.getMessage(), e);
|
||||
throw new DataFormatException("String does not appear to be valid XML/XHTML (error is \""+e.getMessage() + "\"): " + theValue, e);
|
||||
} catch (FactoryConfigurationError e) {
|
||||
throw new ConfigurationException(e);
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import org.apache.http.client.methods.HttpRequestBase;
|
|||
import org.apache.http.message.BasicHeader;
|
||||
|
||||
import ca.uhn.fhir.rest.server.EncodingEnum;
|
||||
import ca.uhn.fhir.util.VersionUtil;
|
||||
|
||||
public abstract class BaseHttpClientInvocation {
|
||||
|
||||
|
@ -87,6 +88,11 @@ public abstract class BaseHttpClientInvocation {
|
|||
theHttpRequest.addHeader(next);
|
||||
}
|
||||
}
|
||||
|
||||
theHttpRequest.addHeader("User-Agent", "HAPI-FHIR/" + VersionUtil.getVersion() + " (FHIR Client)");
|
||||
theHttpRequest.addHeader("Accept-Charset", "utf-8");
|
||||
theHttpRequest.addHeader("Accept-Encoding", "gzip");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.Collections;
|
|||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -46,7 +47,10 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.commons.lang3.StringEscapeUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.commons.lang3.Validate;
|
||||
import org.apache.http.Header;
|
||||
import org.apache.http.HttpEntity;
|
||||
import org.apache.http.HttpEntityEnclosingRequest;
|
||||
import org.apache.http.HttpResponse;
|
||||
import org.apache.http.client.methods.HttpRequestBase;
|
||||
import org.apache.http.entity.ContentType;
|
||||
|
@ -93,7 +97,8 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
private static final String PUBLIC_TESTER_RESULT_HTML = "/PublicTesterResult.html";
|
||||
private static final long serialVersionUID = 1L;
|
||||
private FhirContext myCtx;
|
||||
private String myServerBase;
|
||||
private LinkedHashMap<String, String> myIdToServerName = new LinkedHashMap<String, String>();
|
||||
private LinkedHashMap<String, String> myIdToServerBase = new LinkedHashMap<String, String>();
|
||||
private HashMap<String, String> myStaticResources;
|
||||
|
||||
private TemplateEngine myTemplateEngine;
|
||||
|
@ -191,10 +196,15 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
myTemplateEngine.initialize();
|
||||
}
|
||||
|
||||
public void setServerBase(String theServerBase) {
|
||||
myServerBase = theServerBase;
|
||||
public void addServerBase(String theId, String theDisplayName, String theServerBase) {
|
||||
Validate.notBlank(theId, "theId can not be blank");
|
||||
Validate.notBlank(theDisplayName, "theDisplayName can not be blank");
|
||||
Validate.notBlank(theServerBase, "theServerBase can not be blank");
|
||||
myIdToServerBase.put(theId, theServerBase);
|
||||
myIdToServerName.put(theId, theDisplayName);
|
||||
}
|
||||
|
||||
|
||||
private RuntimeResourceDefinition getResourceType(HttpServletRequest theReq) throws ServletException {
|
||||
String resourceName = StringUtils.defaultString(theReq.getParameter(PARAM_RESOURCE));
|
||||
RuntimeResourceDefinition def = myCtx.getResourceDefinition(resourceName);
|
||||
|
@ -214,9 +224,9 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
RESOURCE, BUNDLE, TAGLIST, NONE
|
||||
}
|
||||
|
||||
private void processAction(HttpServletRequest theReq, WebContext theContext) {
|
||||
private void processAction(HttpServletRequest theReq, WebContext theContext, IGenericClient theClient, String theServerBase) {
|
||||
|
||||
GenericClient client = (GenericClient) myCtx.newRestfulGenericClient(myServerBase);
|
||||
GenericClient client = (GenericClient) theClient;
|
||||
client.setKeepResponses(true);
|
||||
ResultType returnsResource;
|
||||
long latency = 0;
|
||||
|
@ -285,7 +295,7 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
} else if ("page".equals(method)) {
|
||||
|
||||
String url = defaultString(theReq.getParameter("page-url"));
|
||||
if (!url.startsWith(myServerBase)) {
|
||||
if (!url.startsWith(theServerBase)) {
|
||||
theContext.getVariables().put("errorMsg", "Invalid page URL: " + url);
|
||||
return;
|
||||
}
|
||||
|
@ -453,6 +463,13 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
String resultStatus = client.getLastResponse() != null ? client.getLastResponse().getStatusLine().toString() : null;
|
||||
String resultBody = client.getLastResponseBody();
|
||||
|
||||
if (lastRequest instanceof HttpEntityEnclosingRequest) {
|
||||
HttpEntity entity = ((HttpEntityEnclosingRequest) lastRequest).getEntity();
|
||||
if (entity.isRepeatable()) {
|
||||
requestBody = IOUtils.toString(entity.getContent());
|
||||
}
|
||||
}
|
||||
|
||||
HttpResponse lastResponse = client.getLastResponse();
|
||||
ContentType ct = lastResponse != null ? ContentType.get(lastResponse.getEntity()) : null;
|
||||
String mimeType = ct != null ? ct.getMimeType() : null;
|
||||
|
@ -591,7 +608,7 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
if (nextChar == ':') {
|
||||
inValue = true;
|
||||
b.append(nextChar);
|
||||
} else if (nextChar == '[' || nextChar == '[') {
|
||||
} else if (nextChar == '[' || nextChar == '{') {
|
||||
b.append("<span class='hlControl'>");
|
||||
b.append(nextChar);
|
||||
b.append("</span>");
|
||||
|
@ -694,7 +711,18 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
return;
|
||||
}
|
||||
|
||||
IGenericClient client = myCtx.newRestfulGenericClient(myServerBase);
|
||||
String serverId = theReq.getParameter("server-id");
|
||||
String serverBase;
|
||||
String serverName;
|
||||
if (isBlank(serverId) && !myIdToServerBase.containsKey(serverId)) {
|
||||
serverBase = myIdToServerBase.entrySet().iterator().next().getValue();
|
||||
serverName = myIdToServerName.entrySet().iterator().next().getValue();
|
||||
}else {
|
||||
serverBase = myIdToServerBase.get(serverId);
|
||||
serverName = myIdToServerName.get(serverId);
|
||||
}
|
||||
|
||||
IGenericClient client = myCtx.newRestfulGenericClient(serverBase);
|
||||
Conformance conformance = client.conformance();
|
||||
|
||||
WebContext ctx = new WebContext(theReq, theResp, theReq.getServletContext(), theReq.getLocale());
|
||||
|
@ -736,16 +764,19 @@ public class RestfulTesterServlet extends HttpServlet {
|
|||
}
|
||||
}
|
||||
|
||||
ctx.setVariable("serverId", serverId);
|
||||
ctx.setVariable("resourceCounts", resourceCounts);
|
||||
ctx.setVariable("conf", conformance);
|
||||
ctx.setVariable("base", myServerBase);
|
||||
ctx.setVariable("base", serverBase);
|
||||
ctx.setVariable("baseName", serverName);
|
||||
ctx.setVariable("serverEntries", myIdToServerName.entrySet());
|
||||
String resourceName = defaultString(theReq.getParameter(PARAM_RESOURCE));
|
||||
ctx.setVariable("resourceName", resourceName);
|
||||
ctx.setVariable("jsonEncodedConf", myCtx.newJsonParser().encodeResourceToString(conformance));
|
||||
addStandardVariables(ctx, theReq.getParameterMap());
|
||||
|
||||
if (isNotBlank(theReq.getParameter("action"))) {
|
||||
processAction(theReq, ctx);
|
||||
processAction(theReq, ctx, client, serverBase);
|
||||
}
|
||||
|
||||
if (isNotBlank(resourceName)) {
|
||||
|
|
|
@ -40,6 +40,7 @@
|
|||
|
||||
<body>
|
||||
<form action="" method="get" id="outerForm">
|
||||
<input type="hidden" id="server-id" name="server-id" th:value="${serverId}"/>
|
||||
|
||||
<div class="navbar navbar-inverse navbar-fixed-top" role="navigation">
|
||||
<div class="container-fluid">
|
||||
|
@ -64,6 +65,18 @@
|
|||
</div>
|
||||
<div class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="dropdown">
|
||||
<a href="#" class="dropdown-toggle" data-toggle="dropdown">
|
||||
<span class="glyphicon glyphicon-fire" style="color: #66AAFF"/>
|
||||
<th:block th:text="'Server: ' + ${baseName}"/>
|
||||
<span class="caret" />
|
||||
</a>
|
||||
<ul class="dropdown-menu" role="menu">
|
||||
<li th:each="serverEntry : ${serverEntries}">
|
||||
<a th:href="'javascript:selectServer(\'' + ${serverEntry.key} + '\');'" th:text="${serverEntry.value}">Action</a>
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#">Help</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
@ -135,12 +148,17 @@
|
|||
}
|
||||
</script>
|
||||
|
||||
<h4>Query Mode</h4>
|
||||
<h4>Server Home</h4>
|
||||
|
||||
<ul class="nav nav-sidebar">
|
||||
<li th:class="${resourceName.empty} ? 'active' : ''">
|
||||
<a href="#" onclick="doAction(this, 'home', null);">RESTful Server</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<h4>Resources</h4>
|
||||
|
||||
<ul class="nav nav-sidebar">
|
||||
<th:block
|
||||
th:each="resource, resIterStat : ${conf.restFirstRep.resource}">
|
||||
<li th:class="${resourceName} == ${resource.type.valueAsString} ? 'active' : ''">
|
||||
|
|
|
@ -230,10 +230,10 @@ PRE.resultBodyPlaceholder {
|
|||
padding: 0px;
|
||||
}
|
||||
|
||||
SPAN.searchParamDescription {
|
||||
DIV.searchParamDescription {
|
||||
font-size: 0.8em;
|
||||
text-align: justify;
|
||||
color: #000066;
|
||||
color: #668;
|
||||
}
|
||||
|
||||
DIV.searchParamSeparator {
|
||||
|
|
|
@ -45,7 +45,7 @@ function addSearchParamRow() {
|
|||
if (restResource.searchParam) {
|
||||
for (var i = 0; i < restResource.searchParam.length; i++) {
|
||||
var searchParam = restResource.searchParam[i];
|
||||
params[searchParam.name] = searchParam;
|
||||
params['_' + searchParam.name] = searchParam;
|
||||
select.append(
|
||||
$('<option />', { value: searchParam.name }).text(searchParam.name + ' - ' + searchParam.documentation)
|
||||
);
|
||||
|
@ -79,15 +79,15 @@ function addSearchParamRow() {
|
|||
select.change(function(){ handleSearchParamTypeChange(select, params, nextRow); });
|
||||
}
|
||||
|
||||
function addSerarchControls(searchParam, searchParamName, containerRowNum, rowNum) {
|
||||
$('#search-param-rowopts-' + containerRowNum).append(
|
||||
$('<br clear="all"/>'),
|
||||
$('<div class="searchParamSeparator"/>'),
|
||||
$('<div />', { 'class': 'col-sm-6' }).append(
|
||||
$('<span class="searchParamDescription">' + searchParam.documentation + '</span>')
|
||||
)
|
||||
);
|
||||
|
||||
function addSearchControls(searchParam, searchParamName, containerRowNum, rowNum, isChild) {
|
||||
if (searchParam.childParam || isChild) {
|
||||
$('#search-param-rowopts-' + containerRowNum).append(
|
||||
$('<br clear="all"/>'),
|
||||
$('<div class="searchParamSeparator"/>'),
|
||||
$('<div />', { 'class': 'col-sm-6 searchParamDescription' }).text(searchParam.documentation)
|
||||
);
|
||||
}
|
||||
|
||||
if (searchParam.chain && searchParam.chain.length > 0) {
|
||||
$('#search-param-rowopts-' + containerRowNum).append(
|
||||
$('<input />', { name: 'param.' + rowNum + '.qualifier', type: 'hidden', value: '.' + searchParam.chain[0] })
|
||||
|
@ -167,7 +167,7 @@ function addSerarchControls(searchParam, searchParamName, containerRowNum, rowNu
|
|||
*/
|
||||
$('<input />', { name: 'param.' + rowNum + '.0.type', type: 'hidden', value: searchParam.childParam.type })
|
||||
);
|
||||
addSerarchControls(searchParam.childParam, searchParamName, containerRowNum, rowNum + '.0');
|
||||
addSearchControls(searchParam.childParam, searchParamName, containerRowNum, rowNum + '.0', true);
|
||||
}
|
||||
|
||||
|
||||
|
@ -180,16 +180,25 @@ function handleSearchParamTypeChange(select, params, rowNum) {
|
|||
return;
|
||||
}
|
||||
$('#search-param-rowopts-' + rowNum).empty();
|
||||
var searchParam = params[newVal];
|
||||
var searchParam = params['_' + newVal];
|
||||
$('#search-param-rowopts-' + rowNum).append(
|
||||
$('<input />', { name: 'param.' + rowNum + '.type', type: 'hidden', value: searchParam.type })
|
||||
);
|
||||
|
||||
addSerarchControls(searchParam, searchParam.name, rowNum, rowNum);
|
||||
addSearchControls(searchParam, searchParam.name, rowNum, rowNum, false);
|
||||
|
||||
select.prevVal = newVal;
|
||||
}
|
||||
|
||||
function selectServer(serverId) {
|
||||
$('#server-id').val(serverId);
|
||||
$('#outerForm').append(
|
||||
$('<input type="hidden" name="action" value="home"/>')
|
||||
);
|
||||
$('#outerForm').submit();
|
||||
}
|
||||
|
||||
|
||||
$( document ).ready(function() {
|
||||
addSearchParamRow();
|
||||
});
|
|
@ -25,10 +25,12 @@ import org.junit.BeforeClass;
|
|||
import org.junit.Test;
|
||||
import org.mockito.internal.matchers.Not;
|
||||
|
||||
import ca.uhn.fhir.context.ConfigurationException;
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.model.api.Bundle;
|
||||
import ca.uhn.fhir.model.api.BundleEntry;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.api.ResourceMetadataKeyEnum;
|
||||
import ca.uhn.fhir.model.api.TagList;
|
||||
import ca.uhn.fhir.model.api.annotation.Child;
|
||||
|
@ -84,6 +86,25 @@ public class JsonParserTest {
|
|||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseEmptyNarrative() throws ConfigurationException, DataFormatException, IOException {
|
||||
String text = "{\n" +
|
||||
" \"resourceType\" : \"Patient\",\n" +
|
||||
" \"extension\" : [\n" +
|
||||
" {\n" +
|
||||
" \"url\" : \"http://clairol.org/colour\",\n" +
|
||||
" \"valueCode\" : \"B\"\n" +
|
||||
" }\n" +
|
||||
" ],\n" +
|
||||
" \"text\" : {\n" +
|
||||
" \"div\" : \"<?xml version=\\\"1.0\\\" encoding=\\\"UTF-8\\\"?>\"\n" +
|
||||
" }" +
|
||||
"}";
|
||||
|
||||
IResource res = ourCtx.newJsonParser().parseResource(text);
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNestedContainedResources() {
|
||||
|
||||
|
|
|
@ -79,7 +79,6 @@ public class XmlParserTest {
|
|||
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testNestedContainedResources() {
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -88,7 +88,13 @@ public class JpaTestApp {
|
|||
RestfulTesterServlet testerServlet = new RestfulTesterServlet();
|
||||
String base = "http://localhost:" + myPort + "/fhir/context";
|
||||
// base = "http://fhir.healthintersections.com.au/open";
|
||||
testerServlet.setServerBase(base);
|
||||
// base = "http://spark.furore.com/fhir";
|
||||
|
||||
testerServlet.addServerBase("local", "Localhost Server", base);
|
||||
testerServlet.addServerBase("hi", "Health Intersections", "http://fhir.healthintersections.com.au/open");
|
||||
testerServlet.addServerBase("furore", "Spark - Furore Reference Server", "http://spark.furore.com/fhir");
|
||||
testerServlet.addServerBase("blaze", "Blaze (Orion Health)", "https://his-medicomp-gateway.orionhealth.com/blaze/fhir");
|
||||
|
||||
ServletHolder handler = new ServletHolder();
|
||||
handler.setName("Tester");
|
||||
handler.setServlet(testerServlet);
|
||||
|
|
Loading…
Reference in New Issue