Doc updates

This commit is contained in:
jamesagnew 2014-04-02 08:05:16 -04:00
parent 81b2b1cc50
commit f7a4b48e07
13 changed files with 205 additions and 61 deletions

View File

@ -264,8 +264,10 @@
var pres = elements[i].getElementsByTagName("pre");
for (var j = 0; j < pres.length; j++) {
var pre = pres[j];
if (pre.innerHTML.match(/\\\*/)) {
if (pre.innerHTML.match(/\/\*/)) {
pre.className = 'brush: java';
} else if (pre.innerHTML.match(/^\#/)) {
pre.className = 'brush: bash';
} else if (pre.innerHTML.match(/\&lt\;\//)) {
pre.className = 'brush: xml';
} else {

View File

@ -51,15 +51,20 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
private HashMap<String, String> myProfileToNarrativeName;
private HashMap<Class<?>, String> myClassToNarrativeName;
private HashMap<String, String> myNameToNarrativeTemplate;
private boolean myApplyDefaultDatatypeTemplates=true;
private volatile boolean myInitialized;
@Override
public NarrativeDt generateNarrative(IResource theResource) {
return generateNarrative(null, theResource);
}
@Override
public NarrativeDt generateNarrative(String theProfile, IResource theResource) {
if (!myInitialized) {
initialize();
}
String name = null;
if (StringUtils.isNotBlank(theProfile)) {
name = myProfileToNarrativeName.get(theProfile);
@ -80,7 +85,7 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
try {
Context context = new Context();
context.setVariable("resource", theResource);
String result = myProfileTemplateEngine.process(name, context);
if (myCleanWhitespace) {
@ -113,8 +118,11 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
if (isBlank(propFileName)) {
throw new ConfigurationException("Property file name can not be null");
}
try {
if (myApplyDefaultDatatypeTemplates) {
loadProperties(DefaultThymeleafNarrativeGenerator.NARRATIVES_PROPERTIES);
}
loadProperties(propFileName);
} catch (IOException e) {
throw new ConfigurationException("Can not load property file " + propFileName, e);
@ -139,9 +147,12 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
protected abstract String getPropertyFile();
/**
* If set to <code>true</code> (which is the default), most whitespace will be trimmed from the generated narrative before it is returned.
* If set to <code>true</code> (which is the default), most whitespace will
* be trimmed from the generated narrative before it is returned.
* <p>
* Note that in order to preserve formatting, not all whitespace is trimmed. Repeated whitespace characters (e.g. "\n \n ") will be trimmed to a single space.
* Note that in order to preserve formatting, not all whitespace is trimmed.
* Repeated whitespace characters (e.g. "\n \n ") will be
* trimmed to a single space.
* </p>
*/
public boolean isCleanWhitespace() {
@ -149,24 +160,30 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
}
/**
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative
* indicating that no narrative is available.
* If set to <code>true</code>, which is the default, if any failure occurs
* during narrative generation the generator will suppress any generated
* exceptions, and simply return a default narrative indicating that no
* narrative is available.
*/
public boolean isIgnoreFailures() {
return myIgnoreFailures;
}
/**
* If set to true, will return an empty narrative block for any profiles where no template is available
* If set to true, will return an empty narrative block for any profiles
* where no template is available
*/
public boolean isIgnoreMissingTemplates() {
return myIgnoreMissingTemplates;
}
/**
* If set to <code>true</code> (which is the default), most whitespace will be trimmed from the generated narrative before it is returned.
* If set to <code>true</code> (which is the default), most whitespace will
* be trimmed from the generated narrative before it is returned.
* <p>
* Note that in order to preserve formatting, not all whitespace is trimmed. Repeated whitespace characters (e.g. "\n \n ") will be trimmed to a single space.
* Note that in order to preserve formatting, not all whitespace is trimmed.
* Repeated whitespace characters (e.g. "\n \n ") will be
* trimmed to a single space.
* </p>
*/
public void setCleanWhitespace(boolean theCleanWhitespace) {
@ -174,15 +191,18 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
}
/**
* If set to <code>true</code>, which is the default, if any failure occurs during narrative generation the generator will suppress any generated exceptions, and simply return a default narrative
* indicating that no narrative is available.
* If set to <code>true</code>, which is the default, if any failure occurs
* during narrative generation the generator will suppress any generated
* exceptions, and simply return a default narrative indicating that no
* narrative is available.
*/
public void setIgnoreFailures(boolean theIgnoreFailures) {
myIgnoreFailures = theIgnoreFailures;
}
/**
* If set to true, will return an empty narrative block for any profiles where no template is available
* If set to true, will return an empty narrative block for any profiles
* where no template is available
*/
public void setIgnoreMissingTemplates(boolean theIgnoreMissingTemplates) {
myIgnoreMissingTemplates = theIgnoreMissingTemplates;
@ -261,11 +281,11 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
} else if (name.startsWith("file:")) {
File file = new File(name.substring("file:".length()));
if (file.exists() == false) {
throw new IOException("Can not read file: " + file.getAbsolutePath());
throw new IOException("File not found: " + file.getAbsolutePath());
}
return new FileInputStream(file);
} else {
throw new IOException("Invalid resource name: '" + name + "'");
throw new IOException("Invalid resource name: '" + name + "' (must start with classpath: or file: )");
}
}
@ -337,11 +357,14 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
final IStandardExpression expression = expressionParser.parseExpression(configuration, theArguments, attributeValue);
final Object value = expression.execute(configuration, theArguments);
theElement.removeAttribute(theAttributeName);
theElement.clearChildren();
Context context = new Context();
context.setVariable("resource", value);
String name = myClassToNarrativeName.get(value.getClass());
if (name == null) {
if (myIgnoreMissingTemplates) {
ourLog.debug("No narrative template available for type: {}", value.getClass());
@ -354,9 +377,6 @@ public abstract class BaseThymeleafNarrativeGenerator implements INarrativeGener
String result = myProfileTemplateEngine.process(name, context);
Document dom = DOMUtils.getXhtmlDOMFor(new StringReader(result));
theElement.removeAttribute(theAttributeName);
theElement.clearChildren();
Element firstChild = (Element) dom.getFirstChild();
for (Node next : firstChild.getChildren()) {
theElement.addChild(next);

View File

@ -1,16 +1,13 @@
package ca.uhn.fhir.narrative;
import java.io.IOException;
public class DefaultThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGenerator implements INarrativeGenerator {
public DefaultThymeleafNarrativeGenerator() throws IOException {
super();
}
static final String NARRATIVES_PROPERTIES = "classpath:ca/uhn/fhir/narrative/narratives.properties";
@Override
protected String getPropertyFile() {
return "classpath:ca/uhn/fhir/narrative/narratives.properties";
return NARRATIVES_PROPERTIES;
}
}

View File

@ -6,6 +6,8 @@ import ca.uhn.fhir.parser.DataFormatException;
public interface INarrativeGenerator {
public NarrativeDt generateNarrative(String theProfile, IResource theResource) throws DataFormatException;
NarrativeDt generateNarrative(String theProfile, IResource theResource) throws DataFormatException;
NarrativeDt generateNarrative(IResource theResource);
}

View File

@ -0,0 +1,25 @@
package example;
import java.io.IOException;
import org.junit.Test;
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.CustomThymeleafNarrativeGenerator;
public class NarrativeGenerator {
@Test
public void testGenerator() throws IOException {
//START SNIPPET: gen
String propFile = "classpath:/com/foo/customnarrative.properties";
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator(propFile);
FhirContext ctx = new FhirContext();
ctx.setNarrativeGenerator(gen);
//END SNIPPET: gen
}
}

View File

@ -56,6 +56,7 @@
<script type="text/javascript" src="syntaxhighlighter/shCore.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJScript.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushJava.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushBash.js"></script>
<script type="text/javascript" src="syntaxhighlighter/shBrushXml.js"></script>
<link href="syntaxhighlighter/shCore.css" rel="stylesheet" type="text/css" />
<link href="syntaxhighlighter/shThemeDefault.css" rel="stylesheet" type="text/css" />

View File

@ -0,0 +1,38 @@
<?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">
<properties>
<title>Download - HAPI FHIR</title>
<author email="jamesagnew@users.sourceforge.net">James Agnew</author>
</properties>
<body>
<section name="Downloading HAPI FHIR">
<p>
The easiest way to get started with HAPI-FHIR is to either download the
source code from our
<a href="https://sourceforge.net/p/hl7api/fhircode/ci/master/tree/">Git Repository</a>
, or to use Maven:
</p>
<source><![CDATA[<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>${project.version}</version>
</dependency>]]></source>
<subsection name="Non-Maven Users">
<p>
Non-maven users can grab the files from the
<a href="https://sourceforge.net/projects/hl7api/files/hapi-fhir/">Sourceforge File Release System</a>.
</p>
</subsection>
</section>
</body>
</document>

View File

@ -9,7 +9,7 @@
<body>
<!-- The body of the document contains a number of sections -->
<section name="Developing using FHIR-HAPI">
<section name="Developing using HAPI FHIR">
<macro name="toc">
</macro>
@ -45,24 +45,10 @@
<section name="Getting Started">
<p>
The easiest way to get started with HAPI-FHIR is to either download the
source code from our
<a href="https://sourceforge.net/p/hl7api/fhircode/ci/master/tree/">Git Repository</a>
, or to use Maven:
</p>
<source><![CDATA[<dependency>
<groupId>ca.uhn.hapi.fhir</groupId>
<artifactId>hapi-fhir-base</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>]]></source>
<p>
If you are not using Maven, you can download the latest version
of the snapshot JAR (and optionally the Javadoc and Sources JAR) from the Maven
repo here: <a href="http://oss.sonatype.org/content/repositories/snapshots/ca/uhn/hapi/fhir/hapi-fhir-base/1.0-SNAPSHOT/">download</a>.
Once a formal release has been created, it will be uploaded through the Sourceforge
file release system (as the HAPI v2 libraries are).
</p>
To get started with HAPI FHIR, first download a copy and add it
to your project. See the <a href="doc_download.html">Download Page</a>
for instructions.
</p>
<subsection name="Introcuding the FHIR Context">

View File

@ -111,6 +111,63 @@
</section>
<section name="Creating your own Templates">
<p>
To use your own templates for narrative generation,
simply create one or more templates, using the Thymeleaf
HTML based syntax.
</p>
<macro name="snippet">
<param name="file" value="src/test/resources/narrative/Practitioner.html" />
</macro>
<p>
Then create a properties file which describes your
templates. In this properties file, each resource to
be defined has a pair or properties.
</p>
<p>
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 <code>file:/path/foo.html</code> or <code>classpath:/com/classpath/foo.html</code>
</p>
<source><![CDATA[# 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...]]></source>
<p>
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.
</p>
<source><![CDATA[# 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>
<p>
Finally, use the
<a href="./apidocs/ca/uhn/fhir/narrative/CustomThymeleafNarrativeGenerator.html">CustomThymeleafNarrativeGenerator</a>
and provide it
to the FhirContext.
</p>
<macro name="snippet">
<param name="id" value="gen" />
<param name="file" value="src/site/example/java/example/NarrativeGenerator.java" />
</macro>
</section>
</body>
</document>

View File

@ -1,18 +1,36 @@
package ca.uhn.fhir.narrative;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.io.IOException;
import org.junit.Test;
import ca.uhn.fhir.model.dstu.composite.NarrativeDt;
import ca.uhn.fhir.model.dstu.resource.Practitioner;
public class CustomThymeleafNarrativeGeneratorTest {
private static final org.slf4j.Logger ourLog = org.slf4j.LoggerFactory.getLogger(CustomThymeleafNarrativeGeneratorTest.class);
@Test
public void testGenerator() throws IOException {
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator("src/test/resources/narrative/customnarrative.properties");
CustomThymeleafNarrativeGenerator gen = new CustomThymeleafNarrativeGenerator("file:src/test/resources/narrative/customnarrative.properties");
Practitioner p = new Practitioner();
p.addIdentifier("sys", "val1");
p.addIdentifier("sys", "val2");
p.getAddress().addLine("line1").addLine("line2");
p.getName().addFamily("fam1").addGiven("given");
NarrativeDt narrative = gen.generateNarrative(p);
String actual = narrative.getDiv().getValueAsString();
ourLog.info(actual);
assertThat(actual, containsString("<h1>Name</h1><div> given <b>FAM1 </b></div><h1>Address</h1><div><span>line1 </span><br/><span>line2 </span><br/></div></div>"));
}
}

View File

@ -27,7 +27,7 @@ public class DefaultThymeleafNarrativeGeneratorTest {
private DefaultThymeleafNarrativeGenerator gen;
@Before
public void before() throws IOException {
public void before() {
gen = new DefaultThymeleafNarrativeGenerator();
gen.setIgnoreFailures(false);
gen.setIgnoreMissingTemplates(false);

View File

@ -10,12 +10,10 @@
HAPI also defines a custom tag, th:narrative="value", which is
used to render a datatype.
-->
<div th:narrative="${resource.addressFirstRep}"></div>
<h1>Name</h1>
<div th:narrative="${resource.name}"></div>
<h1>Address</h1>
<div th:narrative="${resource.address}"></div>
<!--
HAPI also defines a custom tag, th:narrative="value", which is
used to render a datatype.
-->
<div th:narrative="${resource.nameFirstRep}"></div>
</div>

View File

@ -9,7 +9,7 @@
# Format is file:/path/foo.html or classpath:/com/classpath/foo.html
#
practitioner.class=ca.uhn.fhir.model.dstu.resource.Practitioner
practitioner.narrative=file:src/test/resource/narrative/Practitioner.html
practitioner.narrative=file:src/test/resources/narrative/Practitioner.html
# You may also override/define behaviour for datatypes
humanname.class=ca.uhn.fhir.model.dstu.composite.HumanNameDt