de.knowwe.core.kdom.rendering.RenderResult.java Source code

Java tutorial

Introduction

Here is the source code for de.knowwe.core.kdom.rendering.RenderResult.java

Source

/*
 * Copyright (C) 2010 Chair of Artificial Intelligence and Applied Informatics
 * Computer Science VI, University of Wuerzburg
 * 
 * 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 3 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 de.knowwe.core.kdom.rendering;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang.StringUtils;

import com.denkbares.strings.Strings;
import com.denkbares.utils.Log;
import com.denkbares.utils.Pair;
import de.knowwe.core.kdom.parsing.Section;
import de.knowwe.core.user.UserContext;
import de.knowwe.core.utils.KnowWEUtils;
import de.knowwe.kdom.filter.SectionFilter;

public class RenderResult {

    private static final String storeKey = RenderResult.class.getName();
    private static final String[] HTML = new String[] { "[{", "}]", "\"", "'", ">", "<", "[", "]" };

    private final String maskKey;
    private final String[] maskedHtml;
    private final StringBuilder builder = new StringBuilder();

    private List<Pair<SectionFilter, Renderer>> customRenderers = Collections.emptyList();

    public RenderResult(UserContext context) {
        this(context.getRequest());
    }

    public RenderResult(HttpServletRequest request) {
        this.maskKey = createMaskKey(request);
        this.maskedHtml = createMaskHtml(maskKey);
    }

    /**
     * Creates a new {@link RenderResult} using the same masking key as the given parent.<br>
     * <b>Attention: </b> The newly instantiated {@link RenderResult} will not contain any content
     * of the given parent {@link RenderResult}. The parent is only needed for the masking key.
     *
     * @param parent the parent needed for using the same masking key
     */
    public RenderResult(RenderResult parent) {
        this.maskKey = parent.maskKey;
        this.maskedHtml = parent.maskedHtml; // NOSONAR
        this.customRenderers = parent.customRenderers;
    }

    public void addCustomRenderer(SectionFilter filter, Renderer renderer) {
        List<Pair<SectionFilter, Renderer>> newList = new ArrayList<>(customRenderers.size() + 1);
        newList.add(0, new Pair<>(filter, renderer));
        newList.addAll(customRenderers);
        customRenderers = newList;
    }

    private static String createMaskKey(HttpServletRequest request) {
        Object storedMaskKey = request.getAttribute(storeKey);
        if (storedMaskKey != null)
            return (String) storedMaskKey;

        int rnd = Math.abs(new Random().nextInt());
        String maskKey = Integer.toString(rnd, Character.MAX_RADIX);
        request.setAttribute(storeKey, maskKey);
        return maskKey;
    }

    private static String[] createMaskHtml(String maskKey) {
        String[] maskedHtml = new String[HTML.length];
        for (int i = 0; i < HTML.length; i++) {
            maskedHtml[i] = "@@" + maskKey + "_" + i + "@@";
        }
        return maskedHtml;
    }

    public RenderResult append(boolean bool) {
        builder.append(bool);
        return this;
    }

    public RenderResult append(char c) {
        builder.append(c);
        return this;
    }

    public RenderResult append(char[] str) {
        builder.append(str);
        return this;
    }

    public RenderResult append(char[] str, int offset, int len) {
        builder.append(str, offset, len);
        return this;
    }

    public RenderResult append(CharSequence str) {
        builder.append(str);
        return this;
    }

    public RenderResult append(CharSequence str, int start, int end) {
        builder.append(str, start, end);
        return this;
    }

    public RenderResult append(double d) {
        builder.append(d);
        return this;
    }

    public RenderResult append(float f) {
        builder.append(f);
        return this;
    }

    public RenderResult append(int i) {
        builder.append(i);
        return this;
    }

    public RenderResult append(long l) {
        builder.append(l);
        return this;
    }

    public RenderResult append(Object object) {
        builder.append(object);
        return this;
    }

    public RenderResult append(RenderResult result) {
        builder.append(result.builder);
        return this;
    }

    /**
     * Appends the section to this render result. The section is rendered by using the sections
     * defined renderer. The method is a common shortcut for <code>DelegateRenderer.getRenderer(section,
     * user).render(section, user, result)</code>. The method is null-secure for the section. If
     * null is specified as the section, nothing is rendered.
     * <p>
     * This method additionally consider custom renderer that has previously been set to overwrite
     * the default rendering behaviour.
     *
     * @param section the section to be rendered
     * @return this render result
     * @created 15.02.2014
     */
    public RenderResult append(Section<?> section, UserContext user) {
        if (section != null) {
            Renderer renderer = DelegateRenderer.getRenderer(section, user);
            for (Pair<SectionFilter, Renderer> pair : customRenderers) {
                if (pair.getA().accept(section)) {
                    renderer = pair.getB();
                    break;
                }
            }
            renderer.render(section, user, this);
        }
        return this;
    }

    public RenderResult appendAvoidParagraphs(RenderResult result) {
        String raw = result.builder.toString();
        raw = raw.replaceAll("\n\n", "\n \n");
        builder.append(raw);
        return this;
    }

    public RenderResult append(String text) {
        builder.append(text);
        return this;
    }

    public RenderResult appendHtml(RenderResult html) {
        builder.append(mask(html.toStringRaw()));
        return this;
    }

    public RenderResult appendHtml(String html) {
        builder.append(mask(html));
        return this;
    }

    /**
     * Appends the specified string encoded as html entities, using {@link
     * Strings#encodeHtml(String)}.
     *
     * @param text the text to be appended
     * @return a reference to this object.
     * @created 20.08.2013
     */
    public RenderResult appendEntityEncoded(String text) {
        builder.append(Strings.encodeHtml(text));
        return this;
    }

    public RenderResult appendJSPWikiMarkup(RenderResult result) {
        StringBuilder tempBuilder = new StringBuilder(result.builder);
        KnowWEUtils.maskJSPWikiMarkup(tempBuilder);
        builder.append(tempBuilder);
        return this;
    }

    public RenderResult appendJSPWikiMarkup(String markup) {
        builder.append(KnowWEUtils.maskJSPWikiMarkup(markup));
        return this;
    }

    public char charAt(int arg0) {
        return builder.charAt(arg0);
    }

    public RenderResult delete(int start, int end) {
        builder.delete(start, end);
        return this;
    }

    public RenderResult deleteCharAt(int index) {
        builder.deleteCharAt(index);
        return this;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj instanceof RenderResult) {
            return builder.equals(((RenderResult) obj).builder);
        }
        return builder.equals(obj);
    }

    @Override
    public int hashCode() {
        return builder.hashCode();
    }

    public int indexOf(String str) {
        return builder.indexOf(str);
    }

    public int indexOf(String str, int fromIndex) {
        return builder.indexOf(str, fromIndex);
    }

    public RenderResult insert(int offset, boolean b) {
        builder.insert(offset, b);
        return this;
    }

    public RenderResult insert(int offset, char c) {
        builder.insert(offset, c);
        return this;
    }

    public RenderResult insert(int offset, char[] str) {
        builder.insert(offset, str);
        return this;
    }

    public RenderResult insert(int index, char[] str, int offset, int len) {
        builder.insert(index, str, offset, len);
        return this;
    }

    public RenderResult insert(int dstOffset, CharSequence s) {
        builder.insert(dstOffset, s);
        return this;
    }

    public RenderResult insert(int dstOffset, CharSequence s, int start, int end) {
        builder.insert(dstOffset, s, start, end);
        return this;
    }

    public RenderResult insert(int offset, double d) {
        builder.insert(offset, d);
        return this;
    }

    public RenderResult insert(int offset, float f) {
        builder.insert(offset, f);
        return this;
    }

    public RenderResult insert(int offset, int i) {
        builder.insert(offset, i);
        return this;
    }

    public RenderResult insert(int offset, long l) {
        builder.insert(offset, l);
        return this;
    }

    public RenderResult insert(int offset, Object obj) {
        builder.insert(offset, obj);
        return this;
    }

    public RenderResult insert(int offset, String str) {
        builder.insert(offset, str);
        return this;
    }

    public int lastIndexOf(String str) {
        return builder.lastIndexOf(str);
    }

    public int lastIndexOf(String str, int fromIndex) {
        return builder.lastIndexOf(str, fromIndex);
    }

    public int length() {
        return builder.length();
    }

    private String mask(String html) {
        for (int i = 0; i < HTML.length; i++) {
            // somehow this is way faster for large strings than
            // StringUtils.replaceEach(String, String[], String[]).
            html = StringUtils.replace(html, HTML[i], maskedHtml[i]);
        }
        return html;
    }

    public static String mask(String string, UserContext context) {
        RenderResult renderResult = new RenderResult(context);
        return renderResult.mask(string);
    }

    public static String mask(String string, RenderResult parent) {
        RenderResult renderResult = new RenderResult(parent);
        return renderResult.mask(string);
    }

    public static String mask(String string, HttpServletRequest request) {
        RenderResult renderResult = new RenderResult(request);
        return renderResult.mask(string);
    }

    public RenderResult replace(int start, int end, String str) {
        builder.replace(start, end, str);
        return this;
    }

    public CharSequence subSequence(int arg0, int arg1) {
        return builder.subSequence(arg0, arg1);
    }

    public String substring(int arg0) {
        return builder.substring(arg0);
    }

    public String substring(int arg0, int arg1) {
        return builder.substring(arg0, arg1);
    }

    /**
     * Returns the <b>unmasked</b> String of this {@link RenderResult}.
     * <p>
     * <b>Attention:</b> Do not use this method for append this {@link RenderResult} to another.
     * There are two other methods allowing this: {@link RenderResult#toStringRaw()} and {@link
     * RenderResult#append(RenderResult)}.
     */
    @Override
    public String toString() {
        return unmask(builder.toString());
    }

    /**
     * Returns the still masked string of this {@link RenderResult}.
     *
     * @return the still masked string of this {@link RenderResult}
     * @created 11.02.2013
     */
    public String toStringRaw() {
        return builder.toString();
    }

    private String unmask(String string) {
        for (int i = 0; i < maskedHtml.length; i++) {
            // somehow this is way faster for large strings than
            // StringUtils.replaceEach(String, String[], String[]).
            string = StringUtils.replace(string, maskedHtml[i], HTML[i]);
        }
        return string;
    }

    public static String unmask(String string, UserContext context) {
        RenderResult renderResult = new RenderResult(context);
        return renderResult.unmask(string);
    }

    public static String unmask(String string, RenderResult parent) {
        RenderResult renderResult = new RenderResult(parent);
        return renderResult.unmask(string);
    }

    public static String unmask(String string, HttpServletRequest request) {
        RenderResult renderResult = new RenderResult(request);
        return renderResult.unmask(string);
    }

    /**
     * Appends an opening and masked HTML element without having to fiddle with strings and quoting.
     * Just set tag name and the attributes. Attributes need to be given in pairs. First the name of
     * the attribute, second the content of the attribute.
     *
     * @param tag        the tag name of the HTML element
     * @param attributes the attributes of the HTML element: the odd elements are the attribute
     *                   names and the even elements the attribute contents
     * @created 05.02.2013
     */
    public void appendHtmlTag(String tag, String... attributes) {
        appendHtmlTag(tag, true, attributes);
    }

    /**
     * Appends an opening and masked HTML element without having to fiddle with strings and quoting.
     * Just set tag name and the attributes. Attributes need to be given in pairs. First the name of
     * the attribute, second the content of the attribute.
     *
     * @param tag        the tag name of the HTML element
     * @param encode     decides whether the attributes will be html encoded or not
     * @param attributes the attributes of the HTML element: the odd elements are the attribute
     *                   names and the even elements the attribute contents
     * @created 05.02.2013
     */
    public RenderResult appendHtmlTag(String tag, boolean encode, String... attributes) {
        StringBuilder html = new StringBuilder();
        html.append("<").append(tag);
        for (int i = 0; i + 2 <= attributes.length; i += 2) {
            String attributeName = attributes[i];
            String attributeValue = attributes[i + 1];
            if (attributeName == null)
                continue;
            if (attributeValue == null)
                continue;
            html.append(getAttribute(encode, attributeName, attributeValue));
        }
        html.append(">");
        appendHtml(html.toString());
        return this;
    }

    private static String getAttribute(boolean encode, String attributeName, String attribute) {
        return " " + attributeName + "=\"" + (encode ? Strings.encodeHtml(attribute) : attribute) + "\"";
    }

    /**
     * Appends a complete and masked HTML element without having to fiddle with strings and quoting.
     * Just set tag name, content and the attributes. Attributes need to be given in pairs. First
     * the name of the attribute, second the content of the attribute.
     *
     * @param tag        the tag name of the HTML element
     * @param content    the content of the HTML element
     * @param attributes the attributes of the HTML element: the odd elements are the attribute
     *                   names and the even elements the attribute contents
     * @created 05.02.2013
     */
    public RenderResult appendHtmlElement(String tag, String content, String... attributes) {
        if (tag.equals("img") && Strings.isBlank(content)) {
            appendHtmlTag(tag, attributes);
        } else {
            appendHtmlTag(tag, attributes);
            append(content);
            appendHtml("</" + tag + ">");
        }
        return this;
    }

    public RenderResult appendException(String message, Throwable e) {
        appendHtmlElement("span", message, "class", "error");
        Log.severe(message, e);
        return this;
    }

    public RenderResult appendException(Throwable e) {
        appendException("Exception while rendering: " + e.getClass().getSimpleName()
                + (e.getMessage() == null ? "" : ": " + e.getMessage()), e);
        return this;
    }
}