org.beangle.struts2.view.component.Component.java Source code

Java tutorial

Introduction

Here is the source code for org.beangle.struts2.view.component.Component.java

Source

/* Copyright c 2005-2012.
 * Licensed under GNU  LESSER General Public License, Version 3.
 * http://www.gnu.org/licenses
 */
package org.beangle.struts2.view.component;

import java.io.IOException;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Stack;

import org.apache.commons.lang.StringUtils;
import org.apache.struts2.ServletActionContext;
import org.apache.struts2.StrutsException;
import org.apache.struts2.util.FastByteArrayOutputStream;
import org.apache.struts2.views.util.ContextUtil;
import org.springframework.context.ApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import com.opensymphony.xwork2.util.TextParseUtil;
import com.opensymphony.xwork2.util.ValueStack;

/**
 * <li>remove actionMapper\determineActionURL\determineNamespace</li> <li>remove
 * copy parameter</li>
 * 
 * @author chaostone
 */
public class Component {
    public static final String COMPONENT_STACK = "b__component_stack";
    protected ValueStack stack;
    protected Map<String, Object> parameters;

    /**
     * Constructor.
     * 
     * @param stack
     *            OGNL value stack.
     */
    public Component(ValueStack stack) {
        this.stack = stack;
        this.parameters = new LinkedHashMap<String, Object>();
        getComponentStack().push(this);
    }

    /**
     * Gets the name of this component.
     * 
     * @return the name of this component.
     */
    private String getComponentName() {
        Class<?> c = getClass();
        String name = c.getName();
        int dot = name.lastIndexOf('.');
        return name.substring(dot + 1).toLowerCase();
    }

    /**
     * Gets the component stack of this component.
     * 
     * @return the component stack of this component, never <tt>null</tt>.
     */
    protected Stack<Component> getComponentStack() {
        @SuppressWarnings("unchecked")
        Stack<Component> componentStack = (Stack<Component>) stack.getContext().get(COMPONENT_STACK);
        if (componentStack == null) {
            componentStack = new Stack<Component>();
            stack.getContext().put(COMPONENT_STACK, componentStack);
        }
        return componentStack;
    }

    /**
     * Callback for the start tag of this component. Should the body be
     * evaluated?
     * 
     * @param writer
     *            the output writer.
     * @return true if the body should be evaluated
     */
    public boolean start(Writer writer) {
        return true;
    }

    /**
     * Callback for the end tag of this component. Should the body be evaluated
     * again?
     * <p/>
     * <b>NOTE:</b> will pop component stack.
     * 
     * @param writer
     *            the output writer.
     * @param body
     *            the rendered body.
     * @return true if the body should be evaluated again
     */
    public boolean end(Writer writer, String body) {
        return end(writer, body, true);
    }

    /**
     * Callback for the start tag of this component. Should the body be
     * evaluated again?
     * <p/>
     * <b>NOTE:</b> has a parameter to determine to pop the component stack.
     * 
     * @param writer
     *            the output writer.
     * @param body
     *            the rendered body.
     * @param popComponentStack
     *            should the component stack be popped?
     * @return true if the body should be evaluated again
     */
    protected boolean end(Writer writer, String body, boolean popComponentStack) {
        assert (body != null);

        try {
            writer.write(body);
        } catch (IOException e) {
            throw new StrutsException("IOError while writing the body: " + e.getMessage(), e);
        }
        if (popComponentStack) {
            popComponentStack();
        }
        return false;
    }

    /**
     * Pops the component stack.
     */
    protected void popComponentStack() {
        getComponentStack().pop();
    }

    /**
     * Finds the nearest ancestor of this component stack.
     * 
     * @param clazz
     *            the class to look for, or if assignable from.
     * @return the component if found, <tt>null</tt> if not.
     */
    @SuppressWarnings("unchecked")
    protected <T extends Component> T findAncestor(Class<T> clazz) {
        Stack<? extends Component> componentStack = getComponentStack();
        int currPosition = componentStack.search(this);
        if (currPosition >= 0) {
            int start = componentStack.size() - currPosition - 1;
            // for (int i = componentStack.size() - 2; i >= 0; i--) {
            for (int i = start; i >= 0; i--) {
                Component component = componentStack.get(i);
                if (clazz.isAssignableFrom(component.getClass()) && component != this) {
                    return (T) component;
                }
            }
        }

        return null;
    }

