All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.richfaces.cdk.templatecompiler.el.ELVisitor Maven / Gradle / Ivy

The newest version!
/**
 * 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.richfaces.cdk.templatecompiler.el;

import static org.richfaces.cdk.templatecompiler.statements.HelperMethod.TO_STRING_CONVERSION;
import static org.richfaces.cdk.util.JavaUtils.getEscapedString;

import java.text.MessageFormat;
import java.util.Collections;
import java.util.EnumSet;
import java.util.Set;

import org.jboss.el.parser.AstAnd;
import org.jboss.el.parser.AstBracketSuffix;
import org.jboss.el.parser.AstChoice;
import org.jboss.el.parser.AstCompositeExpression;
import org.jboss.el.parser.AstDeferredExpression;
import org.jboss.el.parser.AstDiv;
import org.jboss.el.parser.AstDynamicExpression;
import org.jboss.el.parser.AstEmpty;
import org.jboss.el.parser.AstEqual;
import org.jboss.el.parser.AstFalse;
import org.jboss.el.parser.AstFloatingPoint;
import org.jboss.el.parser.AstFunction;
import org.jboss.el.parser.AstGreaterThan;
import org.jboss.el.parser.AstGreaterThanEqual;
import org.jboss.el.parser.AstIdentifier;
import org.jboss.el.parser.AstInteger;
import org.jboss.el.parser.AstLessThan;
import org.jboss.el.parser.AstLessThanEqual;
import org.jboss.el.parser.AstLiteralExpression;
import org.jboss.el.parser.AstMethodSuffix;
import org.jboss.el.parser.AstMinus;
import org.jboss.el.parser.AstMod;
import org.jboss.el.parser.AstMult;
import org.jboss.el.parser.AstNegative;
import org.jboss.el.parser.AstNot;
import org.jboss.el.parser.AstNotEqual;
import org.jboss.el.parser.AstNull;
import org.jboss.el.parser.AstOr;
import org.jboss.el.parser.AstPlus;
import org.jboss.el.parser.AstPropertySuffix;
import org.jboss.el.parser.AstString;
import org.jboss.el.parser.AstTrue;
import org.jboss.el.parser.AstValue;
import org.jboss.el.parser.ELParser;
import org.jboss.el.parser.Node;
import org.richfaces.cdk.Logger;
import org.richfaces.cdk.templatecompiler.builder.model.JavaField;
import org.richfaces.cdk.templatecompiler.builder.model.JavaImport;
import org.richfaces.cdk.templatecompiler.builder.model.Variables;
import org.richfaces.cdk.templatecompiler.el.node.AstBracketSuffixTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstChoiceTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstCompositeComponentAttributesTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstCompositeComponentTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstDeferredOrDynamicExpressionTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstEmptyTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstFloatingPointTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstFunctionTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstIdentifierTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstIntegerTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstLiteralTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstMethodSuffixTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstNegativeTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstNotTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstPropertySuffixTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstStringTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.AstValueTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.BinaryArithmeticIntegerOperationTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.BinaryArithmeticOperationTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.BinaryBooleanOperationTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.BinaryBooleanResultOperationTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.ConstantValueTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.EqualityTestTreeNode;
import org.richfaces.cdk.templatecompiler.el.node.ITreeNode;
import org.richfaces.cdk.templatecompiler.el.types.ELPropertyDescriptor;
import org.richfaces.cdk.templatecompiler.el.types.ELType;
import org.richfaces.cdk.templatecompiler.el.types.TypesFactory;
import org.richfaces.cdk.templatecompiler.statements.HelperMethod;
import org.richfaces.cdk.templatecompiler.statements.StatementsContainer;
import org.richfaces.cdk.templatecompiler.statements.TypedTemplateStatement;

/**
 * Entry point for parsing EL expressions. @see parse() method.
 *
 * @author amarkhel
 */
public final class ELVisitor implements TypedTemplateStatement {
    private String parsedExpression = null;
    private ELType expressionType = null;
    private Variables variables = null;
    private Set usedHelperMethods = EnumSet.noneOf(HelperMethod.class);
    private final Logger log;
    private final TypesFactory typesFactory;
    private boolean mixedExpression;
    private boolean literal = true;
    private StatementsContainer parent;

    public ELVisitor(Logger log, TypesFactory typesFactory) {
        this.log = log;
        this.typesFactory = typesFactory;
    }

