/*
* Copyright (c) 2014 Thomas Kratz
*
* 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.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.eiswind.magnolia.thymeleaf.renderer;
import de.eiswind.magnolia.thymeleaf.workaraounds.AppendableWriterWrapper;
import info.magnolia.context.MgnlContext;
import info.magnolia.module.blossom.render.RenderContext;
import info.magnolia.objectfactory.Components;
import info.magnolia.rendering.context.RenderingContext;
import info.magnolia.rendering.engine.RenderException;
import info.magnolia.rendering.engine.RenderingEngine;
import info.magnolia.rendering.model.RenderingModel;
import info.magnolia.rendering.renderer.AbstractRenderer;
import info.magnolia.rendering.template.RenderableDefinition;
import info.magnolia.rendering.util.AppendableWriter;
import info.magnolia.templating.functions.TemplatingFunctions;
import info.magnolia.templating.jsp.cmsfn.JspTemplatingFunction;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.servlet.support.RequestContext;
import org.thymeleaf.context.Context;
import org.thymeleaf.spring4.SpringTemplateEngine;
import org.thymeleaf.spring4.naming.SpringContextVariableNames;
import javax.jcr.Node;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
/**
* mgnl renderer for thymeleaf.
*/
public class ThymeleafRenderer extends AbstractRenderer implements ServletContextAware, ApplicationContextAware {
//private final Logger log = LoggerFactory.getLogger(getClass());
private SpringTemplateEngine engine;
private ApplicationContext applicationContext;
private ServletContext servletContext;
/**
* Constructs a Renderer that uses Thymeleaf.
*/
public ThymeleafRenderer() {
super(Components.getComponent(RenderingEngine.class));
}
/**
* {@inheritDoc}
*/
@Override
protected void onRender(Node content, RenderableDefinition definition, RenderingContext renderingCtx,
Map<String, Object> ctx, String templateScript) throws RenderException {
Map<String, Object> vars = new HashMap<>(ctx);
vars.put("content", JspTemplatingFunction.asContentMap(content));
vars.put("cmsfn", Components.getComponent(TemplatingFunctions.class));
final HttpServletRequest request = MgnlContext.getWebContext().getRequest();
final HttpServletResponse response = MgnlContext.getWebContext().getResponse();
// setup spring request context in spring web context
final RequestContext requestContext = new RequestContext(request, response, servletContext, vars);
vars.put(SpringContextVariableNames.SPRING_REQUEST_CONTEXT, requestContext);
// copy all spring model attributes into the spring web context as variables
vars.putAll(RenderContext.get().getModel());
Set<String> selectors = new HashSet<>();
// we mimic the fragment selector syntax here
if (templateScript.contains("::")) {
String[] split = templateScript.split("::");
templateScript = split[0].trim();
selectors.add(split[1].trim());
}
try (AppendableWriter out = renderingCtx.getAppendable()) {
// allow template fragment syntax to be used e.g. template.html :: area
Context context = new Context(MgnlContext.getLocale(), vars);
// and pass the fragment name and spec then onto the engine
engine.process(templateScript, selectors, context, new AppendableWriterWrapper(out));
} catch (IOException x) {
throw new RenderException(x);
}
}
/**
* {@inheritDoc}
*/
@Override
protected Map<String, Object> newContext() {
return new HashMap<String, Object>();
}
/**
* {@inheritDoc}
*/
@Override
protected String resolveTemplateScript(final Node content, final RenderableDefinition definition,
final RenderingModel<?> model, final String actionResult) {
return RenderContext.get().getTemplateScript();
}
public SpringTemplateEngine getEngine() {
return engine;
}
public void setEngine(final SpringTemplateEngine engine1) {
this.engine = engine1;
}
public ServletContext getServletContext() {
return servletContext;
}
public void setServletContext(final ServletContext servletContext1) {
this.servletContext = servletContext1;
}
public ApplicationContext getApplicationContext() {
return applicationContext;
}
public void setApplicationContext(final ApplicationContext applicationContext1) {
this.applicationContext = applicationContext1;
}
}