Clean up docs
This commit is contained in:
parent
7a7e876b93
commit
004f42cdcc
|
@ -20,5 +20,24 @@ package ca.uhn.hapi.fhir.docs;
|
|||
* #L%
|
||||
*/
|
||||
|
||||
public class NewInterceptors {
|
||||
import ca.uhn.fhir.interceptor.api.Hook;
|
||||
import ca.uhn.fhir.interceptor.api.Interceptor;
|
||||
import ca.uhn.fhir.interceptor.api.Pointcut;
|
||||
import ca.uhn.fhir.rest.api.server.RequestDetails;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
// START SNIPPET: sampleClass
|
||||
@Interceptor
|
||||
public class MyInterceptor {
|
||||
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(MyInterceptor.class);
|
||||
|
||||
@Hook(Pointcut.SERVER_INCOMING_REQUEST_PRE_HANDLED)
|
||||
public void logRequests(RequestDetails theRequest) {
|
||||
ourLog.info("Request of type {} with request ID: {}", theRequest.getOperation(), theRequest.getRequestId());
|
||||
}
|
||||
|
||||
}
|
||||
// END SNIPPET: sampleClass
|
|
@ -8,6 +8,7 @@ page.model.working_with_resources=Working With Resources
|
|||
page.model.profiles_and_extensions=Profiles and Extensions
|
||||
page.model.converter=Version Converters
|
||||
page.model.custom_structures=Custom Structures
|
||||
page.model.narrative_generation=Narrative Generation
|
||||
|
||||
section.server.title=Plain Server
|
||||
page.server.cors=CORS
|
||||
|
@ -18,6 +19,9 @@ section.jpa.jpa_server=JPA Server
|
|||
section.interceptors.title=Interceptors
|
||||
page.interceptors.interceptors=Interceptors Overview
|
||||
|
||||
section.validation.title=Validation
|
||||
section.validation.examples=Validation Examples
|
||||
|
||||
section.android.title=Android
|
||||
page.android.client=Android Client
|
||||
|
||||
|
|
|
@ -5,5 +5,5 @@ HAPI FHIR 3.8.0 introduced a new interceptor framework that is used across the e
|
|||
Interceptor classes may "hook into" various points in the processing chain in both the client and the server.
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/NewInterceptors.java|resource}}
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/MyInterceptor.java|sampleClass}}
|
||||
```
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
# Narrative Generation
|
||||
|
||||
HAPI provides a several ways to add [Narrative Text](http://hl7.org/fhir/narrative.html) to your encoded messages.
|
||||
|
||||
The simplest way is to simply place the narrative text directly in the resource via the `setDivAsString()` method.
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/Narrative.java|simple}}
|
||||
```
|
||||
|
||||
# Automatic Narrative Generartion
|
||||
|
||||
HAPI FHIR also comes with a built-in mechanism for automatically generating narratives based on your resources.
|
||||
|
||||
**Warning:** This built-in capability is a work in progress, and does not cover every type of resource or even every attribute in any resource. You should test it and configure it for your particular use cases.
|
||||
|
||||
HAPI's built-in narrative generation uses the [Thymeleaf](http://www.thymeleaf.org/) library for templating narrative texts. Thymeleaf provides a simple XHTML-based syntax which is easy to use and meshes well with the HAPI-FHIR model objects.
|
||||
|
||||
## A Simple Example
|
||||
|
||||
Activating HAPI's built-in narrative generator is as simple as calling [setNarrativeGenerator](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/context/FhirContext.html#setNarrativeGenerator(ca.uhn.fhir.narrative.INarrativeGenerator).
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/Narrative.java|example1}}
|
||||
```
|
||||
|
||||
...which produces the following output:
|
||||
|
||||
```xml
|
||||
<Patient xmlns="http://hl7.org/fhir">
|
||||
<text>
|
||||
<status value="generated"/>
|
||||
<div xmlns="http://www.w3.org/1999/xhtml">
|
||||
<div class="hapiHeaderText"> John Edward <b>SMITH </b></div>
|
||||
<table class="hapiPropertyTable">
|
||||
<tbody>
|
||||
<tr><td>Identifier</td><td>7000135</td></tr>
|
||||
<tr><td>Address</td><td><span>742 Evergreen Terrace</span><br/><span>Springfield</span> <span>ZZ</span></td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</text>
|
||||
<!-- .... snip ..... -->
|
||||
</Patient>
|
||||
```
|
||||
|
||||
# Built-in Narrative Templates
|
||||
|
||||
HAPI currently only comes with built-in support for a few resource types. Our intention is that people enhance these templates and create new ones, and share these back with us so that we can continue to build out the library. To see the current template library, see the source repository [here](https://github.com/jamesagnew/hapi-fhir/tree/master/hapi-fhir-base/src/main/resources/ca/uhn/fhir/narrative).
|
||||
|
||||
Note that these templates expect a few specific CSS definitions to be present in your site's CSS file. See the [narrative CSS](https://github.com/jamesagnew/hapi-fhir/blob/master/hapi-fhir-base/src/main/resources/ca/uhn/fhir/narrative/hapi-narrative.css) to see these.
|
||||
|
||||
# Creating your own Templates
|
||||
|
||||
To use your own templates for narrative generation, simply create one or more templates, using the Thymeleaf HTML based syntax.
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/fhir/narrative/OperationOutcome.html}}
|
||||
```
|
||||
|
||||
Then create a properties file which describes your templates. In this properties file, each resource to be defined has a pair or properties.
|
||||
|
||||
The first (name.class) defines the class name of the resource to define a template for. The second (name.narrative) defines the path/classpath to the template file. The format of this path is `file:/path/foo.html` or `classpath:/com/classpath/foo.html`.
|
||||
</p>
|
||||
|
||||
```properties
|
||||
# Two property lines in the file per template
|
||||
practitioner.class=ca.uhn.fhir.model.dstu.resource.Practitioner
|
||||
practitioner.narrative=file:src/test/resources/narrative/Practitioner.html
|
||||
|
||||
observation.class=ca.uhn.fhir.model.dstu.resource.Observation
|
||||
observation.narrative=file:src/test/resources/narrative/Observation.html
|
||||
|
||||
# etc...
|
||||
```
|
||||
|
||||
You may also override/define behaviour for datatypes. These datatype narrative definitions will be used as content within <code>th:narrative</code> blocks in resource templates. See the example resource template above for an example.
|
||||
|
||||
```properties
|
||||
# datatypes use the same format as resources
|
||||
humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt
|
||||
humanname.narrative=classpath:ca/uhn/fhir/narrative/HumanNameDt.html]]></source>
|
||||
```
|
||||
|
||||
Finally, use the [CustomThymeleafNarrativeGenerator](/hapi-fhir/apidocs/hapi-fhir-base/ca/uhn/fhir/narrative/CustomThymeleafNarrativeGenerator.html) and provide it to the FhirContext.
|
||||
|
||||
```java
|
||||
{{snippet:classpath:/ca/uhn/hapi/fhir/docs/NarrativeGenerator.java|gen}}
|
||||
```
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
|
||||
# Validation Examples
|
||||
|
||||
## Generate a Snapshot profile from a Differential
|
||||
|
||||
The following code can be used to generate a Snapshot Profile (StructureDefinition) when all you have is a differential.
|
||||
|
||||
```java
|
||||
// Create a validation chain that includes default validation support and a
|
||||
// snapshot generator
|
||||
DefaultProfileValidationSupport defaultSupport = new DefaultProfileValidationSupport();
|
||||
SnapshotGeneratingValidationSupport snapshotGenerator = new SnapshotGeneratingValidationSupport(myFhirCtx, defaultSupport);
|
||||
ValidationSupportChain chain = new ValidationSupportChain(defaultSupport, snapshotGenerator);
|
||||
|
||||
// Generate the snapshot
|
||||
StructureDefinition snapshot = chain.generateSnapshot(differential, "http://foo", null, "THE BEST PROFILE");
|
||||
```
|
||||
|
||||
|
|
@ -1,6 +1,9 @@
|
|||
package ca.uhn.fhir.jpa.dao.r4;
|
||||
|
||||
import ca.uhn.fhir.util.TestUtil;
|
||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.validation.SnapshotGeneratingValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.junit.After;
|
||||
import org.junit.AfterClass;
|
||||
|
@ -24,10 +27,22 @@ public class FhirResourceDaoR4StructureDefinitionTest extends BaseJpaR4Test {
|
|||
|
||||
@Test
|
||||
public void testGenerateSnapshot() throws IOException {
|
||||
StructureDefinition sd = loadResourceFromClasspath(StructureDefinition.class, "/r4/profile-differential-patient-r4.json");
|
||||
assertEquals(0, sd.getSnapshot().getElement().size());
|
||||
StructureDefinition differential = loadResourceFromClasspath(StructureDefinition.class, "/r4/profile-differential-patient-r4.json");
|
||||
assertEquals(0, differential.getSnapshot().getElement().size());
|
||||
|
||||
StructureDefinition output = myStructureDefinitionDao.generateSnapshot(sd, "http://foo", null, "THE BEST PROFILE");
|
||||
// Create a validation chain that includes default validation support and a
|
||||
// snapshot generator
|
||||
DefaultProfileValidationSupport defaultSupport = new DefaultProfileValidationSupport();
|
||||
SnapshotGeneratingValidationSupport snapshotGenerator = new SnapshotGeneratingValidationSupport(myFhirCtx, defaultSupport);
|
||||
ValidationSupportChain chain = new ValidationSupportChain(defaultSupport, snapshotGenerator);
|
||||
|
||||
// Generate the snapshot
|
||||
StructureDefinition snapshot = chain.generateSnapshot(differential, "http://foo", null, "THE BEST PROFILE");
|
||||
|
||||
String url = "http://foo";
|
||||
String webUrl = null;
|
||||
String name = "Foo Profile";
|
||||
StructureDefinition output = myStructureDefinitionDao.generateSnapshot(differential, url, webUrl, name);
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(output));
|
||||
|
||||
assertEquals(51, output.getSnapshot().getElement().size());
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
package org.hl7.fhir.r4.validation;
|
||||
|
||||
import ca.uhn.fhir.context.FhirContext;
|
||||
import ca.uhn.fhir.parser.IParser;
|
||||
import ca.uhn.fhir.rest.api.EncodingEnum;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.hl7.fhir.instance.model.api.IBaseResource;
|
||||
import org.hl7.fhir.r4.hapi.ctx.DefaultProfileValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.validation.SnapshotGeneratingValidationSupport;
|
||||
import org.hl7.fhir.r4.hapi.validation.ValidationSupportChain;
|
||||
import org.hl7.fhir.r4.model.StructureDefinition;
|
||||
import org.junit.Test;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class SnapshotGeneratorR4Test {
|
||||
|
||||
private FhirContext myFhirCtx = FhirContext.forR4();
|
||||
private static final Logger ourLog = LoggerFactory.getLogger(SnapshotGeneratorR4Test.class);
|
||||
|
||||
@Test
|
||||
public void testGenerateSnapshot() throws IOException {
|
||||
StructureDefinition differential = loadResourceFromClasspath(StructureDefinition.class, "/r4/profile-differential-patient-r4.json");
|
||||
|
||||
// Create a validation chain that includes default validation support and a
|
||||
// snapshot generator
|
||||
DefaultProfileValidationSupport defaultSupport = new DefaultProfileValidationSupport();
|
||||
SnapshotGeneratingValidationSupport snapshotGenerator = new SnapshotGeneratingValidationSupport(myFhirCtx, defaultSupport);
|
||||
ValidationSupportChain chain = new ValidationSupportChain(defaultSupport, snapshotGenerator);
|
||||
|
||||
// Generate the snapshot
|
||||
StructureDefinition snapshot = chain.generateSnapshot(differential, "http://foo", null, "THE BEST PROFILE");
|
||||
|
||||
ourLog.info(myFhirCtx.newJsonParser().setPrettyPrint(true).encodeResourceToString(snapshot));
|
||||
|
||||
assertEquals(51, snapshot.getSnapshot().getElement().size());
|
||||
}
|
||||
|
||||
|
||||
|
||||
protected <T extends IBaseResource> T loadResourceFromClasspath(Class<T> type, String resourceName) throws IOException {
|
||||
InputStream stream = SnapshotGeneratorR4Test.class.getResourceAsStream(resourceName);
|
||||
if (stream == null) {
|
||||
fail("Unable to load resource: " + resourceName);
|
||||
}
|
||||
String string = IOUtils.toString(stream, StandardCharsets.UTF_8);
|
||||
IParser newJsonParser = EncodingEnum.detectEncodingNoDefault(string).newParser(myFhirCtx);
|
||||
return newJsonParser.parseResource(type, string);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
{
|
||||
"resourceType":"StructureDefinition",
|
||||
"url":"http://example.com/fhir/StructureDefinition/patient-1a-extensions",
|
||||
"version":"0.1",
|
||||
"name":"PatientWithExtensions",
|
||||
"title":"Patient Profile 1 - 1a Extensions",
|
||||
"status":"active",
|
||||
"experimental":false,
|
||||
"date":"2019",
|
||||
"publisher":"Chris Grenz",
|
||||
"contact": [
|
||||
{
|
||||
"telecom": [
|
||||
{
|
||||
"system":"email",
|
||||
"value":"chris.grenz@thoughtworks.com"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"description":"Profile of Patient with extensions",
|
||||
"copyright":"(c)2019 Chris Grenz into public domain",
|
||||
"fhirVersion":"4.0.0",
|
||||
"kind":"resource",
|
||||
"abstract":false,
|
||||
"type":"Patient",
|
||||
"baseDefinition":"http://hl7.org/fhir/StructureDefinition/Patient",
|
||||
"derivation":"constraint",
|
||||
"differential":{
|
||||
"element": [
|
||||
{
|
||||
"id":"Patient",
|
||||
"path":"Patient"
|
||||
},
|
||||
{
|
||||
"id":"Patient.extension",
|
||||
"path":"Patient.extension"
|
||||
},
|
||||
{
|
||||
"id":"Patient.extension:doNotCall",
|
||||
"path":"Patient.extension",
|
||||
"sliceName":"doNotCall",
|
||||
"type": [
|
||||
{
|
||||
"code":"Extension",
|
||||
"profile": [
|
||||
"http://example.com/fhir/StructureDefinition/patient-donotcall"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id":"Patient.extension:legalCase",
|
||||
"path":"Patient.extension",
|
||||
"sliceName":"legalCase",
|
||||
"type": [
|
||||
{
|
||||
"code":"Extension",
|
||||
"profile": [
|
||||
"http://example.com/fhir/StructureDefinition/patient-legalcase"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id":"Patient.extension:legalCase.value[x]:valueBoolean.extension:leadCounsel",
|
||||
"path":"Patient.extension.valueBoolean.extension",
|
||||
"sliceName":"leadCounsel",
|
||||
"type": [
|
||||
{
|
||||
"code":"Extension",
|
||||
"profile": [
|
||||
"http://example.com/fhir/StructureDefinition/patient-legalcase-leadcounsel"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
|
@ -1,6 +1,8 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<document xmlns="http://maven.apache.org/XDOC/2.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/XDOC/2.0 http://maven.apache.org/xsd/xdoc-2.0.xsd">
|
||||
|
||||
<!-- This has been migrated -->
|
||||
|
||||
<properties>
|
||||
<title>Narrative Generation</title>
|
||||
<author email="jamesagnew@users.sourceforge.net">James Agnew</author>
|
||||
|
|
Loading…
Reference in New Issue