de.thischwa.pmcms.view.renderer.VelocityRenderer.java Source code

Java tutorial

Introduction

Here is the source code for de.thischwa.pmcms.view.renderer.VelocityRenderer.java

Source

/*******************************************************************************
 * Poor Man's CMS (pmcms) - A very basic CMS generating static html pages.
 * http://poormans.sourceforge.net
 * Copyright (C) 2004-2013 by Thilo Schwarz
 * 
 * == BEGIN LICENSE ==
 * 
 * Licensed under the terms of any of the following licenses at your
 * choice:
 * 
 *  - GNU Lesser General Public License Version 2.1 or later (the "LGPL")
 *    http://www.gnu.org/licenses/lgpl.html
 * 
 *  - Mozilla Public License Version 1.1 or later (the "MPL")
 *    http://www.mozilla.org/MPL/MPL-1.1.html
 * 
 * == END LICENSE ==
 ******************************************************************************/
package de.thischwa.pmcms.view.renderer;

import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.apache.velocity.VelocityContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Service;

import de.thischwa.pmcms.Constants;
import de.thischwa.pmcms.conf.InitializationManager;
import de.thischwa.pmcms.exception.FatalException;
import de.thischwa.pmcms.exception.RenderingException;
import de.thischwa.pmcms.livecycle.PojoHelper;
import de.thischwa.pmcms.livecycle.SiteHolder;
import de.thischwa.pmcms.model.IRenderable;
import de.thischwa.pmcms.model.InstanceUtil;
import de.thischwa.pmcms.model.domain.PoInfo;
import de.thischwa.pmcms.model.domain.pojo.APoormansObject;
import de.thischwa.pmcms.model.domain.pojo.ASiteResource;
import de.thischwa.pmcms.model.domain.pojo.Site;
import de.thischwa.pmcms.view.ViewMode;
import de.thischwa.pmcms.view.context.ContextObjectManager;
import de.thischwa.pmcms.view.context.object.ContextTool;
import de.thischwa.pmcms.view.context.object.Utils;
import de.thischwa.pmcms.view.context.object.admin.AdminTool;

/**
 * The velocity rendering methods.
 * 
 * TODO rewrite exception handling. all methods should throw just the RenderingException
 */
@Service()
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
public class VelocityRenderer {
    private static final Logger logger = Logger.getLogger(VelocityRenderer.class);

    @Autowired
    private SiteHolder siteHolder;

    @Value("${baseurl}")
    private String baseUrl;

    /**
     * The main render method. It renders a string with respect of possible context objects.
     * 
     * @param writer
     *            Contains the rendered string. It has to be flushed and closed by the caller!
     * @param stringToRender
     *            A string to render.
     * @param contextObjects
     *            Contains the context objects. It could be null or empty too.
     */
    public void renderString(Writer writer, final String stringToRender, final Map<String, Object> contextObjects) {
        if (StringUtils.isBlank(stringToRender))
            return;

        VelocityContext ctx = new VelocityContext(contextObjects);
        try {
            siteHolder.getVelocityEngine().evaluate(ctx, writer, "StaticRenderfield", stringToRender);
        } catch (Exception e) {
            throw new FatalException("While string rendering: " + e.getMessage(), e);
        }
    }

    /**
     * Renders a string with respect of possible context objects.
     * 
     * @param stringToRender
     *            A string to render.
     * @param contextObjects
     *            Context object. It could be null or empty too.
     * @return The rendered string.
     */
    public String renderString(final String stringToRender, final Map<String, Object> contextObjects) {
        if (StringUtils.isBlank(stringToRender))
            return "";

        StringWriter stringWriter = new StringWriter();
        renderString(stringWriter, stringToRender, contextObjects);
        stringWriter.flush();
        IOUtils.closeQuietly(stringWriter);
        return stringWriter.toString();
    }

