org.ajax4jsf.templatecompiler.el.ELCompiler.java Source code

Java tutorial

Introduction

Here is the source code for org.ajax4jsf.templatecompiler.el.ELCompiler.java

Source

/**
 * License Agreement.
 *
 * Rich Faces - Natural Ajax for Java Server Faces (JSF)
 *
 * Copyright (C) 2007 Exadel, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License version 2.1 as published by the Free Software Foundation.
 *
 * This library 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 library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 */

package org.ajax4jsf.templatecompiler.el;

import java.beans.PropertyDescriptor;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.el.PropertyNotFoundException;

import org.ajax4jsf.templatecompiler.builder.CompilationContext;
import org.ajax4jsf.templatecompiler.builder.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.sun.el.parser.ArithmeticNode;
import com.sun.el.parser.AstAnd;
import com.sun.el.parser.AstBracketSuffix;
import com.sun.el.parser.AstChoice;
import com.sun.el.parser.AstDeferredExpression;
import com.sun.el.parser.AstDiv;
import com.sun.el.parser.AstDotSuffix;
import com.sun.el.parser.AstEmpty;
import com.sun.el.parser.AstEqual;
import com.sun.el.parser.AstFalse;
import com.sun.el.parser.AstFunction;
import com.sun.el.parser.AstGreaterThan;
import com.sun.el.parser.AstGreaterThanEqual;
import com.sun.el.parser.AstIdentifier;
import com.sun.el.parser.AstInteger;
import com.sun.el.parser.AstLessThan;
import com.sun.el.parser.AstLessThanEqual;
import com.sun.el.parser.AstLiteralExpression;
import com.sun.el.parser.AstMinus;
import com.sun.el.parser.AstMod;
import com.sun.el.parser.AstMult;
import com.sun.el.parser.AstNot;
import com.sun.el.parser.AstNotEqual;
import com.sun.el.parser.AstOr;
import com.sun.el.parser.AstPlus;
import com.sun.el.parser.AstString;
import com.sun.el.parser.AstTrue;
import com.sun.el.parser.AstValue;
import com.sun.el.parser.BooleanNode;
import com.sun.el.parser.ELParser;
import com.sun.el.parser.Node;

/**
 * Compiler EL-expressions.
 * 
 * @author ayukhovich@exadel.com (latest modification by $Author: alexsmirnov $)
 * @version $Revision: 1.1.2.2 $ $Date: 2007/02/21 17:17:12 $
 * 
 */
public class ELCompiler implements IELCompiler {

    private static final Log log = LogFactory.getLog(ELCompiler.class);

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

    static {
    }

    /**
     * 
     */
    public ELCompiler() {
        super();
        resetVariables();
    }

    /**
     * 
     */
    public void resetVariables() {
        // maps.put("context", "javax.faces.context.FacesContext" );
        // maps.put("component", "javax.faces.component.UIComponent" );
        // maps.put("a4jSkin", "org.ajax4jsf.framework.skin.Skin" );

        this.functionsMap.put("a4jSkin:getParameter", "org.ajax4jsf.framework.skin.getParameter");
    }

    public String compileEL(String expression, CompilationContext componentBean) {
        Node node = ELParser.parse(expression);
        StringBuffer sbMain = new StringBuffer();
        processNode(node, sbMain, componentBean);
        return sbMain.toString();
    }