    /**
     * Evaluates the OGNL stack to find a String value.
     * 
     * @param expr
     *            OGNL expression.
     * @return the String value found.
     */
    protected String findString(String expr) {
        return (String) findValue(expr, String.class);
    }

    /**
     * Evaluates the OGNL stack to find a String value.
     * <p/>
     * If the given expression is <tt>null</tt/> a error is logged and a
     * <code>RuntimeException</code> is thrown constructed with a messaged based
     * on the given field and errorMsg paramter.
     * 
     * @param expr
     *            OGNL expression.
     * @param field
     *            field name used when throwing <code>RuntimeException</code>.
     * @param errorMsg
     *            error message used when throwing <code>RuntimeException</code>
     *            .
     * @return the String value found.
     * @throws StrutsException
     *             is thrown in case of expression is <tt>null</tt>.
     */
    protected String findString(String expr, String field, String errorMsg) {
        if (expr == null) {
            throw fieldError(field, errorMsg, null);
        } else {
            return findString(expr);
        }
    }

    /**
     * Constructs a <code>RuntimeException</code> based on the given
     * information.
     * <p/>
     * A message is constructed and logged at ERROR level before being returned
     * as a <code>RuntimeException</code>.
     * 
     * @param field
     *            field name used when throwing <code>RuntimeException</code>.
     * @param errorMsg
     *            error message used when throwing <code>RuntimeException</code>
     *            .
     * @param e
     *            the caused exception, can be <tt>null</tt>.
     * @return the constructed <code>StrutsException</code>.
     */
    protected StrutsException fieldError(String field, String errorMsg, Exception e) {
        String msg = "tag '" + getComponentName() + "', field '" + field
                + (parameters != null && parameters.containsKey("name") ? "', name '" + parameters.get("name") : "")
                + "': " + errorMsg;
        throw new StrutsException(msg, e);
    }

    /**
     * Finds a value from the OGNL stack based on the given expression. Will
     * always evaluate <code>expr</code> against stack except when
     * <code>expr</code> is null. If altsyntax (%{...}) is applied, simply strip
     * it off.
     * 
     * @param expr
     *            the expression. Returns <tt>null</tt> if expr is null.
     * @return the value, <tt>null</tt> if not found.
     */
    protected Object findValue(String expr) {
        if (expr == null) {
            return null;
        }
        expr = stripExpressionIfAltSyntax(expr);
        return stack.findValue(expr, false);
    }

    /**
     * If altsyntax (%{...}) is applied, simply strip the "%{" and "}" off.
     * 
     * @param expr
     *            the expression (must be not null)
     * @return the stripped expression if altSyntax is enabled. Otherwise the
     *         parameter expression is returned as is.
     */
    protected String stripExpressionIfAltSyntax(String expr) {
        return stripExpressionIfAltSyntax(stack, expr);
    }

    /**
     * If altsyntax (%{...}) is applied, simply strip the "%{" and "}" off.
     * 
     * @param stack
     *            the ValueStack where the context value is searched for.
     * @param expr
     *            the expression (must be not null)
     * @return the stripped expression if altSyntax is enabled. Otherwise the
     *         parameter expression is returned as is.
     */
    public static String stripExpressionIfAltSyntax(ValueStack stack, String expr) {
        if (altSyntax(stack)) {
            // does the expression start with %{ and end with }? if so, just cut
            // it off!
            if (expr.startsWith("%{") && expr.endsWith("}")) {
                return expr.substring(2, expr.length() - 1);
            }
        }
        return expr;
    }

    /**
     * Is the altSyntax enabled? [TRUE]
     * <p/>
     * 
     * @param stack
     *            the ValueStack where the context value is searched for.
     * @return true if altSyntax is activated. False otherwise. See
     *         <code>struts.properties</code> where the altSyntax flag is
     *         defined.
     */
    public static boolean altSyntax(ValueStack stack) {
        return ContextUtil.isUseAltSyntax(stack.getContext());
    }

    /**
     * Is the altSyntax enabled? [TRUE]
     * <p/>
     * See <code>struts.properties</code> where the altSyntax flag is defined.
     */
    public boolean altSyntax() {
        return altSyntax(stack);
    }

    /**
     * Adds the sorrounding %{ } to the expression for proper processing.
     * 
     * @param expr
     *            the expression.
     * @return the modified expression if altSyntax is enabled, or the parameter
     *         expression otherwise.
     */
    protected String completeExpressionIfAltSyntax(String expr) {
        if (altSyntax()) {
            return "%{" + expr + "}";
        }
        return expr;
    }

