//Dstl (c) Crown Copyright 2017 package uk.gov.dstl.baleen.consumers.template; import java.io.IOException; import java.io.Writer; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.stream.Stream; import com.samskivert.mustache.Template; import org.apache.commons.io.FilenameUtils; import org.apache.commons.lang3.StringUtils; import org.apache.uima.UimaContext; import org.apache.uima.fit.descriptor.ConfigurationParameter; import org.apache.uima.jcas.JCas; import org.apache.uima.resource.ResourceInitializationException; /** * A Mustache HTML template consumer for records that applies a template per * record per document. * <p> * Templates should be placed in the recordTemplateDirectory, and have the same * basename as the name of the record they are to match, with a ".html" * extension. * </p> * <p> * See {@link AbstractMustacheHtmlTemplateRecordConsumer} for examples of * writing a mustache template for this consumer. * </p> * <p> * For each document a file per record will be created in the configured * outputDirectory. The generated output files take the basename of the source * document URI, followed by a "-" followed by the name of the record, with a * ".html" extension, eg <code>MyDocument-recordName.html</code>. * </p> */ public class PerRecordMustacheHtmlTemplateRecordConsumer extends AbstractMustacheHtmlTemplateRecordConsumer { /** The Constant PARAM_RECORD_TEMPLATE_DIRECTORY. */ public static final String PARAM_RECORD_TEMPLATE_DIRECTORY = "recordTemplateDirectory"; /** * A directory containing templates named after each desired output record. * * @baleen.config recordTemplates */ @ConfigurationParameter(name = PARAM_RECORD_TEMPLATE_DIRECTORY, defaultValue = "recordTemplates") private String recordTemplateDirectory; /** The templates. */ private Map<String, Template> templates; @Override public void initialize(UimaContext context) throws ResourceInitializationException { super.initialize(context); templates = new HashMap<>(); Path templatesDir = Paths.get(recordTemplateDirectory); try (Stream<Path> templateStream = Files.list(templatesDir)) { templateStream.forEach(this::compileAndStoreTemplate); } catch (IOException e) { throw new ResourceInitializationException(e); } } /** * Compiles and stores the template based on its filename in the template * map for later lookup. * * Template filenames should end in ".html" and have a basename that * corresponds to the record name they are for. * * @param templatePath * the template path */ private void compileAndStoreTemplate(Path templatePath) { try { Template template = compileTemplate(templatePath); String baseName = FilenameUtils.getBaseName(templatePath.toString()); templates.put(StringUtils.lowerCase(baseName), template); } catch (IOException e) { getMonitor().warn("Failed to compile template " + templatePath.toAbsolutePath().toString(), e); } } @Override protected void writeRecords(String documentSourceName, JCas jCas, Map<String, Collection<ExtractedRecord>> records, Map<String, Object> fieldMap) { for (Collection<ExtractedRecord> extractedRecords : records.values()) { for (ExtractedRecord extractedRecord : extractedRecords) { String name = extractedRecord.getName(); Template template = templates.get(StringUtils.lowerCase(name)); if (template == null) { getMonitor().info("No template found for record {}", name); continue; } try (Writer writer = createOutputWriter(documentSourceName, name)) { template.execute(fieldMap, writer); } catch (IOException e) { getMonitor().warn("Failed to write record " + name + " for document " + documentSourceName, e); } } } } }