    /**
     * Processing node
     * 
     * @param node
     * @param sbMain
     * @param componentBean
     */
    private void processNode(Node node, StringBuffer sbMain, CompilationContext componentBean) {
        int numChildren = node.jjtGetNumChildren();

        boolean bNeedConversion = false;
        for (int i = 0; i < numChildren; i++) {
            Node childNode = node.jjtGetChild(i);
            if (childNode instanceof AstLiteralExpression) {
                bNeedConversion = true;
                break;
            }
        }

        for (int i = 0; i < numChildren; i++) {
            Node childNode = node.jjtGetChild(i);

            if (childNode instanceof AstLiteralExpression) {
                if (childNode.getImage() != null) {
                    if (i > 0) {
                        sbMain.append(" + ");
                    }
                    sbMain.append("\"");
                    sbMain.append(StringUtils.getEscapedString(childNode.getImage()));
                    sbMain.append("\"");

                    if (i < (numChildren - 1)) {
                        sbMain.append(" + ");
                    }
                }
            } else {
                if (bNeedConversion) {
                    sbMain.append("convertToString(");
                }
                boolean processing = processingNode(childNode, sbMain, componentBean);
                if (!processing) {
                    processNode(childNode, sbMain, componentBean);
                }
                if (bNeedConversion) {
                    sbMain.append(")");
                }
            }

        }
    }

    /**
     * 
     * @param node
     * @param sbMain
     * @param componentBean
     * @param cMain
     * @return
     */
    public boolean processingNode(Node node, StringBuffer sbMain, CompilationContext componentBean) {
        boolean returnValue = false;
        if (node instanceof ArithmeticNode) {
            returnValue = processingArithmeticNode((ArithmeticNode) node, sbMain, componentBean);
        } else if (node instanceof AstIdentifier) {
            returnValue = processingIdentifier((AstIdentifier) node, sbMain, componentBean);
        } else if (node instanceof AstValue) {
            returnValue = processingValue((AstValue) node, sbMain, componentBean);
        } else if (node instanceof AstInteger) {
            returnValue = processingInteger((AstInteger) node, sbMain);
        } else if (node instanceof AstString) {
            returnValue = processingString((AstString) node, sbMain);
        } else if (node instanceof AstFunction) {
            returnValue = processingFunction((AstFunction) node, sbMain, componentBean);
        } else if (node instanceof AstDeferredExpression) {

        } else if (node instanceof BooleanNode) {
            returnValue = processingBooleanNode((BooleanNode) node, sbMain, componentBean);
        } else if (node instanceof AstNot) {
            returnValue = processingNot((AstNot) node, sbMain, componentBean);
        } else if (node instanceof AstChoice) {
            returnValue = processingChoice((AstChoice) node, sbMain, componentBean);
        } else if (node instanceof AstEmpty) {
            returnValue = processingEmpty((AstEmpty) node, sbMain, componentBean);
        } else {
            StringBuffer sb = new StringBuffer();
            sb.append(node.toString());
            sb.append(" (");
            sb.append(node.getClass().getName());
            sb.append(")");
            log.debug(sb.toString());
        }

        return returnValue;
    }

    /**
     * Processing 'empty' node
     * 
     * @param node
     * @param sb
     * @param cMain
     * @return
     */
    private boolean processingEmpty(AstEmpty node, StringBuffer sbMain, CompilationContext componentBean) {
        boolean returnValue = false;
        StringBuffer sb1 = new StringBuffer();

        Node node1 = node.jjtGetChild(0);

        if (null != node1) {
            if (!(returnValue = processingNode(node1, sb1, componentBean))) {
                log.error("Error processing node1: " + node1.getImage());
            }
        }

        if (returnValue) {
            sbMain.append(" isEmpty( ");
            sbMain.append(sb1);
            sbMain.append(" ) ");
        }

        return returnValue;
    }