    /**
     * This check is needed for backwards compatibility with 2.1.x
     * 
     * @param expr
     *            the expression.
     * @return the found string if altSyntax is enabled. The parameter
     *         expression otherwise.
     */
    protected String findStringIfAltSyntax(String expr) {
        if (altSyntax()) {
            return findString(expr);
        }
        return expr;
    }

    /**
     * Evaluates the OGNL stack to find an Object value.
     * <p/>
     * Function just like <code>findValue(String)</code> except that if the
     * given expression is <tt>null</tt/> a error is logged and a
     * <code>RuntimeException</code> is thrown constructed with a messaged based
     * on the given field and errorMsg paramter.
     * 
     * @param expr
     *            OGNL expression.
     * @param field
     *            field name used when throwing <code>RuntimeException</code>.
     * @param errorMsg
     *            error message used when throwing <code>RuntimeException</code>
     *            .
     * @return the Object found, is never <tt>null</tt>.
     * @throws StrutsException
     *             is thrown in case of not found in the OGNL stack, or
     *             expression is <tt>null</tt>.
     */
    protected Object findValue(String expr, String field, String errorMsg) {
        if (expr == null) {
            throw fieldError(field, errorMsg, null);
        } else {
            Object value = null;
            Exception problem = null;
            try {
                value = findValue(expr);
            } catch (Exception e) {
                problem = e;
            }

            if (value == null) {
                throw fieldError(field, errorMsg, problem);
            }

            return value;
        }
    }

    /**
     * Evaluates the OGNL stack to find an Object of the given type. Will
     * evaluate <code>expr</code> the portion wrapped with altSyntax (%{...})
     * against stack when altSyntax is on, else the whole <code>expr</code> is
     * evaluated against the stack.
     * <p/>
     * This method only supports the altSyntax. So this should be set to true.
     * 
     * @param expr
     *            OGNL expression.
     * @param toType
     *            the type expected to find.
     * @return the Object found, or <tt>null</tt> if not found.
     */
    protected Object findValue(String expr, Class<?> toType) {
        if (altSyntax() && toType == String.class) {
            return TextParseUtil.translateVariables('%', expr, stack);
        } else {
            expr = stripExpressionIfAltSyntax(expr);
            return stack.findValue(expr, toType, false);
        }
    }

    /**
     * Constructs a string representation of the given exception.
     * 
     * @param t
     *            the exception
     * @return the exception as a string.
     */
    protected String toString(Throwable t) {
        FastByteArrayOutputStream bout = new FastByteArrayOutputStream();
        PrintWriter wrt = new PrintWriter(bout);
        t.printStackTrace(wrt);
        wrt.close();
        return bout.toString();
    }

    /**
     * Gets the parameters.
     * 
     * @return the parameters. Is never <tt>null</tt>.
     */
    public Map<String, Object> getParameters() {
        return parameters;
    }

    /**
     * Adds all the given parameters to this component's own parameters.
     * 
     * @param params
     *            the parameters to add.
     */
    public void addAllParameters(Map<String, Object> params) {
        parameters.putAll(params);
    }

    /**
     * Adds the given key and value to this component's own parameter.
     * <p/>
     * If the provided key is <tt>null</tt> nothing happens. If the provided
     * value is <tt>null</tt> any existing parameter with the given key name is
     * removed.
     * 
     * @param key
     *            the key of the new parameter to add.
     * @param value
     *            the value assoicated with the key.
     */
    public void addParameter(String key, Object value) {
        if (key != null) {
            Map<String, Object> params = getParameters();
            if (value == null) {
                params.remove(key);
            } else {
                params.put(key, value);
            }
        }
    }

    /**
     * Overwrite to set if body shold be used.
     * 
     * @return always false for this component.
     */
    public boolean usesBody() {
        return false;
    }

    public <T> T getBean(Class<T> cls) {
        try {
            ApplicationContext ctx = WebApplicationContextUtils
                    .getWebApplicationContext(ServletActionContext.getServletContext());
            String name = StringUtils.uncapitalize(StringUtils.substringAfterLast(cls.getName(), "."));
            @SuppressWarnings("unchecked")
            T t = (T) ctx.getBean(name);
            return t;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}