com.xpn.xwiki.render.XWikiVelocityRenderer.java Source code

Java tutorial

Introduction

Here is the source code for com.xpn.xwiki.render.XWikiVelocityRenderer.java

Source

/*
 * See the NOTICE file distributed with this work for additional
 * information regarding copyright ownership.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package com.xpn.xwiki.render;

import java.io.StringWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.lang3.StringUtils;
import org.apache.velocity.VelocityContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.xwiki.velocity.VelocityManager;

import com.xpn.xwiki.XWikiContext;
import com.xpn.xwiki.XWikiException;
import com.xpn.xwiki.api.Document;
import com.xpn.xwiki.doc.XWikiDocument;
import com.xpn.xwiki.util.Util;
import com.xpn.xwiki.web.Utils;

public class XWikiVelocityRenderer implements XWikiRenderer, XWikiInterpreter {
    /** Anything which doesn't contain any of these characters cannot be velocity code */
    private static final String VELOCITY_CHARACTERS = "$#";

    private static final Logger LOGGER = LoggerFactory.getLogger(XWikiVelocityRenderer.class);

    /**
     * {@inheritDoc}
     * 
     * @see XWikiInterpreter#interpret(String,XWikiDocument,XWikiContext)
     */
    public String interpret(String content, XWikiDocument contextdoc, XWikiContext context) {
        return render(content, contextdoc, contextdoc, context);
    }

    /**
     * {@inheritDoc}
     * 
     * @see XWikiRenderer#render(String,XWikiDocument,XWikiDocument,XWikiContext)
     */
    public String render(String content, XWikiDocument contentdoc, XWikiDocument contextdoc, XWikiContext context) {
        // If there are no # or $ characters than the content doesn't contain any velocity code
        // see: http://velocity.apache.org/engine/releases/velocity-1.5/vtl-reference-guide.html
        if (StringUtils.containsNone(content, VELOCITY_CHARACTERS)) {
            return content;
        }
        VelocityManager velocityManager = Utils.getComponent(VelocityManager.class);
        VelocityContext vcontext = velocityManager.getVelocityContext();
        Document previousdoc = (Document) vcontext.get("doc");

        content = context.getUtil().substitute("s/#include\\(/\\\\#include\\(/go", content);

        try {
            vcontext.put("doc", contextdoc.newDocument(context));
            try {
                // We need to do this in case there are any macros in the content
                List<String> macrolist = context.getWiki().getIncludedMacros(contentdoc.getSpace(), content,
                        context);
                if (macrolist != null) {
                    com.xpn.xwiki.XWiki xwiki = context.getWiki();
                    for (String docname : macrolist) {
                        LOGGER.debug(
                                "Pre-including macro topic " + docname + " in context " + contextdoc.getFullName());
                        xwiki.include(docname, true, context);
                    }
                }
            } catch (Exception e) {
                // Make sure we never fail
                LOGGER.warn("Exception while pre-including macro topics", e);
            }

            return evaluate(content, contextdoc.getPrefixedFullName(), vcontext, context);
        } finally {
            if (previousdoc != null) {
                vcontext.put("doc", previousdoc);
            }
        }
    }

    /**
     * {@inheritDoc}
     * 
     * @see com.xpn.xwiki.render.XWikiRenderer#flushCache()
     */
    public void flushCache() {
        // To change body of implemented methods use File | Settings | File Templates.
    }

    public static String evaluate(String content, String name, VelocityContext vcontext, XWikiContext context) {
        StringWriter writer = new StringWriter();
        try {
            VelocityManager velocityManager = Utils.getComponent(VelocityManager.class);
            velocityManager.getVelocityEngine().evaluate(vcontext, writer, name, content);
            return writer.toString();
        } catch (Exception e) {
            e.printStackTrace();
            Object[] args = { name };
            XWikiException xe = new XWikiException(XWikiException.MODULE_XWIKI_RENDERING,
                    XWikiException.ERROR_XWIKI_RENDERING_VELOCITY_EXCEPTION,
                    "Error while parsing velocity page {0}", e, args);
            return Util.getHTMLExceptionMessage(xe, context);
        }
    }

    private void generateFunction(StringBuffer result, String param, String data, XWikiVirtualMacro macro) {
        Map<String, String> namedparams = new HashMap<String, String>();
        List<String> unnamedparams = new ArrayList<String>();
        if ((param != null) && (!param.trim().equals(""))) {
            String[] params = StringUtils.split(param, "|");
            for (int i = 0; i < params.length; i++) {
                String[] rparam = StringUtils.split(params[i], "=");
                if (rparam.length == 1) {
                    unnamedparams.add(params[i]);
                } else {
                    namedparams.put(rparam[0], rparam[1]);
                }
            }
        }

        result.append("#");
        result.append(macro.getFunctionName());
        result.append("(");

        List<String> macroparam = macro.getParams();
        int j = 0;
        for (int i = 0; i < macroparam.size(); i++) {
            String name = macroparam.get(i);
            String value = namedparams.get(name);
            if (value == null) {
                try {
                    value = unnamedparams.get(j);
                    j++;
                } catch (Exception e) {
                    value = "";
                }
            }
            if (i > 0) {
                result.append(" ");
            }
            result.append("\"");
            result.append(value.replaceAll("\"", "\\\\\""));
            result.append("\"");
        }

        if (data != null) {
            result.append(" ");
            result.append("\"");
            result.append(data.replaceAll("\"", "\\\\\""));
            result.append("\"");
        }
        result.append(")");
    }

    private void addVelocityMacros(StringBuffer result, XWikiContext context) {
        Object macroAdded = context.get("velocityMacrosAdded");
        if (macroAdded == null) {
            context.put("velocityMacrosAdded", "1");
            String velocityMacrosDocumentName = context.getWiki().getXWikiPreference("macros_velocity", context);
            if (velocityMacrosDocumentName.trim().length() > 0) {
                try {
                    XWikiDocument doc = context.getWiki().getDocument(velocityMacrosDocumentName, context);
                    result.append(doc.getContent());
                } catch (XWikiException e) {
                    if (LOGGER.isErrorEnabled()) {
                        LOGGER.error("Impossible to load velocity macros doc " + velocityMacrosDocumentName);
                    }
                }
            }
        }
    }

    public String convertSingleLine(String macroname, String param, String allcontent, XWikiVirtualMacro macro,
            XWikiContext context) {
        StringBuffer result = new StringBuffer();
        addVelocityMacros(result, context);
        generateFunction(result, param, null, macro);
        return result.toString();
    }

    public String convertMultiLine(String macroname, String param, String data, String allcontent,
            XWikiVirtualMacro macro, XWikiContext context) {
        StringBuffer result = new StringBuffer();
        addVelocityMacros(result, context);
        generateFunction(result, param, data, macro);
        return result.toString();
    }
}