Refactor the way that contexts are used in narrative generator

This commit is contained in:
James Agnew 2019-03-11 16:05:08 -04:00
parent f934f76c96
commit 71a07c0239
13 changed files with 135 additions and 139 deletions

View File

@ -36,16 +36,16 @@ public abstract class BaseThymeleafNarrativeGenerator extends ThymeleafNarrative
/**
* Constructor
*/
public BaseThymeleafNarrativeGenerator(FhirContext theFhirContext) {
super(theFhirContext);
public BaseThymeleafNarrativeGenerator() {
super();
}
@Override
public boolean populateResourceNarrative(IBaseResource theResource) {
public boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource) {
if (!myInitialized) {
initialize();
}
super.populateResourceNarrative(theResource);
super.populateResourceNarrative(theFhirContext, theResource);
return false;
}
@ -58,7 +58,7 @@ public abstract class BaseThymeleafNarrativeGenerator extends ThymeleafNarrative
List<String> propFileName = getPropertyFile();
try {
NarrativeTemplateManifest manifest = NarrativeTemplateManifest.forManifestFileLocation(getFhirContext(), propFileName);
NarrativeTemplateManifest manifest = NarrativeTemplateManifest.forManifestFileLocation(propFileName);
setManifest(manifest);
} catch (IOException e) {
throw new InternalErrorException(e);

View File

@ -40,8 +40,8 @@ public class CustomThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGen
* <li>classpath:/com/package/file.properties</li>
* </ul>
*/
public CustomThymeleafNarrativeGenerator(FhirContext theFhirContext, String... thePropertyFile) {
super(theFhirContext);
public CustomThymeleafNarrativeGenerator(String... thePropertyFile) {
super();
setPropertyFile(thePropertyFile);
}

View File

@ -20,8 +20,6 @@ package ca.uhn.fhir.narrative;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import java.util.ArrayList;
import java.util.List;
@ -32,8 +30,8 @@ public class DefaultThymeleafNarrativeGenerator extends BaseThymeleafNarrativeGe
private boolean myUseHapiServerConformanceNarrative;
public DefaultThymeleafNarrativeGenerator(FhirContext theFhirContext) {
super(theFhirContext);
public DefaultThymeleafNarrativeGenerator() {
super();
}
@Override

View File

@ -20,6 +20,7 @@ package ca.uhn.fhir.narrative;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.instance.model.api.IBaseResource;
public interface INarrativeGenerator {
@ -32,6 +33,6 @@ public interface INarrativeGenerator {
*
* @return Returns <code>true</code> if a narrative was actually generated
*/
boolean populateResourceNarrative(IBaseResource theResource);
boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource);
}

View File

@ -27,14 +27,13 @@ import ca.uhn.fhir.context.FhirVersionEnum;
import ca.uhn.fhir.fluentpath.IFluentPath;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import ca.uhn.fhir.rest.server.exceptions.InternalErrorException;
import org.apache.commons.lang3.Validate;
import org.hl7.fhir.instance.model.api.IBase;
import org.hl7.fhir.instance.model.api.IBaseResource;
import org.hl7.fhir.instance.model.api.INarrative;
import java.util.Collections;
import java.util.EnumSet;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
@ -44,12 +43,6 @@ import static org.apache.commons.lang3.StringUtils.isNotBlank;
public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
private INarrativeTemplateManifest myManifest;
private final FhirContext myFhirContext;
public BaseNarrativeGenerator(FhirContext theFhirContext) {
Validate.notNull(theFhirContext, "theFhirContext must not be null");
myFhirContext = theFhirContext;
}
public INarrativeTemplateManifest getManifest() {
return myManifest;
@ -59,43 +52,40 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
myManifest = theManifest;
}
public FhirContext getFhirContext() {
return myFhirContext;
}
@Override
public boolean populateResourceNarrative(IBaseResource theResource) {
Optional<INarrativeTemplate> templateOpt = getTemplateForElement(theResource);
if (templateOpt.isPresent()) {
return applyTemplate(templateOpt.get(), theResource);
} else {
return false;
public boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource) {
List<INarrativeTemplate> templateOpt = getTemplateForElement(theFhirContext, theResource);
if (templateOpt.size() > 0) {
applyTemplate(theFhirContext, templateOpt.get(0), theResource);
return true;
}
return false;
}
private Optional<INarrativeTemplate> getTemplateForElement(IBase theElement) {
return myManifest.getTemplateByElement(getStyle(), theElement);
private List<INarrativeTemplate> getTemplateForElement(FhirContext theFhirContext, IBase theElement) {
return myManifest.getTemplateByElement(theFhirContext, getStyle(), theElement);
}
private boolean applyTemplate(INarrativeTemplate theTemplate, IBaseResource theResource) {
private boolean applyTemplate(FhirContext theFhirContext, INarrativeTemplate theTemplate, IBaseResource theResource) {
if (templateDoesntApplyToResource(theTemplate, theResource)) {
return false;
}
boolean retVal = false;
String resourceName = myFhirContext.getResourceDefinition(theResource).getName();
String resourceName = theFhirContext.getResourceDefinition(theResource).getName();
String contextPath = defaultIfEmpty(theTemplate.getContextPath(), resourceName);
// Narrative templates define a path within the resource that they apply to. Here, we're
// finding anywhere in the resource that gets a narrative
List<IBase> targets = findElementsInResourceRequiringNarratives(theResource, contextPath);
List<IBase> targets = findElementsInResourceRequiringNarratives(theFhirContext, theResource, contextPath);
for (IBase nextTargetContext : targets) {
// Extract [element].text of type Narrative
INarrative nextTargetNarrative = getOrCreateNarrativeChildElement(nextTargetContext);
INarrative nextTargetNarrative = getOrCreateNarrativeChildElement(theFhirContext, nextTargetContext);
// Create the actual narrative text
String narrative = applyTemplate(theTemplate, nextTargetContext);
String narrative = applyTemplate(theFhirContext, theTemplate, nextTargetContext);
narrative = cleanWhitespace(narrative);
if (isNotBlank(narrative)) {
@ -112,13 +102,13 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
return retVal;
}
private INarrative getOrCreateNarrativeChildElement(IBase nextTargetContext) {
BaseRuntimeElementCompositeDefinition<?> targetElementDef = (BaseRuntimeElementCompositeDefinition<?>) getFhirContext().getElementDefinition(nextTargetContext.getClass());
private INarrative getOrCreateNarrativeChildElement(FhirContext theFhirContext, IBase nextTargetContext) {
BaseRuntimeElementCompositeDefinition<?> targetElementDef = (BaseRuntimeElementCompositeDefinition<?>) theFhirContext.getElementDefinition(nextTargetContext.getClass());
BaseRuntimeChildDefinition targetTextChild = targetElementDef.getChildByName("text");
List<IBase> existing = targetTextChild.getAccessor().getValues(nextTargetContext);
INarrative nextTargetNarrative;
if (existing.isEmpty()) {
nextTargetNarrative = (INarrative) getFhirContext().getElementDefinition("narrative").newInstance();
nextTargetNarrative = (INarrative) theFhirContext.getElementDefinition("narrative").newInstance();
targetTextChild.getMutator().addValue(nextTargetContext, nextTargetNarrative);
} else {
nextTargetNarrative = (INarrative) existing.get(0);
@ -126,15 +116,15 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
return nextTargetNarrative;
}
private List<IBase> findElementsInResourceRequiringNarratives(IBaseResource theResource, String theContextPath) {
if (myFhirContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
private List<IBase> findElementsInResourceRequiringNarratives(FhirContext theFhirContext, IBaseResource theResource, String theContextPath) {
if (theFhirContext.getVersion().getVersion().isOlderThan(FhirVersionEnum.DSTU3)) {
return Collections.singletonList(theResource);
}
IFluentPath fhirPath = myFhirContext.newFluentPath();
IFluentPath fhirPath = theFhirContext.newFluentPath();
return fhirPath.evaluate(theResource, theContextPath, IBase.class);
}
protected abstract String applyTemplate(INarrativeTemplate theTemplate, IBase theTargetContext);
protected abstract String applyTemplate(FhirContext theFhirContext, INarrativeTemplate theTemplate, IBase theTargetContext);
private boolean templateDoesntApplyToResource(INarrativeTemplate theTemplate, IBaseResource theResource) {
boolean retVal = false;
@ -156,7 +146,7 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
return retVal;
}
protected abstract TemplateTypeEnum getStyle();
protected abstract EnumSet<TemplateTypeEnum> getStyle();
/**
* Trims the superfluous whitespace out of an HTML block
@ -188,7 +178,6 @@ public abstract class BaseNarrativeGenerator implements INarrativeGenerator {
if (inWhitespace && !lastNonWhitespaceCharWasTagEnd) {
b.append(' ');
}
inWhitespace = false;
b.append(nextChar);
inWhitespace = false;
betweenTags = false;

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.narrative2;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -20,14 +20,16 @@ package ca.uhn.fhir.narrative2;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import org.hl7.fhir.instance.model.api.IBase;
import java.util.Optional;
import java.util.EnumSet;
import java.util.List;
public interface INarrativeTemplateManifest {
Optional<INarrativeTemplate> getTemplateByResourceName(TemplateTypeEnum theStyle, String theResourceName);
List<INarrativeTemplate> getTemplateByResourceName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theResourceName);
Optional<INarrativeTemplate> getTemplateByName(TemplateTypeEnum theStyle, String theName);
List<INarrativeTemplate> getTemplateByName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theName);
Optional<INarrativeTemplate> getTemplateByElement(TemplateTypeEnum theStyle, IBase theElementValue);
List<INarrativeTemplate> getTemplateByElement(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, IBase theElementValue);
}

View File

@ -9,9 +9,9 @@ package ca.uhn.fhir.narrative2;
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -34,41 +34,37 @@ import org.slf4j.LoggerFactory;
import java.io.*;
import java.util.*;
import java.util.stream.Collectors;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
private static final Logger ourLog = LoggerFactory.getLogger(NarrativeTemplateManifest.class);
private final Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> myStyleToResourceTypeToTemplate;
private final Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> myStyleToDatatypeToTemplate;
private final Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> myStyleToNameToTemplate;
private final FhirContext myCtx;
private final Map<String, List<NarrativeTemplate>> myStyleToResourceTypeToTemplate;
private final Map<String, List<NarrativeTemplate>> myStyleToDatatypeToTemplate;
private final Map<String, List<NarrativeTemplate>> myStyleToNameToTemplate;
private final int myTemplateCount;
private NarrativeTemplateManifest(FhirContext theFhirContext, Collection<NarrativeTemplate> theTemplates) {
myCtx = theFhirContext;
Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> styleToResourceTypeToTemplate = new HashMap<>();
Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> styleToDatatypeToTemplate = new HashMap<>();
Map<TemplateTypeEnum, Map<String, NarrativeTemplate>> styleToNameToTemplate = new HashMap<>();
private NarrativeTemplateManifest(Collection<NarrativeTemplate> theTemplates) {
Map<String, List<NarrativeTemplate>> resourceTypeToTemplate = new HashMap<>();
Map<String, List<NarrativeTemplate>> datatypeToTemplate = new HashMap<>();
Map<String, List<NarrativeTemplate>> nameToTemplate = new HashMap<>();
for (NarrativeTemplate nextTemplate : theTemplates) {
Map<String, NarrativeTemplate> resourceTypeToTemplate = styleToResourceTypeToTemplate.computeIfAbsent(nextTemplate.getTemplateType(), t -> new HashMap<>());
Map<String, NarrativeTemplate> datatypeToTemplate = styleToDatatypeToTemplate.computeIfAbsent(nextTemplate.getTemplateType(), t -> new HashMap<>());
Map<String, NarrativeTemplate> nameToTemplate = styleToNameToTemplate.computeIfAbsent(nextTemplate.getTemplateType(), t -> new HashMap<>());
nameToTemplate.put(nextTemplate.getTemplateName(), nextTemplate);
nameToTemplate.computeIfAbsent(nextTemplate.getTemplateName(), t -> new ArrayList<>()).add(nextTemplate);
for (String nextResourceType : nextTemplate.getAppliesToResourceTypes()) {
resourceTypeToTemplate.put(nextResourceType.toUpperCase(), nextTemplate);
resourceTypeToTemplate.computeIfAbsent(nextResourceType.toUpperCase(), t -> new ArrayList<>()).add(nextTemplate);
}
for (String nextDataType : nextTemplate.getAppliesToDataTypes()) {
datatypeToTemplate.put(nextDataType.toUpperCase(), nextTemplate);
datatypeToTemplate.computeIfAbsent(nextDataType.toUpperCase(), t -> new ArrayList<>()).add(nextTemplate);
}
}
myTemplateCount = theTemplates.size();
myStyleToNameToTemplate = makeImmutable(styleToNameToTemplate);
myStyleToResourceTypeToTemplate = makeImmutable(styleToResourceTypeToTemplate);
myStyleToDatatypeToTemplate = makeImmutable(styleToDatatypeToTemplate);
myStyleToNameToTemplate = makeImmutable(nameToTemplate);
myStyleToResourceTypeToTemplate = makeImmutable(resourceTypeToTemplate);
myStyleToDatatypeToTemplate = makeImmutable(datatypeToTemplate);
}
public int getNamedTemplateCount() {
@ -76,31 +72,31 @@ public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
}
@Override
public Optional<INarrativeTemplate> getTemplateByResourceName(TemplateTypeEnum theStyle, String theResourceName) {
return getFromMap(theStyle, theResourceName.toUpperCase(), myStyleToResourceTypeToTemplate);
public List<INarrativeTemplate> getTemplateByResourceName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theResourceName) {
return getFromMap(theStyles, theResourceName.toUpperCase(), myStyleToResourceTypeToTemplate);
}
@Override
public Optional<INarrativeTemplate> getTemplateByName(TemplateTypeEnum theStyle, String theName) {
return getFromMap(theStyle, theName, myStyleToNameToTemplate);
public List<INarrativeTemplate> getTemplateByName(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, String theName) {
return getFromMap(theStyles, theName, myStyleToNameToTemplate);
}
@Override
public Optional<INarrativeTemplate> getTemplateByElement(TemplateTypeEnum theStyle, IBase theElement) {
public List<INarrativeTemplate> getTemplateByElement(FhirContext theFhirContext, EnumSet<TemplateTypeEnum> theStyles, IBase theElement) {
if (theElement instanceof IBaseResource) {
String resourceName = myCtx.getResourceDefinition((IBaseResource) theElement).getName();
return getTemplateByResourceName(theStyle, resourceName);
String resourceName = theFhirContext.getResourceDefinition((IBaseResource) theElement).getName();
return getTemplateByResourceName(theFhirContext, theStyles, resourceName);
} else {
String datatypeName = myCtx.getElementDefinition(theElement.getClass()).getName();
return getFromMap(theStyle, datatypeName.toUpperCase(), myStyleToDatatypeToTemplate);
String datatypeName = theFhirContext.getElementDefinition(theElement.getClass()).getName();
return getFromMap(theStyles, datatypeName.toUpperCase(), myStyleToDatatypeToTemplate);
}
}
public static NarrativeTemplateManifest forManifestFileLocation(FhirContext theFhirContext, String... thePropertyFilePaths) throws IOException {
return forManifestFileLocation(theFhirContext, Arrays.asList(thePropertyFilePaths));
return forManifestFileLocation(Arrays.asList(thePropertyFilePaths));
}
public static NarrativeTemplateManifest forManifestFileLocation(FhirContext theFhirContext, Collection<String> thePropertyFilePaths) throws IOException {
public static NarrativeTemplateManifest forManifestFileLocation(Collection<String> thePropertyFilePaths) throws IOException {
ourLog.debug("Loading narrative properties file(s): {}", thePropertyFilePaths);
List<String> manifestFileContents = new ArrayList<>(thePropertyFilePaths.size());
@ -109,19 +105,19 @@ public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
manifestFileContents.add(resource);
}
return forManifestFileContents(theFhirContext, manifestFileContents);
return forManifestFileContents(manifestFileContents);
}
public static NarrativeTemplateManifest forManifestFileContents(FhirContext theFhirContext, String... theResources) throws IOException {
return forManifestFileContents(theFhirContext, Arrays.asList(theResources));
public static NarrativeTemplateManifest forManifestFileContents(String... theResources) throws IOException {
return forManifestFileContents(Arrays.asList(theResources));
}
public static NarrativeTemplateManifest forManifestFileContents(FhirContext theFhirContext, Collection<String> theResources) throws IOException {
public static NarrativeTemplateManifest forManifestFileContents(Collection<String> theResources) throws IOException {
List<NarrativeTemplate> templates = new ArrayList<>();
for (String next : theResources) {
templates.addAll(loadProperties(next));
}
return new NarrativeTemplateManifest(theFhirContext, templates);
return new NarrativeTemplateManifest(templates);
}
private static Collection<NarrativeTemplate> loadProperties(String theManifestText) throws IOException {
@ -222,17 +218,16 @@ public class NarrativeTemplateManifest implements INarrativeTemplateManifest {
}
}
private static <T> Optional<INarrativeTemplate> getFromMap(TemplateTypeEnum theStyle, T theResourceName, Map<TemplateTypeEnum, Map<T, NarrativeTemplate>> theMap) {
NarrativeTemplate retVal = null;
Map<T, NarrativeTemplate> resourceTypeToTemplate = theMap.get(theStyle);
if (resourceTypeToTemplate != null) {
retVal = resourceTypeToTemplate.get(theResourceName);
}
return Optional.ofNullable(retVal);
private static <T> List<INarrativeTemplate> getFromMap(EnumSet<TemplateTypeEnum> theStyles, T theKey, Map<T, List<NarrativeTemplate>> theMap) {
return theMap
.getOrDefault(theKey, Collections.emptyList())
.stream()
.filter(t->theStyles.contains(t.getTemplateType()))
.collect(Collectors.toList());
}
private static <T> Map<TemplateTypeEnum, Map<T, NarrativeTemplate>> makeImmutable(Map<TemplateTypeEnum, Map<T, NarrativeTemplate>> theStyleToResourceTypeToTemplate) {
theStyleToResourceTypeToTemplate.replaceAll((key, value) -> Collections.unmodifiableMap(value));
private static <T> Map<T, List<NarrativeTemplate>> makeImmutable(Map<T, List<NarrativeTemplate>> theStyleToResourceTypeToTemplate) {
theStyleToResourceTypeToTemplate.replaceAll((key, value) -> Collections.unmodifiableList(value));
return Collections.unmodifiableMap(theStyleToResourceTypeToTemplate);
}

View File

@ -20,12 +20,13 @@ package ca.uhn.fhir.narrative2;
* #L%
*/
import ca.uhn.fhir.context.FhirContext;
import ca.uhn.fhir.narrative.INarrativeGenerator;
import org.hl7.fhir.instance.model.api.IBaseResource;
public class NullNarrativeGenerator implements INarrativeGenerator {
@Override
public boolean populateResourceNarrative(IBaseResource theResource) {
public boolean populateResourceNarrative(FhirContext theFhirContext, IBaseResource theResource) {
return false;
}
}

View File

@ -45,9 +45,7 @@ import org.thymeleaf.templateresolver.DefaultTemplateResolver;
import org.thymeleaf.templateresource.ITemplateResource;
import org.thymeleaf.templateresource.StringTemplateResource;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.*;
import static org.apache.commons.lang3.StringUtils.isNotBlank;
@ -58,13 +56,13 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
/**
* Constructor
*/
public ThymeleafNarrativeGenerator(FhirContext theFhirContext) {
super(theFhirContext);
public ThymeleafNarrativeGenerator() {
super();
}
private TemplateEngine getTemplateEngine() {
private TemplateEngine getTemplateEngine(FhirContext theFhirContext) {
TemplateEngine engine = new TemplateEngine();
ProfileResourceResolver resolver = new ProfileResourceResolver();
ProfileResourceResolver resolver = new ProfileResourceResolver(theFhirContext);
engine.setTemplateResolver(resolver);
if (myMessageResolver != null) {
engine.setMessageResolver(myMessageResolver);
@ -73,8 +71,8 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
@Override
public Set<IProcessor> getProcessors(String theDialectPrefix) {
Set<IProcessor> retVal = super.getProcessors(theDialectPrefix);
retVal.add(new NarrativeTagProcessor(theDialectPrefix));
retVal.add(new NarrativeAttributeProcessor(theDialectPrefix));
retVal.add(new NarrativeTagProcessor(theFhirContext, theDialectPrefix));
retVal.add(new NarrativeAttributeProcessor(theDialectPrefix, theFhirContext));
return retVal;
}
@ -85,25 +83,23 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
}
@Override
protected String applyTemplate(INarrativeTemplate theTemplate, IBase theTargetContext) {
protected String applyTemplate(FhirContext theFhirContext, INarrativeTemplate theTemplate, IBase theTargetContext) {
Context context = new Context();
context.setVariable("resource", theTargetContext);
context.setVariable("context", theTargetContext);
context.setVariable("fhirVersion", getFhirContext().getVersion().getVersion().name());
context.setVariable("fhirVersion", theFhirContext.getVersion().getVersion().name());
String result = getTemplateEngine().process(theTemplate.getTemplateName(), context);
return result;
return getTemplateEngine(theFhirContext).process(theTemplate.getTemplateName(), context);
}
@Override
protected TemplateTypeEnum getStyle() {
return TemplateTypeEnum.THYMELEAF;
protected EnumSet<TemplateTypeEnum> getStyle() {
return EnumSet.of(TemplateTypeEnum.THYMELEAF);
}
private String applyTemplateWithinTag(ITemplateContext theTemplateContext, String theName, String theElement) {
private String applyTemplateWithinTag(FhirContext theFhirContext, ITemplateContext theTemplateContext, String theName, String theElement) {
IEngineConfiguration configuration = theTemplateContext.getConfiguration();
IStandardExpressionParser expressionParser = StandardExpressions.getExpressionParser(configuration);
final IStandardExpression expression = expressionParser.parseExpression(theTemplateContext, theElement);
@ -113,20 +109,20 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
return "";
}
Optional<INarrativeTemplate> templateOpt;
List<INarrativeTemplate> templateOpt;
if (isNotBlank(theName)) {
templateOpt = getManifest().getTemplateByName(getStyle(), theName);
if (!templateOpt.isPresent()) {
templateOpt = getManifest().getTemplateByName(theFhirContext, getStyle(), theName);
if (templateOpt.isEmpty()) {
throw new InternalErrorException("Unknown template name: " + theName);
}
} else {
templateOpt = getManifest().getTemplateByElement(getStyle(), elementValue);
if (!templateOpt.isPresent()) {
templateOpt = getManifest().getTemplateByElement(theFhirContext, getStyle(), elementValue);
if (templateOpt.isEmpty()) {
throw new InternalErrorException("No template for type: " + elementValue.getClass());
}
}
return applyTemplate(templateOpt.get(), elementValue);
return applyTemplate(theFhirContext, templateOpt.get(0), elementValue);
}
public void setMessageResolver(IMessageResolver theMessageResolver) {
@ -135,9 +131,15 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
private class ProfileResourceResolver extends DefaultTemplateResolver {
private final FhirContext myFhirContext;
private ProfileResourceResolver(FhirContext theFhirContext) {
myFhirContext = theFhirContext;
}
@Override
protected boolean computeResolvable(IEngineConfiguration theConfiguration, String theOwnerTemplate, String theTemplate, Map<String, Object> theTemplateResolutionAttributes) {
return getManifest().getTemplateByName(getStyle(), theTemplate).isPresent();
return getManifest().getTemplateByName(myFhirContext, getStyle(), theTemplate).size() > 0;
}
@Override
@ -148,7 +150,9 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
@Override
protected ITemplateResource computeTemplateResource(IEngineConfiguration theConfiguration, String theOwnerTemplate, String theTemplate, Map<String, Object> theTemplateResolutionAttributes) {
return getManifest()
.getTemplateByName(getStyle(), theTemplate)
.getTemplateByName(myFhirContext, getStyle(), theTemplate)
.stream()
.findFirst()
.map(t -> new StringTemplateResource(t.getTemplateText()))
.orElseThrow(() -> new IllegalArgumentException("Unknown template: " + theTemplate));
}
@ -161,8 +165,11 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
private class NarrativeTagProcessor extends AbstractElementTagProcessor {
public NarrativeTagProcessor(String dialectPrefix) {
private final FhirContext myFhirContext;
NarrativeTagProcessor(FhirContext theFhirContext, String dialectPrefix) {
super(TemplateMode.XML, dialectPrefix, "narrative", true, null, true, 0);
myFhirContext = theFhirContext;
}
@Override
@ -170,7 +177,7 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
String name = theTag.getAttributeValue("th:name");
String element = theTag.getAttributeValue("th:element");
String appliedTemplate = applyTemplateWithinTag(theTemplateContext, name, element);
String appliedTemplate = applyTemplateWithinTag(myFhirContext, theTemplateContext, name, element);
theStructureHandler.replaceWith(appliedTemplate, false);
}
}
@ -181,13 +188,16 @@ public class ThymeleafNarrativeGenerator extends BaseNarrativeGenerator {
*/
private class NarrativeAttributeProcessor extends AbstractAttributeTagProcessor {
protected NarrativeAttributeProcessor(String theDialectPrefix) {
private final FhirContext myFhirContext;
NarrativeAttributeProcessor(String theDialectPrefix, FhirContext theFhirContext) {
super(TemplateMode.XML, theDialectPrefix, null, false, "narrative", true, 0, true);
myFhirContext = theFhirContext;
}
@Override
protected void doProcess(ITemplateContext theContext, IProcessableElementTag theTag, AttributeName theAttributeName, String theAttributeValue, IElementTagStructureHandler theStructureHandler) {
String text = applyTemplateWithinTag(theContext, null, theAttributeValue);
String text = applyTemplateWithinTag(myFhirContext, theContext, null, theAttributeValue);
theStructureHandler.setBody(text, false);
}

View File

@ -360,7 +360,7 @@ public class JsonParser extends BaseParser implements IJsonLikeParser {
narr = null;
}
if (narr != null && narr.isEmpty()) {
gen.populateResourceNarrative(theResource);
gen.populateResourceNarrative(myContext, theResource);
if (!narr.isEmpty()) {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;
String childName = nextChild.getChildNameByDatatype(child.getDatatype());

View File

@ -371,7 +371,7 @@ public class XmlParser extends BaseParser /* implements IParser */ {
}
// FIXME potential null access on narr see line 623
if (gen != null && narr.isEmpty()) {
gen.populateResourceNarrative(theResource);
gen.populateResourceNarrative(myContext, theResource);
}
if (narr != null && narr.isEmpty() == false) {
RuntimeChildNarrativeDefinition child = (RuntimeChildNarrativeDefinition) nextChild;

View File

@ -1241,7 +1241,7 @@ public class JsonParserDstu3Test {
Patient p = new Patient();
p.addName().setFamily("Smith").addGiven("John");
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator(ourCtx));
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
String output = ourCtx.newJsonParser().encodeResourceToString(p);
ourLog.info(output);
@ -1410,7 +1410,7 @@ public class JsonParserDstu3Test {
}
@Test
public void testInvalidDateTimeValueInvalid() throws Exception {
public void testInvalidDateTimeValueInvalid() {
IParserErrorHandler errorHandler = mock(IParserErrorHandler.class);
String res = "{ \"resourceType\": \"Observation\", \"valueDateTime\": \"foo\" }";
@ -1422,7 +1422,7 @@ public class JsonParserDstu3Test {
assertEquals("foo", parsed.getValueDateTimeType().getValueAsString());
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq("foo"), msgCaptor.capture());
verify(errorHandler, times(1)).invalidValue(isNull(), eq("foo"), msgCaptor.capture());
assertEquals("Invalid date/time format: \"foo\"", msgCaptor.getValue());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
@ -1454,7 +1454,7 @@ public class JsonParserDstu3Test {
assertEquals(null, parsed.getGenderElement().getValueAsString());
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq(""), msgCaptor.capture());
verify(errorHandler, times(1)).invalidValue(isNull(), eq(""), msgCaptor.capture());
assertEquals("Attribute values must not be empty (\"\")", msgCaptor.getValue());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
@ -1474,7 +1474,7 @@ public class JsonParserDstu3Test {
assertEquals("foo", parsed.getGenderElement().getValueAsString());
ArgumentCaptor<String> msgCaptor = ArgumentCaptor.forClass(String.class);
verify(errorHandler, times(1)).invalidValue(isNull(IParseLocation.class), eq("foo"), msgCaptor.capture());
verify(errorHandler, times(1)).invalidValue(isNull(), eq("foo"), msgCaptor.capture());
assertEquals("Unknown AdministrativeGender code 'foo'", msgCaptor.getValue());
String encoded = ourCtx.newJsonParser().encodeResourceToString(parsed);
@ -1509,7 +1509,7 @@ public class JsonParserDstu3Test {
// FIXME: this should pass
@Test
@Ignore
public void testNamespacePreservationEncode() throws Exception {
public void testNamespacePreservationEncode() {
//@formatter:off
String input = "<Patient xmlns=\"http://hl7.org/fhir\" xmlns:xhtml=\"http://www.w3.org/1999/xhtml\">" +
"<text>" +
@ -1533,7 +1533,7 @@ public class JsonParserDstu3Test {
// TODO: this should pass
@Test
@Ignore
public void testNamespacePreservationParse() throws Exception {
public void testNamespacePreservationParse() {
String input = "{\"resourceType\":\"Patient\",\"text\":{\"div\":\"<xhtml:div xmlns:xhtml=\\\"http://www.w3.org/1999/xhtml\\\"><xhtml:img src=\\\"foo\\\"/>@fhirabend</xhtml:div>\"}}";
Patient parsed = ourCtx.newJsonParser().parseResource(Patient.class, input);
XhtmlNode div = parsed.getText().getDiv();
@ -2065,7 +2065,7 @@ public class JsonParserDstu3Test {
}
@Test
public void testParseMetadata() throws Exception {
public void testParseMetadata() {
//@formatter:off
String bundle = "{\n" +
" \"resourceType\" : \"Bundle\",\n" +
@ -2219,7 +2219,7 @@ public class JsonParserDstu3Test {
}
@Test(expected = DataFormatException.class)
public void testParseWithTrailingContent() throws Exception {
public void testParseWithTrailingContent() {
//@formatter:off
String bundle = "{\n" +
" \"resourceType\" : \"Bundle\",\n" +

View File

@ -1943,7 +1943,7 @@ public class XmlParserDstu3Test {
Patient p = new Patient();
p.addName().setFamily("Smith").addGiven("John");
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator(ourCtx));
ourCtx.setNarrativeGenerator(new DefaultThymeleafNarrativeGenerator());
String output = ourCtx.newXmlParser().encodeResourceToString(p);
ourLog.info(output);