    /**
     * Processing 'choice' node
     * 
     * @param node
     * @param sb
     * @param cMain
     * @return
     */
    private boolean processingChoice(AstChoice node, StringBuffer sbMain, CompilationContext componentBean) {
        boolean returnValue = true;

        StringBuffer sb1 = new StringBuffer();
        StringBuffer sb2 = new StringBuffer();
        StringBuffer sb3 = new StringBuffer();

        Node node1 = node.jjtGetChild(0);

        if (node1 != null) {
            if (!(returnValue &= processingNode(node1, sb1, componentBean))) {
                log.error("Error processing node1: " + node1.getImage());
            }
        }

        Node node2 = node.jjtGetChild(1);

        if (null != node2) {
            if (!(returnValue &= processingNode(node2, sb2, componentBean))) {
                log.error("Error processing node2: " + node2.getImage());
            }
        }

        Node node3 = node.jjtGetChild(2);

        if (null != node3) {
            if (!(returnValue &= processingNode(node3, sb3, componentBean))) {
                log.error("Error processing node3: " + node3.getImage());
            }
        }

        if (returnValue) {
            sbMain.append(" ( ");
            sbMain.append(sb1);
            sbMain.append(" ? ");
            sbMain.append(sb2);
            sbMain.append(" : ");
            sbMain.append(sb3);
            sbMain.append(" ) ");
        }

        return returnValue;
    }

    /**
     * Processing node containing 'not' expression
     * 
     * @param node
     * @param sb
     * @param cMain
     * @return
     */
    private boolean processingNot(AstNot node, StringBuffer sbMain, CompilationContext componentBean) {
        boolean returnValue = false;
        StringBuffer sb1 = new StringBuffer();

        Node node1 = node.jjtGetChild(0);

        if (null != node1) {
            if (!(returnValue = processingNode(node1, sb1, componentBean))) {
                log.error("Error processing node1: " + node1.getImage());
            }
        }

        if (returnValue) {
            sbMain.append(" ( ! ");
            sbMain.append(sb1);
            sbMain.append(" ) ");
        }

        return returnValue;
    }

    /**
     * Processing boolean node
     * 
     * @param node
     * @param sb
     * @param cMain
     * @return
     */
    private boolean processingBooleanNode(BooleanNode node, StringBuffer sb, CompilationContext componentBean) {
        boolean returnValue = true;

        StringBuffer sb1 = new StringBuffer();
        StringBuffer sb2 = new StringBuffer();

        if (node instanceof AstFalse) {
            sb.append(" false ");
            return returnValue;
        }
        if (node instanceof AstTrue) {
            sb.append(" true ");
            return returnValue;
        }

        Node node1 = node.jjtGetChild(0);

        if (node1 != null) {
            if (!(returnValue &= processingNode(node1, sb1, componentBean))) {
                log.error("Error processing node1: " + node1.getImage());
            }
        }

        Node node2 = node.jjtGetChild(1);

        if (null != node2) {
            if (!(returnValue &= processingNode(node2, sb2, componentBean))) {
                log.error("Error processing node2: " + node2.getImage());
            }
        }

        if (returnValue) {
            sb.append(" ( ");
            sb.append(sb1);

            if (node instanceof AstAnd) {
                sb.append(" && ");
            } else if (node instanceof AstEqual) {
                sb.append(" == ");
            } else if (node instanceof AstGreaterThan) {
                sb.append(" > ");
            } else if (node instanceof AstGreaterThanEqual) {
                sb.append(" >= ");
            } else if (node instanceof AstLessThan) {
                sb.append(" < ");
            } else if (node instanceof AstLessThanEqual) {
                sb.append(" <= ");
            } else if (node instanceof AstNotEqual) {
                sb.append(" != ");
            } else if (node instanceof AstOr) {
                sb.append(" || ");
            }
            sb.append(sb2);
            sb.append(" ) ");
        }

        return returnValue;
    }