    /**
     * Renders an {@link IRenderable} with respect of the {@link ViewMode} and possible context objects into <code>writer</code>.
     * 
     * @param writer
     *            Contains the rendered string. It has to be flushed and closed by the caller!
     * @param renderable
     *            The {@link IRenderable} to render.
     * @param viewMode
     *            The {@link ViewMode} to respect.
     * @param additionalContextObjects
     *            Contains the context objects. It could be null or empty.
     * @throws RenderingException 
     */
    public void render(Writer writer, final IRenderable renderable, final ViewMode viewMode,
            final Map<String, Object> additionalContextObjects) throws RenderingException {
        logger.debug("Try to render: " + renderable);
        PojoHelper pojoHelper = new PojoHelper();
        pojoHelper.putpo((APoormansObject<?>) renderable);
        Site site = pojoHelper.getSite();
        Map<String, Object> contextObjects = ContextObjectManager.get(pojoHelper, viewMode);
        if (logger.isDebugEnabled()) {
            logger.debug("context objects:");
            for (String objName : contextObjects.keySet()) {
                logger.debug(" - Object class: " + objName + " - " + contextObjects.get(objName).getClass());
            }
        }
        if (additionalContextObjects != null && !additionalContextObjects.isEmpty())
            contextObjects.putAll(additionalContextObjects);
        try {
            String templateContent = PoInfo.getTemplateContent(renderable);
            StringWriter contentWriter = new StringWriter();
            renderString(contentWriter, templateContent, contextObjects);

            String layoutContent = site.getLayoutTemplate().getText();
            if (layoutContent != null) {
                contentWriter.flush();
                contextObjects.put("content", contentWriter.toString());
                renderString(writer, layoutContent, contextObjects);
            } else
                writer.write(contentWriter.toString());
        } catch (IOException e) {
            throw new RenderingException(e);
        }
    }

    /**
     * Renders a {@link ASiteResource}.
     * 
     * @param writer Writer where to write out the rendered result.
     * @param siteResource
     *            Must be pre-configured, shouldn't be null!
     * @throws IOException
     */
    public void render(Writer writer, final ASiteResource siteResource) throws IOException {
        logger.debug("Try to render a SiteResource.");

        File editorDir = new File(InitializationManager.getSourceEditorPath());
        Map<String, Object> contextObjects = new HashMap<String, Object>();
        contextObjects.put("admintool", new AdminTool(siteResource));
        contextObjects.put("sr", siteResource);
        contextObjects.put("utils", new Utils());
        contextObjects.put("contexttool", new ContextTool());
        if (siteResource.getId() != APoormansObject.UNSET_VALUE) {
            String link = String.format("%s?id=%d", Constants.LINK_IDENTICATOR_SAVE, siteResource.getId());
            contextObjects.put("link", link);
        }
        if (InstanceUtil.isMacro(siteResource)) {
            contextObjects.put("type", Constants.LINK_TYPE_MACRO);
        } else if (InstanceUtil.isTemplate(siteResource)) {
            contextObjects.put("type", Constants.LINK_TYPE_TEMPLATE);
        } else
            throw new IllegalArgumentException("Unknown type of siteresource!");

        File editor;
        editor = new File(editorDir, "editor.html");
        if (!editor.exists())
            throw new IOException("Didn't find the main source editor file!");
        String templateContent = IOUtils.toString(new BufferedInputStream(new FileInputStream(editor)));
        renderString(writer, templateContent, contextObjects);
    }

    /**
     * A wrapper to {@link #render(Writer, ASiteResource)}.
     */
    public String render(final ASiteResource siteResource) throws RenderingException {
        StringWriter writer = new StringWriter();
        try {
            render(writer, siteResource);
        } catch (IOException e) {
            throw new RenderingException(e);
        }
        return writer.toString();
    }

    /**
     * A wrapper to {@link #render(Writer, IRenderable, ViewMode, Map)}.
     */
    public void render(Writer writer, final IRenderable renderable, final ViewMode viewMode)
            throws RenderingException {
        render(writer, renderable, viewMode, null);
    }

    /**
     * A wrapper to {@link #render(Writer, IRenderable, ViewMode)}
     */
    public String render(final IRenderable renderable, final ViewMode viewMode) throws RenderingException {
        StringWriter writer = new StringWriter();
        render(writer, renderable, viewMode);

        return writer.toString();
    }
}