Skip to content

Commit

Permalink
Fix for #108, replace unnecessary template fetches with faster,
Browse files Browse the repository at this point in the history
sub-model searches
  • Loading branch information
ultraq committed May 29, 2016
1 parent 3f4c8ac commit 86e51d3
Show file tree
Hide file tree
Showing 7 changed files with 36 additions and 56 deletions.
11 changes: 3 additions & 8 deletions Source/nz/net/ultraq/thymeleaf/decorators/Decorator.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,11 @@ import org.thymeleaf.model.IModel
*/
interface Decorator {

// TODO: Might need to find a way to join source model and template into a
// single object so we don't have excessive method signatures.

/**
* Decorate the target model with the contents of the source model.
*
* @param targetModel The target model to be decorated.
* @param targetTemplate Name of the template from which the target model came.
* @param sourceModel The source model to use for decorating.
* @param sourceTemplate Name of the template from which the source model came.
* @param targetModel The target model to be decorated.
* @param sourceModel The source model to use for decorating.
*/
void decorate(IModel targetModel, String targetTemplate, IModel sourceModel, String sourceTemplate)
void decorate(IModel targetModel, IModel sourceModel)
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import nz.net.ultraq.thymeleaf.decorators.xml.XmlDocumentDecorator
import nz.net.ultraq.thymeleaf.expressions.ExpressionProcessor
import nz.net.ultraq.thymeleaf.fragments.FragmentMap
import nz.net.ultraq.thymeleaf.fragments.FragmentFinder
import nz.net.ultraq.thymeleaf.models.ModelFinder
import nz.net.ultraq.thymeleaf.models.TemplateModelFinder

import org.thymeleaf.context.ITemplateContext
import org.thymeleaf.engine.AttributeName
Expand Down Expand Up @@ -82,22 +82,21 @@ class DecoratorProcessor extends AbstractAttributeModelProcessor {
throw new IllegalArgumentException('layout:decorator attribute must appear in the root element of your template')
}

def modelFactory = context.modelFactory
def contentTemplateName = context.templateData.template
def decoratorTemplateName = new ExpressionProcessor(context).processAsString(attributeValue)

// Locate the template to 'redirect' processing to by completely replacing
// the current document with it
def modelFinder = new ModelFinder(context, templateMode)
def decoratorTemplate = modelFinder.findTemplate(decoratorTemplateName)
def decoratorTemplateName = new ExpressionProcessor(context).processAsString(attributeValue)
def decoratorTemplate = new TemplateModelFinder(context, templateMode)
.findTemplate(decoratorTemplateName)
.cloneModel()

// Gather all fragment parts from this page to apply to the new document
// after decoration has taken place
def pageFragments = new FragmentFinder(dialectPrefix).findFragments(model)

// Choose the decorator to use based on template mode, then apply it
def modelFactory = context.modelFactory
def decorator =
templateMode == TemplateMode.HTML ? new HtmlDocumentDecorator(modelFactory, modelFinder, sortingStrategy) :
templateMode == TemplateMode.HTML ? new HtmlDocumentDecorator(modelFactory, sortingStrategy) :
templateMode == TemplateMode.XML ? new XmlDocumentDecorator(modelFactory) :
null
if (!decorator) {
Expand All @@ -106,7 +105,7 @@ class DecoratorProcessor extends AbstractAttributeModelProcessor {
only HTML and XML template modes are currently supported
""".stripMargin())
}
decorator.decorate(decoratorTemplate, decoratorTemplateName, model, contentTemplateName)
decorator.decorate(decoratorTemplate, model)

// TODO: The modified decorator template includes anything outside the root
// element, which we don't want for the next step. Strip those events
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,19 +42,16 @@ class HtmlBodyDecorator extends XmlElementDecorator {
* Decorate the {@code <body>} part.
*
* @param targetBodyModel
* @param targetBodyTemplate
* @param sourceBodyModel
* @param targetBodyTemplate
*/
@Override
void decorate(IModel targetBodyModel, String targetBodyTemplate,
IModel sourceBodyModel, String sourceBodyTemplate) {
void decorate(IModel targetBodyModel, IModel sourceBodyModel) {

// Try to ensure there is a body as a result of decoration, applying the
// source body, or just using what is in the target
if (sourceBodyModel) {
if (targetBodyModel) {
super.decorate(targetBodyModel, targetBodyTemplate, sourceBodyModel, sourceBodyTemplate)
super.decorate(targetBodyModel, sourceBodyModel)
}
else {
targetBodyModel.replaceModel(sourceBodyModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package nz.net.ultraq.thymeleaf.decorators.html
import nz.net.ultraq.thymeleaf.decorators.Decorator
import nz.net.ultraq.thymeleaf.decorators.SortingStrategy
import nz.net.ultraq.thymeleaf.models.AttributeMerger
import nz.net.ultraq.thymeleaf.models.ModelFinder

import org.thymeleaf.model.ICloseElementTag
import org.thymeleaf.model.IModel
Expand All @@ -36,43 +35,37 @@ import org.thymeleaf.model.IOpenElementTag
class HtmlDocumentDecorator implements Decorator {

private final IModelFactory modelFactory
private final ModelFinder modelFinder
private final SortingStrategy sortingStrategy

/**
* Constructor, apply the given sorting strategy to the decorator.
*
* @param modelFactory
* @param modelFinder
* @param sortingStrategy
*/
HtmlDocumentDecorator(IModelFactory modelFactory, ModelFinder modelFinder, SortingStrategy sortingStrategy) {
HtmlDocumentDecorator(IModelFactory modelFactory, SortingStrategy sortingStrategy) {

this.modelFactory = modelFactory
this.modelFinder = modelFinder
this.sortingStrategy = sortingStrategy
}

/**
* Decorate an entire HTML page.
*
* @param targetDocumentModel
* @param targetDocumentTemplate
* @param sourceDocumentModel
* @param sourceDocumentTemplate
*/
@Override
void decorate(IModel targetDocumentModel, String targetDocumentTemplate,
IModel sourceDocumentModel, String sourceDocumentTemplate) {
void decorate(IModel targetDocumentModel, IModel sourceDocumentModel) {

// TODO: Expand the model finder to locate models within models so I
// don't have to go through the template manager. I think it'll
// also reduce the need for me to pass these template names around.
def headModelFinder = { event ->
return event instanceof IOpenElementTag && event.elementCompleteName == 'head'
}

def targetHeadModel = modelFinder.find(targetDocumentTemplate, 'head')
def targetHeadModel = targetDocumentModel.findModel(headModelFinder)
new HtmlHeadDecorator(modelFactory, sortingStrategy).decorate(
targetHeadModel, targetDocumentTemplate,
modelFinder.find(sourceDocumentTemplate, 'head'), sourceDocumentTemplate
targetHeadModel,
sourceDocumentModel.findModel(headModelFinder)
)

// Replace the head element and events with the decorated one
Expand All @@ -97,9 +90,12 @@ class HtmlDocumentDecorator implements Decorator {
targetDocumentModel.insertModel(headIndex, targetHeadModel)
}

def bodyModelFinder = { event ->
return event instanceof IOpenElementTag && event.elementCompleteName == 'body'
}
new HtmlBodyDecorator(modelFactory).decorate(
modelFinder.find(targetDocumentTemplate, 'body'), targetDocumentTemplate,
modelFinder.find(sourceDocumentTemplate, 'body'), sourceDocumentTemplate
targetDocumentModel.findModel(bodyModelFinder),
sourceDocumentModel.findModel(bodyModelFinder)
)

// TODO
Expand All @@ -112,12 +108,10 @@ class HtmlDocumentDecorator implements Decorator {


// Find the root element of the target document to merge
// TODO: Way of obtaining a model from within a model
def rootElementEventIndex = targetDocumentModel.findIndexOf { targetDocumentEvent ->
return targetDocumentEvent instanceof IOpenElementTag
}
def targetDocumentRootModel = modelFinder.find(targetDocumentTemplate,
targetDocumentModel.get(rootElementEventIndex).elementCompleteName)
def targetDocumentRootModel = targetDocumentModel.getModel(rootElementEventIndex)

// Bring the decorator into the content page (which is the one being processed)
new AttributeMerger(modelFactory).merge(targetDocumentRootModel, sourceDocumentModel)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,10 @@ class HtmlHeadDecorator extends XmlElementDecorator {
* Decorate the {@code <head>} part.
*
* @param targetHeadModel
* @param targetHeadTemplate
* @param sourceHeadModel
* @param sourceHeadTemplate
*/
@Override
void decorate(IModel targetHeadModel, String targetHeadTemplate,
IModel sourceHeadModel, String sourceHeadTemplate) {
void decorate(IModel targetHeadModel, IModel sourceHeadModel) {

// Try to ensure there is a head as a result of decoration, applying the
// source head, or just using what is in the target
Expand Down Expand Up @@ -130,6 +127,6 @@ class HtmlHeadDecorator extends XmlElementDecorator {
}
}

super.decorate(targetHeadModel, targetHeadTemplate, sourceHeadModel, sourceHeadTemplate)
super.decorate(targetHeadModel, sourceHeadModel)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ package nz.net.ultraq.thymeleaf.decorators.xml

import nz.net.ultraq.thymeleaf.decorators.Decorator
import nz.net.ultraq.thymeleaf.models.AttributeMerger
import nz.net.ultraq.thymeleaf.models.ModelFinder

import org.thymeleaf.model.IModel
import org.thymeleaf.model.IModelFactory
Expand All @@ -44,11 +43,13 @@ class XmlDocumentDecorator implements Decorator {
}

/**
* {@inheritDoc}
* Decorates the target XML document with the source one.
*
* @param targetDocumentModel
* @param sourceDocumentModel
*/
@Override
void decorate(IModel targetDocumentModel, String targetDocumentTemplate,
IModel sourceDocumentModel, String sourceDocumentTemplate) {
void decorate(IModel targetDocumentModel, IModel sourceDocumentModel) {

// TODO
// Copy text outside of the root element, keeping whitespace copied to a minimum
Expand Down Expand Up @@ -78,7 +79,7 @@ class XmlDocumentDecorator implements Decorator {
return targetDocumentEvent instanceof IOpenElementTag
}

// Bring the decorator into the content page (which is the one being processed)
// Decorate the target document with the source one (which is the one being processed)
new AttributeMerger(modelFactory).merge(targetDocumentRootModel, sourceDocumentModel)
targetDocumentModel.replaceModel(targetDocumentRootModel)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,10 @@ class XmlElementDecorator implements Decorator {
* fragment processors.
*
* @param targetElementModel
* @param targetElementTemplate
* @param sourceElementModel
* @param sourceElementTemplate
*/
@Override
void decorate(IModel targetElementModel, String targetElementTemplate,
IModel sourceElementModel, String sourceElementTemplate) {
void decorate(IModel targetElementModel, IModel sourceElementModel) {

new AttributeMerger(modelFactory).merge(targetElementModel, sourceElementModel)
}
Expand Down

0 comments on commit 86e51d3

Please sign in to comment.