    /**
     * Processing arithmetic node
     * 
     * @param node
     * @param sb
     * @param cMain
     * @return
     */
    private boolean processingArithmeticNode(ArithmeticNode node, StringBuffer sb,
            CompilationContext componentBean) {
        StringBuffer sb1 = new StringBuffer();
        StringBuffer sb2 = new StringBuffer();

        boolean returnValue = true;

        Node node1 = node.jjtGetChild(0);

        if (node1 != null) {
            if (!(returnValue &= processingNode(node1, sb1, componentBean))) {
                log.error("Error processing node1: " + node1.getImage());
            }
        }

        Node node2 = node.jjtGetChild(1);

        if (null != node2) {
            if (!(returnValue &= processingNode(node2, sb2, componentBean))) {
                log.error("Error processing node2: " + node2.getImage());
            }
        }

        if (returnValue) {
            sb.append(" ( ");
            sb.append(sb1);

            if (node instanceof AstDiv) {
                sb.append(" / ");
            } else if (node instanceof AstMult) {
                sb.append(" * ");
            } else if (node instanceof AstMod) {
                sb.append(" % ");
            } else if (node instanceof AstPlus) {
                sb.append(" + ");
            } else if (node instanceof AstMinus) {
                sb.append(" - ");
            }

            sb.append(sb2);
            sb.append(" ) ");
        }
        return returnValue;
    }

    /**
     * Processing node contain integer
     * 
     * @param node
     * @param sb
     * @return
     */
    private boolean processingInteger(AstInteger node, StringBuffer sb) {
        sb.append(node.getImage());
        return true;
    }

    /**
     * Processing node contain string
     * 
     * @param node
     * @param sb
     * @return
     */
    private boolean processingString(AstString node, StringBuffer sb) {
        sb.append("\"");
        sb.append(node.getString());
        sb.append("\"");
        return true;
    }

    /**
     * 
     * @param node
     * @param sb
     * @return
     */
    private boolean processingFunction(AstFunction node, StringBuffer sb, CompilationContext componentBean) {

        log.debug("Processing function : " + node.getPrefix());
        log.debug("Processing function : " + node.getLocalName());
        log.debug("Processing function : " + node.getOutputName());

        String prefix = node.getPrefix();
        boolean isThis = prefix.equals("this");
        boolean isUtils = prefix.equals("utils");

        if (isThis || isUtils) {
            if (isUtils) {
                sb.append("getUtils().");
            }

            sb.append(node.getLocalName());
            sb.append("(");
            int numChildren = node.jjtGetNumChildren();
            for (int i = 0; i < numChildren; i++) {
                Node childNode = node.jjtGetChild(i);
                StringBuffer buf = new StringBuffer();
                processingNode(childNode, buf, componentBean);
                if (i != 0) {
                    sb.append(",");
                }
                sb.append(buf);
            }
            sb.append(")");
        } else {
            String functionName = node.getOutputName();
            if (this.functionsMap.containsKey(functionName)) {
                sb.append(this.functionsMap.get(functionName));
                sb.append("(");
                int numChildren = node.jjtGetNumChildren();
                for (int i = 0; i < numChildren; i++) {
                    Node childNode = node.jjtGetChild(i);
                    StringBuffer buf = new StringBuffer();
                    processingNode(childNode, buf, componentBean);
                    if (i != 0) {
                        sb.append(",");
                    }
                    sb.append(buf);
                }
                sb.append(")");
            } // if
        } // else
        return true;
    }

    /**
     * 
     * @param node
     * @param sb
     * @return
     */
    private boolean processingIdentifier(AstIdentifier node, StringBuffer sb, CompilationContext componentBean) {
        String variableName = node.getImage();
        if (componentBean.containsVariable(variableName)) {
            sb.append(variableName);
        } else {
            sb.append("variables.getVariable(\"");
            sb.append(variableName);
            sb.append("\")");
        }

        return true;
    }

    /**
     * 
     * @param basketSuffix
     * @return
     */
    private String processingBracketSuffix(AstBracketSuffix basketSuffix, CompilationContext componentBean) {
        StringBuffer sb = new StringBuffer();
        Node node = basketSuffix.jjtGetChild(0);
        if (node instanceof AstIdentifier) {
            processingIdentifier((AstIdentifier) node, sb, componentBean);
        } else if (node instanceof AstInteger) {
            // sb.append("new Integer(");
            sb.append(node.getImage());
            // sb.append(")");
        } else if (node instanceof AstString) {
            AstString stringNode = (AstString) node;
            sb.append("\"");
            sb.append(stringNode.getString());
            sb.append("\"");
        } else {
            sb.append("\"");
            sb.append(node.getImage());
            sb.append("\"");
        }
        return sb.toString();
    }

    /**
     * 
     * @param clazz
     * @param propertyName
     * @return
     */
    private PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName,
            CompilationContext compilationContext) {
        return compilationContext.getPropertyDescriptor(clazz, propertyName);
    }

    private boolean processingValue(AstValue node, StringBuffer sb, CompilationContext componentBean) {
        String lastIndexValue = "null";
        String lastVariableType = null;
        List<String> names = new ArrayList<String>();

        for (int i = 0; i < node.jjtGetNumChildren(); i++) {
            StringBuffer sb1 = new StringBuffer();
            Node subChild = node.jjtGetChild(i);

            if (subChild instanceof AstIdentifier) {
                String variableName = subChild.getImage();
                if (componentBean.containsVariable(variableName)) {
                    lastVariableType = componentBean.getVariableType(variableName).getName();
                    names.add(variableName);
                } else {
                    processingIdentifier((AstIdentifier) subChild, sb1, componentBean);
                }
            } else if (subChild instanceof AstDotSuffix) {
                String propertyName = subChild.getImage();
                log.debug("Object: " + lastVariableType + ", property: " + propertyName);

                if (lastVariableType != null) {
                    try {

                        Class<?> clazz = componentBean.loadClass(lastVariableType);

                        PropertyDescriptor propertyDescriptor = getPropertyDescriptor(clazz, propertyName,
                                componentBean);

                        if (propertyDescriptor == null) {
                            throw new PropertyNotFoundException(
                                    "property: " + propertyName + " not found in class: " + lastVariableType);
                        }

                        log.debug("propertyObject: " + propertyDescriptor.getPropertyType().getName());
                        StringBuffer tmpbuf = new StringBuffer();
                        tmpbuf.append(propertyDescriptor.getReadMethod().getName());
                        tmpbuf.append("()");
                        names.add(tmpbuf.toString());

                        lastVariableType = propertyDescriptor.getPropertyType().getName();
                    } catch (ClassNotFoundException e) {
                        log.error(e.getLocalizedMessage(), e);
                    }

                } else {

                    sb1.append("getProperty(");
                    sb1.append(lastIndexValue);
                    sb1.append(",");
                    sb1.append("\"");
                    sb1.append(subChild.getImage());
                    sb1.append("\")");
                }
            } else if (subChild instanceof AstBracketSuffix) {
                String bracketSuffix = processingBracketSuffix((AstBracketSuffix) subChild, componentBean);

                if (lastVariableType != null) {
                    StringBuffer tmpbuf = new StringBuffer();
                    if (lastVariableType.startsWith("[L")) {
                        tmpbuf.append("[");
                        tmpbuf.append(bracketSuffix);
                        tmpbuf.append("]");
                        names.add(tmpbuf.toString());
                    }

                    if ((lastVariableType.compareTo("java.util.List") == 0)
                            || (lastVariableType.compareTo("java.util.Map") == 0)) {
                        tmpbuf.append("get(");
                        tmpbuf.append(bracketSuffix);
                        tmpbuf.append(")");
                        names.add(tmpbuf.toString());
                    }
                } else {

                    sb1.append("getElelmentByIndex(");
                    sb1.append(lastIndexValue);
                    sb1.append(",");
                    sb1.append(bracketSuffix);
                    sb1.append(")");
                }

            }

        }

        if (names.size() != 0) {
            StringBuffer tmpbuf = new StringBuffer();
            for (String element : names) {
                if (tmpbuf.length() != 0) {
                    tmpbuf.append(".");
                }
                tmpbuf.append(element);
            }
            sb.append(tmpbuf.toString());
        } else {
            sb.append(lastIndexValue);
        }

        return true;
    }

}