ninja.rythm.template.TemplateEngineRythm.java Source code

Java tutorial

Introduction

Here is the source code for ninja.rythm.template.TemplateEngineRythm.java

Source

/**
 * Copyright (C) 2013 the original author or authors.
 *
 * 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 ninja.rythm.template;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import ninja.Context;
import ninja.Result;
import ninja.Results;
import ninja.i18n.Lang;
import ninja.i18n.Messages;
import ninja.rythm.exception.NinjaExceptionHandler;
import ninja.rythm.util.RythmConstant;
import ninja.rythm.util.RythmHelper;
import ninja.template.TemplateEngine;
import ninja.template.TemplateEngineManager;
import ninja.utils.NinjaProperties;
import ninja.utils.ResponseStreams;

import org.rythmengine.RythmEngine;
import org.rythmengine.template.ITemplate;
import org.slf4j.Logger;

import com.google.common.base.CaseFormat;
import com.google.common.base.Optional;
import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;

/**
 * 
 * Render Ninja with Rythm template engine (http://rythmengine.org).
 * 
 * @author sojin
 * 
 */

public class TemplateEngineRythm implements TemplateEngine {

    private final String FILE_SUFFIX = ".html";

    private final Messages messages;

    private final Lang lang;

    private final RythmHelper rythmHelper;

    private final NinjaExceptionHandler exceptionHandler;

    private final Logger logger;

    private final RythmEngine engine;

    @Inject
    public TemplateEngineRythm(Messages messages, Lang lang, Logger ninjaLogger,
            NinjaExceptionHandler exceptionHandler, RythmHelper rythmHelper,
            TemplateEngineManager templateEngineManager, NinjaProperties ninjaProperties, RythmEngine engine)
            throws Exception {

        this.messages = messages;
        this.lang = lang;
        this.logger = ninjaLogger;
        this.exceptionHandler = exceptionHandler;
        this.rythmHelper = rythmHelper;
        this.engine = engine;
    }

    @Override
    @SuppressWarnings("unchecked")
    public void invoke(Context context, Result result) {

        Object object = result.getRenderable();

        ResponseStreams responseStreams = context.finalizeHeaders(result);

        Map map;
        // if the object is null we simply render an empty map...
        if (object == null) {
            map = Maps.newHashMap();

        } else if (object instanceof Map) {
            map = (Map) object;

        } else {
            // We are getting an arbitrary Object and put that into
            // the root of rythm

            // If you are rendering something like Results.ok().render(new
            // MyObject())
            // Assume MyObject has a public String name field and
            // a getter getField()
            // You can then access the fields in the template like that:
            // @myObject.getField()
            // You will need to declare the object in the Template file, for eg:
            // @args package.MyObject myObject

            String realClassNameLowerCamelCase = CaseFormat.UPPER_CAMEL.to(CaseFormat.LOWER_CAMEL,
                    object.getClass().getSimpleName());

            map = Maps.newHashMap();
            map.put(realClassNameLowerCamelCase, object);

        }

        // set language from framework. You can access
        // it in the templates as @lang
        Optional<String> language = lang.getLanguage(context, Optional.of(result));
        Map<String, Object> renderArgs = new HashMap<String, Object>();
        if (language.isPresent()) {

            renderArgs.put("lang", language.get());
        }

        // put all entries of the session cookie to the map.
        // You can access the values by their key in the cookie
        // For eg: @session.get("key")
        if (!context.getSessionCookie().isEmpty()) {
            renderArgs.put("session", context.getSessionCookie().getData());
        }

        renderArgs.put("contextPath", context.getContextPath());

        // /////////////////////////////////////////////////////////////////////
        // Convenience method to translate possible flash scope keys.
        // !!! If you want to set messages with placeholders please do that
        // !!! in your controller. We only can set simple messages.
        // Eg. A message like "errorMessage=my name is: {0}" => translate in
        // controller and pass directly.
        // A message like " errorMessage=An error occurred" => use that as
        // errorMessage.
        //
        // get flash values like @flash.get("key")
        // ////////////////////////////////////////////////////////////////////

        Map<String, String> flash = new HashMap<String, String>();

        for (Entry<String, String> entry : context.getFlashCookie().getCurrentFlashCookieData().entrySet()) {

            String messageValue = null;

            Optional<String> messageValueOptional = messages.get(entry.getValue(), context, Optional.of(result));

            if (!messageValueOptional.isPresent()) {
                messageValue = entry.getValue();
            } else {
                messageValue = messageValueOptional.get();
            }

            flash.put(entry.getKey(), messageValue);
        }
        renderArgs.put("flash", flash);

        String templateName = rythmHelper.getRythmTemplateForResult(context.getRoute(), result, FILE_SUFFIX);

        // Specify the data source where the template files come from.
        // Here I set a file directory for it:

        try {
            PrintWriter writer = new PrintWriter(responseStreams.getWriter());

            if (language.isPresent()) {
                // RythmEngine uses ThreadLocal to set the locale, so this
                // setting per request is Thread safe.
                engine.prepare(new Locale(language.get()));
            }
            ITemplate t = engine.getTemplate(templateName, map);
            t.__setRenderArgs(renderArgs);
            String response = t.render();

            if (templateName.equals(response)) {
                handleServerError(context,
                        new Exception("Couldn't locate template " + templateName + " in views."));
            } else {
                writer.println(response);
                writer.flush();
                writer.close();
            }

        } catch (Exception e) {
            handleServerError(context, e);
        }
    }

    private void handleServerError(Context context, Exception e) {
        ResponseStreams outStream = context.finalizeHeaders(Results.internalServerError());
        String response = engine.getTemplate(RythmConstant.LOCATION_VIEW_HTML_INTERNAL_SERVER_ERROR).render();
        exceptionHandler.handleException(e, response, outStream);
    }

    @Override
    public String getContentType() {
        return "text/html";
    }

    @Override
    public String getSuffixOfTemplatingEngine() {
        return FILE_SUFFIX;
    }
}