    public boolean isMixedExpression() {
        return mixedExpression;
    }

    /**
     * 

*

* * @return the literal */ @Override public boolean isLiteral() { return this.literal; } /** *

*

* * @param literal the literal to set */ public void setLiteral(boolean literal) { this.literal = literal; } public ELType getType() { return expressionType; } public void setExpressionType(ELType variableType) { this.expressionType = variableType; } public ELType getVariable(String name) throws ParsingException { ELType variableType; if (variables.isDefined(name)) { variableType = variables.getVariable(name); } else { log.warn(MessageFormat.format("No type found in context for identifier ''{0}'', handling as generic Object", name)); variableType = TypesFactory.OBJECT_TYPE; } return variableType; } /** * Parse specified EL expression and return Java code, that represent this expression * * @param expression - expression to resolve * @param contextVariables - Map<String, Class<?>> - context for search classes. * * @throws ParsingException - if error occurred during parsing. */ public void parse(String expression, Variables contextVariables, ELType expectedType) throws ParsingException { reset(); Node ret = ELParser.parse(expression); variables = contextVariables; if (ret instanceof AstCompositeExpression && ret.jjtGetNumChildren() >= 2) { // AstCompositeExpression with 2+ children is a mixed expression usedHelperMethods.add(TO_STRING_CONVERSION); this.mixedExpression = true; this.literal = false; } if (ret != null && ret.jjtGetNumChildren() > 0) { parsedExpression = this.visit(ret); } else { parsedExpression = getEscapedString(""); expressionType = TypesFactory.STRING_TYPE; } parsedExpression = coerceToType(parsedExpression, expectedType); } public String coerceToType(String valueString, ELType expectedType) { if (!expectedType.isAssignableFrom(getType())) { for (HelperMethod conversionMethod : HelperMethod.getConversionMethods()) { ELType returnType = typesFactory.getType(conversionMethod.getReturnType()); if (expectedType.isAssignableFrom(returnType)) { usedHelperMethods.add(conversionMethod); setExpressionType(returnType); return conversionMethod.getName() + "(" + valueString + ")"; } } setLiteral(false); } return valueString; } private String visit(Node node) throws ParsingException { int numChildren = node.jjtGetNumChildren(); StringBuilder sb = new StringBuilder(); for (int i = 0; i < numChildren; i++) { Node child = node.jjtGetChild(i); ITreeNode treeNode = determineNodeType(child); treeNode.visit(sb, this); if (i != numChildren - 1) { sb.append(" + "); } } return sb.toString(); } private void reset() { parsedExpression = null; usedHelperMethods.clear(); variables = null; expressionType = null; } @Override public String getCode() { return parsedExpression; } @Override public Iterable getRequiredImports() { return getType().getRequiredImports(); } @Override public Iterable getRequiredFields() { return Collections.emptySet(); } @Override public Iterable getRequiredMethods() { return usedHelperMethods; } public ELType getMatchingVisibleMethodReturnType(String methodName, ELType[] parameterTypes) throws ParsingException { return typesFactory.getMatchingVisibleMethodReturnType(getType(), methodName, parameterTypes); } public ELPropertyDescriptor getPropertyDescriptor(String propertyName) throws ParsingException { return typesFactory.getPropertyDescriptor(getType(), propertyName); } public void addHelperMethods(HelperMethod helper) { usedHelperMethods.add(helper); } /** * This method determine type of parsed node and create wrapper for them, that extends AbstractTreeNode. If node type is not * recognized - throws ParsingException. * * @param child - parsed node * @throws ParsingException - if node type is not recognized. * @return wrapper for parsed node(if node type is recognized), that implement ITreeNode interface. */ public ITreeNode determineNodeType(Node child) throws ParsingException { ITreeNode treeNode = null; if (child instanceof AstIdentifier) { if (isCompositeComponent(child)) { treeNode = new AstCompositeComponentTreeNode(child); } else { treeNode = new AstIdentifierTreeNode(child); } } else if (child instanceof AstValue) { treeNode = new AstValueTreeNode(child); } else if (child instanceof AstInteger) { treeNode = new AstIntegerTreeNode(child); } else if (child instanceof AstString) { treeNode = new AstStringTreeNode(child); } else if (child instanceof AstFunction) { treeNode = new AstFunctionTreeNode(child); } else if (child instanceof AstDeferredExpression || child instanceof AstDynamicExpression) { treeNode = new AstDeferredOrDynamicExpressionTreeNode(child); } else if (child instanceof AstNot) { treeNode = new AstNotTreeNode(child); } else if (child instanceof AstChoice) { treeNode = new AstChoiceTreeNode(child); } else if (child instanceof AstEmpty) { treeNode = new AstEmptyTreeNode(child); } else if (child instanceof AstLiteralExpression) { treeNode = new AstLiteralTreeNode(child); } else if (child instanceof AstFalse) { treeNode = ConstantValueTreeNode.FALSE_NODE; } else if (child instanceof AstTrue) { treeNode = ConstantValueTreeNode.TRUE_NODE; } else if (child instanceof AstNull) { treeNode = ConstantValueTreeNode.NULL_NODE; } else if (child instanceof AstAnd) { treeNode = new BinaryBooleanOperationTreeNode(child, ELNodeConstants.AND_OPERATOR); } else if (child instanceof AstEqual) { treeNode = new EqualityTestTreeNode(child); } else if (child instanceof AstGreaterThan) { treeNode = new BinaryBooleanResultOperationTreeNode(child, ELNodeConstants.GREATER_THEN_OPERATOR); } else if (child instanceof AstGreaterThanEqual) { treeNode = new BinaryBooleanResultOperationTreeNode(child, ELNodeConstants.GREATER_THEN_OR_EQUALITY_OPERATOR); } else if (child instanceof AstLessThan) { treeNode = new BinaryBooleanResultOperationTreeNode(child, ELNodeConstants.LESS_THEN_OPERATOR); } else if (child instanceof AstLessThanEqual) { treeNode = new BinaryBooleanResultOperationTreeNode(child, ELNodeConstants.LESS_THEN_OR_EQUALITY_OPERATOR); } else if (child instanceof AstNotEqual) { treeNode = new EqualityTestTreeNode(child, true); } else if (child instanceof AstOr) { treeNode = new BinaryBooleanOperationTreeNode(child, ELNodeConstants.OR_OPERATOR); } else if (child instanceof AstDiv) { treeNode = new BinaryArithmeticOperationTreeNode(child, ELNodeConstants.DIV_OPERATOR); } else if (child instanceof AstMult) { treeNode = new BinaryArithmeticOperationTreeNode(child, ELNodeConstants.MULT_OPERATOR); } else if (child instanceof AstMod) { treeNode = new BinaryArithmeticIntegerOperationTreeNode(child, ELNodeConstants.MOD_OPERATOR); } else if (child instanceof AstPlus) { treeNode = new BinaryArithmeticOperationTreeNode(child, ELNodeConstants.PLUS_OPERATOR); } else if (child instanceof AstMinus) { treeNode = new BinaryArithmeticOperationTreeNode(child, ELNodeConstants.MINUS_OPERATOR); } else if (child instanceof AstBracketSuffix) { treeNode = new AstBracketSuffixTreeNode(child); } else if (child instanceof AstNegative) { treeNode = new AstNegativeTreeNode(child); } else if (child instanceof AstFloatingPoint) { treeNode = new AstFloatingPointTreeNode(child); } else if (child instanceof AstMethodSuffix) { treeNode = new AstMethodSuffixTreeNode(child); } else if (child instanceof AstPropertySuffix) { if (isCompositeComponentAttributesMap(child)) { treeNode = new AstCompositeComponentAttributesTreeNode(child); } else if (isCompositeComponentAttribute(child)) { treeNode = new AstIdentifierTreeNode(child); } else { treeNode = new AstPropertySuffixTreeNode(child); } } else { throw new ParsingException("Node " + child.getClass().getSimpleName() + "[" + child.getImage() + "] is not recognized;"); } return treeNode; } private boolean isCompositeComponent(Node node) { return "cc".equals(node.getImage()); } private boolean isCompositeComponentAttributesMap(Node node) { return "attrs".equals(node.getImage()) && isCompositeComponent(node.jjtGetParent().jjtGetChild(0)); } private boolean isCompositeComponentAttribute(Node node) { return isCompositeComponentAttributesMap(node.jjtGetParent().jjtGetChild(1)) && node == node.jjtGetParent().jjtGetChild(2); } @Override public void setParent(StatementsContainer parent) { this.parent = parent; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy