/* * #%L * Wisdom-Framework * %% * Copyright (C) 2013 - 2014 Wisdom Framework * %% * 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. * #L% */ package org.wisdom.template.thymeleaf.impl; import nz.net.ultraq.thymeleaf.LayoutDialect; import org.thymeleaf.TemplateEngine; import org.thymeleaf.context.Context; import org.thymeleaf.dialect.IDialect; import org.thymeleaf.exceptions.TemplateProcessingException; import org.wisdom.api.Controller; import org.wisdom.api.asset.Assets; import org.wisdom.api.bodies.RenderableString; import org.wisdom.api.http.MimeTypes; import org.wisdom.api.router.Router; import org.wisdom.api.templates.Template; import org.wisdom.template.thymeleaf.dialect.Routes; import org.wisdom.template.thymeleaf.dialect.WisdomStandardDialect; import java.io.StringWriter; import java.util.List; import java.util.Map; import java.util.Set; /** * The main integration point of Thymeleaf in wisdom. */ public class WisdomTemplateEngine extends TemplateEngine { public WisdomTemplateEngine(Set<IDialect> dialects) { super(); // We clear the dialects as we are using our own standard dialect. clearDialects(); addDialect(new WisdomStandardDialect()); addDialect(new LayoutDialect()); if (dialects != null) { setAdditionalDialects(dialects); } } /** * Renders the given template. * <p> * Variables from the session, flash and request parameters are added to the given parameters. * * @param template the template * @param controller the template asking for the rendering * @param router the router service * @param variables the template parameters * @return the rendered HTML page */ public RenderableString process(Template template, Controller controller, Router router, Assets assets, Map<String, Object> variables) { Context ctx = new Context(); // Add session final org.wisdom.api.http.Context http = org.wisdom.api.http.Context.CONTEXT.get(); ctx.setVariables(http.session().getData()); // Add flash ctx.setVariables(http.flash().getCurrentFlashCookieData()); ctx.setVariables(http.flash().getOutgoingFlashCookieData()); // Add parameter from request, flattened for (Map.Entry<String, List<String>> entry : http.parameters().entrySet()) { if (entry.getValue().size() == 1) { ctx.setVariable(entry.getKey(), entry.getValue().get(0)); } else { ctx.setVariable(entry.getKey(), entry.getValue()); } } // Add request scope for (Map.Entry<String, Object> entry : http.request().data().entrySet()) { ctx.setVariable(entry.getKey(), entry.getValue()); } // Add variable. ctx.setVariables(variables); ctx.setVariable(Routes.ROUTES_VAR, new Routes(router, assets, controller)); // This variable let us resolve template using relative path (in the same directory as the current template). // It's mainly used for 'layout', so we can compute the full url. ctx.setVariable("__TEMPLATE__", template); StringWriter writer = new StringWriter(); try { this.process(template.fullName(), ctx, writer); } catch (TemplateProcessingException e) { // If we have a nested cause having a nested cause, heuristics say that it's the useful message. // Rebuild an exception using this data. if (e.getCause() != null && e.getCause().getCause() != null) { throw new TemplateProcessingException(e.getCause().getCause().getMessage(), e.getTemplateName(), e.getLineNumber(), e.getCause().getCause()); } else { throw e; } } return new RenderableString(writer, MimeTypes.HTML); } }