Start with sample code in tester UI
This commit is contained in:
parent
1346802403
commit
0a7f7d0390
|
@ -23,10 +23,8 @@ package ca.uhn.fhir.rest.server.provider;
|
|||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeSet;
|
||||
|
||||
|
@ -34,8 +32,6 @@ import org.apache.commons.lang3.StringUtils;
|
|||
|
||||
import ca.uhn.fhir.context.RuntimeResourceDefinition;
|
||||
import ca.uhn.fhir.context.RuntimeSearchParam;
|
||||
import ca.uhn.fhir.model.api.ExtensionDt;
|
||||
import ca.uhn.fhir.model.api.IResource;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance.Rest;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance.RestQuery;
|
||||
|
@ -104,7 +100,7 @@ public class ServerConformanceProvider {
|
|||
String resourceName = next.getResourceName();
|
||||
RuntimeResourceDefinition def = myRestfulServer.getFhirContext().getResourceDefinition(resourceName);
|
||||
resource.getType().setValue(def.getName());
|
||||
resource.getProfile().setId(new IdDt(def.getResourceProfile()));
|
||||
resource.getProfile().setReference(new IdDt(def.getResourceProfile()));
|
||||
|
||||
TreeSet<String> includes = new TreeSet<String>();
|
||||
|
||||
|
@ -160,6 +156,9 @@ public class ServerConformanceProvider {
|
|||
query = rest.addQuery();
|
||||
query.getDocumentation().setValue(searchMethodBinding.getDescription());
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
for (SearchParameter nextParameter : searchParameters) {
|
||||
|
|
|
@ -36,5 +36,7 @@ public class ExtensionConstants {
|
|||
public static final String CONF_ADDITIONAL_PARAM_REQUIRED = "http://hl7api.sourceforge.net/hapi-fhir/extensions.xml#additionalParamRequired";
|
||||
|
||||
public static final String CONF_RESOURCE_COUNT = "http://hl7api.sourceforge.net/hapi-fhir/res/extdefs.html#resourceCount";
|
||||
|
||||
public static final String QUERY_ALLOWED_INCLUDE = "http://hl7api.sourceforge.net/hapi-fhir/res/extdefs.html#allowedInclude";
|
||||
|
||||
}
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package ca.uhn.fhir.jpa.provider;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Map;
|
||||
|
||||
import ca.uhn.fhir.jpa.dao.IDaoListener;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirResourceDao;
|
||||
import ca.uhn.fhir.jpa.dao.IFhirSystemDao;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance;
|
||||
import ca.uhn.fhir.model.dstu.resource.Conformance.Rest;
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
<dependent-module archiveName="hapi-fhir-base-0.4-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
|
||||
<dependency-type>uses</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-testpage-overlay?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/prj/hapi-fhir-tester-overlay?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
<dependency-type>consumes</dependency-type>
|
||||
</dependent-module>
|
||||
<dependent-module deploy-path="/" handle="module:/overlay/slf/?includes=**/**&excludes=META-INF/MANIFEST.MF">
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<value>home , UHN/HAPI Server , http://fhirtest.uhn.ca/base</value>
|
||||
<value>hi , Health Intersections , http://fhir.healthintersections.com.au/open</value>
|
||||
<value>furore , Spark - Furore Reference Server , http://spark.furore.com/fhir</value>
|
||||
<value>blaze , Blaze (Orion Health) , https://fhir.orionhealth.com</value>
|
||||
<value>blaze , Blaze (Orion Health) , https://fhir.orionhealth.com/blaze/fhir</value>
|
||||
<value>oridashi , Oridashi , http://demo.oridashi.com.au:8190</value>
|
||||
<value>fhirbase , FHIRPlace (Health Samurai) , http://try-fhirplace.hospital-systems.com/ </value>
|
||||
</list>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<classpath>
|
||||
<classpathentry excluding="**/moment*.*" kind="src" path="src/main/webapp"/>
|
||||
<classpathentry excluding="**/moment*.*" kind="src" path="target/m2e-wtp/web-resources"/>
|
||||
<classpathentry excluding="**/*.svg|**/moment*.*" including="js/RestfulTester.js" kind="src" path="src/main/webapp"/>
|
||||
<classpathentry excluding="**/*.svg|**/moment*.*" kind="src" path="target/m2e-wtp/web-resources"/>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.JRE_CONTAINER"/>
|
||||
<classpathentry kind="con" path="org.eclipse.wst.jsdt.launching.WebProject">
|
||||
<attributes>
|
||||
|
|
|
@ -1,13 +1 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId" project-version="1.5.0">
|
||||
<wb-module deploy-name="hapi-fhir-tester-overlay">
|
||||
<wb-resource deploy-path="/" source-path="/target/m2e-wtp/web-resources"/>
|
||||
<wb-resource deploy-path="/" source-path="/src/main/webapp" tag="defaultRootSource"/>
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/main/java"/>
|
||||
<wb-resource deploy-path="/WEB-INF/classes" source-path="/src/test/resources"/>
|
||||
<dependent-module archiveName="hapi-fhir-base-0.4-SNAPSHOT.jar" deploy-path="/WEB-INF/lib" handle="module:/resource/hapi-fhir-base/hapi-fhir-base">
|
||||
<dependency-type>uses</dependency-type>
|
||||
</dependent-module>
|
||||
<property name="java-output-path" value="/hapi-fhir-tester-overlay/target/classes"/>
|
||||
<property name="context-root" value="hapi-fhir-testpage-overlay"/>
|
||||
</wb-module>
|
||||
</project-modules>
|
||||
<?xml version="1.0" encoding="UTF-8"?><project-modules id="moduleCoreId"/>
|
||||
|
|
|
@ -2,6 +2,7 @@ package ca.uhn.fhir.to;
|
|||
|
||||
import static org.apache.commons.lang3.StringUtils.*;
|
||||
|
||||
import java.io.StringWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
@ -10,6 +11,9 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.TreeSet;
|
||||
|
||||
import javax.json.Json;
|
||||
import javax.json.JsonWriter;
|
||||
import javax.json.stream.JsonGenerator;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
|
@ -134,7 +138,7 @@ public class Controller {
|
|||
try {
|
||||
client.delete(def.getImplementingClass(), new IdDt(id));
|
||||
} catch (Exception e) {
|
||||
returnsResource = handleClientException(client,e, theModel);
|
||||
returnsResource = handleClientException(client, e, theModel);
|
||||
}
|
||||
long delay = System.currentTimeMillis() - start;
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
|
@ -146,11 +150,11 @@ public class Controller {
|
|||
ResultType returnsResource;
|
||||
returnsResource = ResultType.NONE;
|
||||
ourLog.warn("Failed to invoke server", e);
|
||||
|
||||
|
||||
if (theClient.getLastResponse() == null) {
|
||||
theModel.put("errorMsg", "Error: " + e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
return returnsResource;
|
||||
}
|
||||
|
||||
|
@ -293,7 +297,7 @@ public class Controller {
|
|||
|
||||
@RequestMapping({ "/resource" })
|
||||
public String actionResource(final ResourceRequest theRequest, final BindingResult theBindingResult, final ModelMap theModel) {
|
||||
Conformance conformance = addCommonParams(theRequest, theModel);
|
||||
Conformance conformance = addCommonParams(theRequest, theModel);
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
|
||||
|
@ -303,6 +307,7 @@ public class Controller {
|
|||
TreeSet<String> includes = new TreeSet<String>();
|
||||
List<RestQuery> queries = new ArrayList<Conformance.RestQuery>();
|
||||
boolean haveSearchParams = false;
|
||||
List<List<String>> queryIncludes = new ArrayList<List<String>>();
|
||||
for (Rest nextRest : conformance.getRest()) {
|
||||
for (RestResource nextRes : nextRest.getResource()) {
|
||||
if (nextRes.getType().getValue().equals(resourceName)) {
|
||||
|
@ -317,11 +322,25 @@ public class Controller {
|
|||
}
|
||||
}
|
||||
for (RestQuery nextQuery : nextRest.getQuery()) {
|
||||
boolean queryMatchesResource = false;
|
||||
List<ExtensionDt> returnTypeExt = nextQuery.getUndeclaredExtensionsByUrl(ExtensionConstants.QUERY_RETURN_TYPE);
|
||||
if (returnTypeExt != null) {
|
||||
for (ExtensionDt nextExt : returnTypeExt) {
|
||||
if (resourceName.equals(nextExt.getValueAsPrimitive().getValueAsString())) {
|
||||
queries.add(nextQuery);
|
||||
queryMatchesResource = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (queryMatchesResource) {
|
||||
ArrayList<String> nextQueryIncludes = new ArrayList<String>();
|
||||
queryIncludes.add(nextQueryIncludes);
|
||||
List<ExtensionDt> includesExt = nextQuery.getUndeclaredExtensionsByUrl(ExtensionConstants.QUERY_ALLOWED_INCLUDE);
|
||||
if (includesExt != null) {
|
||||
for (ExtensionDt nextExt : includesExt) {
|
||||
nextQueryIncludes.add(nextExt.getValueAsPrimitive().getValueAsString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -330,6 +349,7 @@ public class Controller {
|
|||
theModel.put("includes", includes);
|
||||
theModel.put("queries", queries);
|
||||
theModel.put("haveSearchParams", haveSearchParams);
|
||||
theModel.put("queryIncludes", queryIncludes);
|
||||
|
||||
if (isNotBlank(theRequest.getUpdateId())) {
|
||||
String updateId = theRequest.getUpdateId();
|
||||
|
@ -347,6 +367,12 @@ public class Controller {
|
|||
public String actionSearch(HttpServletRequest theReq, HomeRequest theRequest, BindingResult theBindingResult, ModelMap theModel) {
|
||||
addCommonParams(theRequest, theModel);
|
||||
|
||||
StringWriter clientCodeJsonStringWriter = new StringWriter();
|
||||
JsonGenerator clientCodeJsonWriter = Json.createGenerator(clientCodeJsonStringWriter);
|
||||
clientCodeJsonWriter.writeStartObject();
|
||||
clientCodeJsonWriter.write("action", "search");
|
||||
clientCodeJsonWriter.write("base", (String)theModel.get("base"));
|
||||
|
||||
GenericClient client = theRequest.newClient(myCtx, myConfig);
|
||||
|
||||
IUntypedQuery search = client.search();
|
||||
|
@ -358,9 +384,12 @@ public class Controller {
|
|||
theModel.put("errorMsg", e.toString());
|
||||
return "resource";
|
||||
}
|
||||
clientCodeJsonWriter.write("resource", theReq.getParameter("resource"));
|
||||
} else {
|
||||
query = search.forAllResources();
|
||||
clientCodeJsonWriter.writeNull("resource");
|
||||
}
|
||||
|
||||
|
||||
String outcomeDescription = "Search for Resources";
|
||||
|
||||
|
@ -405,6 +434,11 @@ public class Controller {
|
|||
|
||||
processAndAddLastClientInvocation(client, returnsResource, theModel, delay, outcomeDescription);
|
||||
|
||||
clientCodeJsonWriter.writeEnd();
|
||||
clientCodeJsonWriter.close();
|
||||
String clientCodeJson = clientCodeJsonStringWriter.toString();
|
||||
theModel.put("clientCodeJson", clientCodeJson);
|
||||
|
||||
return "result";
|
||||
}
|
||||
|
||||
|
@ -696,7 +730,7 @@ public class Controller {
|
|||
|
||||
StringBuilder b = new StringBuilder();
|
||||
b.append("<span class='hlUrlBase'>");
|
||||
|
||||
|
||||
boolean inParams = false;
|
||||
for (int i = 0; i < str.length(); i++) {
|
||||
char nextChar = str.charAt(i);
|
||||
|
@ -779,7 +813,7 @@ public class Controller {
|
|||
|
||||
private Conformance loadAndAddConf(final HomeRequest theRequest, final ModelMap theModel) {
|
||||
IGenericClient client = myCtx.newRestfulGenericClient(theRequest.getServerBase(myConfig));
|
||||
|
||||
|
||||
Conformance conformance;
|
||||
try {
|
||||
conformance = client.conformance();
|
||||
|
|
|
@ -102,7 +102,7 @@
|
|||
$('#search-btn').click(function() {
|
||||
var btn = $(this);
|
||||
btn.button('loading');
|
||||
var sd = $('#tab-search').find('input').each(function() {
|
||||
$('#tab-search').find('input').each(function() {
|
||||
if (this.id) {
|
||||
if (this.id.substring(0,4) == 'inc_') {
|
||||
this.name = '_include';
|
||||
|
|
|
@ -22,13 +22,31 @@
|
|||
<!-- *************************************************** -->
|
||||
<!-- ** Response ** -->
|
||||
<!-- *************************************************** -->
|
||||
<div class="well" id="resultWell">
|
||||
Executed request against FHIR RESTful server in
|
||||
<th:block th:text="${latencyMs} + 'ms'"/>
|
||||
</div>
|
||||
|
||||
<div th:if="${requestUrl} != null">
|
||||
|
||||
<div class="well" id="resultWell">
|
||||
Executed request against FHIR RESTful server in
|
||||
<th:block th:text="${latencyMs} + 'ms'"/>
|
||||
<!--
|
||||
<div th:if="${clientCodeJson} != null" class="panel panel-default">
|
||||
<div class="panel-heading">
|
||||
Client Code -
|
||||
<small style="color: #888;">
|
||||
Use the following code snippet to execute this action in your
|
||||
own client.
|
||||
</small>
|
||||
</div>
|
||||
<div class="panel-body clientCodeBox" id="clientCodeBody">
|
||||
</div>
|
||||
<script type="text/javascript" src="js/ClientCodeGeneratorHapi.js"></script>
|
||||
<script type="text/javascript">
|
||||
var jsonClientCode = <th:block th:utext="${clientCodeJson}"/>;
|
||||
generateHapi(jsonClientCode, $('#clientCodeBody'));
|
||||
</script>
|
||||
</div>
|
||||
-->
|
||||
|
||||
<div th:if="${requestUrl} != null">
|
||||
|
||||
<table class="table table-bordered table-striped requestTable" id="requestTable">
|
||||
<colgroup>
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
<html lang="en">
|
||||
<div th:fragment="queries-list" class="container-fluid">
|
||||
<div th:each="query,queryIterStat : ${queries}" class="panel panel-default" th:id="'search-div-' + ${queryIterStat.index}" >
|
||||
|
||||
<div class="panel-heading">
|
||||
<div class="pull-right">
|
||||
<button type="button" th:id="'search-btn-' + ${queryIterStat.index}" class="btn btn-primary btn-block"
|
||||
|
@ -16,8 +17,14 @@
|
|||
var btn = $(this);
|
||||
btn.button('loading');
|
||||
var searchDiv = '<th:block th:text="'search-div-' + ${queryIterStat.index}"/>';
|
||||
var sd = $('#' + searchDiv).find('input').each(function() {
|
||||
this.name = this.id;
|
||||
$('#' + searchDiv).find('input').each(function() {
|
||||
if (this.id) {
|
||||
if (this.id.substring(0,4) == 'inc_') {
|
||||
this.name = '_include';
|
||||
} else {
|
||||
this.name = this.id;
|
||||
}
|
||||
}
|
||||
});
|
||||
$("#outerForm").attr("action", "search").submit();
|
||||
});
|
||||
|
@ -33,6 +40,7 @@
|
|||
<div th:each="param,paramIterStat : ${query.parameter}"
|
||||
th:id="'search-param-rowopts-' + ${queryIterStat.index} + '-' + ${paramIterStat.index}"
|
||||
th:class="'row queryParameter ' + (${paramIterStat.odd} ? 'queryParameterOdd')">
|
||||
|
||||
<div class="col-sm-6">
|
||||
<div class="searchParamDescription">
|
||||
<div>
|
||||
|
@ -61,6 +69,21 @@
|
|||
</script>
|
||||
<br clear="all"/>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid" th:unless="${queryIncludes[queryIterStat.index].empty}">
|
||||
<h4>Includes <small>Also load and include referenced resources in results</small></h4>
|
||||
</div>
|
||||
|
||||
<div class="row-fluid" th:unless="${queryIncludes[queryIterStat.index].empty}">
|
||||
<span th:each="include : ${queryIncludes[queryIterStat.index]}" class="includeCheckContainer">
|
||||
<span class="includeCheckCheck">
|
||||
<input type="checkbox" th:value="${include}" th:id="'inc_' + ${include}" />
|
||||
</span>
|
||||
<span class="includeCheckName" th:text="${include}"/>
|
||||
</span>
|
||||
</div>
|
||||
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -15,6 +15,18 @@ body {
|
|||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
.clientCodeBox
|
||||
{
|
||||
font-family: monospace;
|
||||
font-size: 0.8em;
|
||||
line-height: 0.85em;
|
||||
}
|
||||
|
||||
.clientCodePreamble {
|
||||
color: #888;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
label {
|
||||
font-size: 1.0em;
|
||||
color: #808080;
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
|
||||
function generateHapi(json, container) {
|
||||
if (json.action == 'search') {
|
||||
generateHapiSearch(json, container);
|
||||
}
|
||||
}
|
||||
|
||||
function generateHapiSearch(json, container) {
|
||||
container.append($('<span />', {'class': 'clientCodePreamble'}).text("FhirContext ctx = new FhirContext();"));
|
||||
container.append($('<br/>'));
|
||||
container.append($('<span />', {'class': 'clientCodePreamble'}).text("IGenericClient client = ctx.newRestfulGenericClient(\"" + json.base + "\");"));
|
||||
container.append($('<br/>'));
|
||||
|
||||
var searchLine = 'client.search()';
|
||||
if (json.resource != null) {
|
||||
searchLine = searchLine + '.forResource(' + json.resource + '.class)';
|
||||
} else {
|
||||
searchLine = searchLine + '.forAllResources()';
|
||||
}
|
||||
container.append($('<span />', {'class': 'clientCodeMain'}).text(searchLine));
|
||||
|
||||
}
|
|
@ -87,8 +87,6 @@ public class OverlayTestApp {
|
|||
|
||||
IFhirSystemDao systemDao = appCtx.getBean("mySystemDao", IFhirSystemDao.class);
|
||||
|
||||
@SuppressWarnings("rawtypes")
|
||||
Collection<IFhirResourceDao> resourceDaos = appCtx.getBeansOfType(IFhirResourceDao.class).values();
|
||||
JpaSystemProvider systemProvider = new JpaSystemProvider(systemDao);
|
||||
|
||||
RestfulServer restServer = new RestfulServer();
|
||||
|
|
Loading…
Reference in New Issue