Clean up docs

This commit is contained in:
James Agnew 2019-09-23 15:56:02 -04:00
parent 7a7e876b93
commit 004f42cdcc
9 changed files with 462 additions and 175 deletions

View File

@ -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

View File

@ -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

View File

@ -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}}
```

View File

@ -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}}
```

View File

@ -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");
```

View File

@ -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());

View File

@ -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);
}
}

View File

@ -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"
]
}
]
}
]
}
}

View File

@ -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>