001    package railo.transformer.cfml.evaluator.impl;
002    
003    
004    import java.util.Iterator;
005    import java.util.List;
006    import java.util.Map;
007    
008    import railo.commons.lang.StringUtil;
009    import railo.runtime.functions.system.CFFunction;
010    import railo.runtime.listener.AppListenerUtil;
011    import railo.transformer.bytecode.Body;
012    import railo.transformer.bytecode.BytecodeException;
013    import railo.transformer.bytecode.Literal;
014    import railo.transformer.bytecode.Statement;
015    import railo.transformer.bytecode.cast.CastBoolean;
016    import railo.transformer.bytecode.cast.CastString;
017    import railo.transformer.bytecode.expression.ExprString;
018    import railo.transformer.bytecode.expression.Expression;
019    import railo.transformer.bytecode.literal.LitBoolean;
020    import railo.transformer.bytecode.literal.LitLong;
021    import railo.transformer.bytecode.literal.LitString;
022    import railo.transformer.bytecode.statement.tag.Attribute;
023    import railo.transformer.bytecode.statement.tag.Tag;
024    import railo.transformer.bytecode.util.ASMUtil;
025    import railo.transformer.cfml.evaluator.EvaluatorException;
026    import railo.transformer.cfml.evaluator.EvaluatorSupport;
027    import railo.transformer.library.function.FunctionLib;
028    import railo.transformer.library.function.FunctionLibFunction;
029    import railo.transformer.library.tag.TagLibTag;
030    
031    /**
032     * Prueft den Kontext des Tag function.
033     * Das Attribute <code>argument</code> darf nur direkt innerhalb des Tag <code>function</code> liegen.
034     * Dem Tag <code>argument</code> muss als erstes im tag function vorkommen
035     */
036    public final class Function extends EvaluatorSupport {
037    
038            //�
039            /**
040             * @see railo.transformer.cfml.evaluator.EvaluatorSupport#evaluate(org.w3c.dom.Element, railo.transformer.library.tag.TagLibTag)
041             */
042            public void evaluate(Tag tag, TagLibTag libTag, FunctionLib[] flibs) throws EvaluatorException {
043                    //Body p=(Body) tag.getParent();
044                    //Statement pp = p.getParent();
045                    
046                    boolean isCFC=true;
047            try {
048                            isCFC = ASMUtil.getAncestorPage(tag).isComponent();
049                    } catch (BytecodeException e) {}
050    
051                    Attribute attrName = tag.getAttribute("name");
052                    if(attrName!=null) {
053                            Expression expr = attrName.getValue();
054                            if(expr instanceof LitString && !isCFC){
055                                    checkFunctionName(((LitString)expr).getString(),flibs);
056                            }
057                                    
058                    }
059                    // attribute modifier
060                    Attribute attrModifier = tag.getAttribute("modifier");
061                    if(attrModifier!=null) {
062                            ExprString expr = CastString.toExprString(attrModifier.getValue());
063                            if(!(expr instanceof Literal))
064                                    throw new EvaluatorException("Attribute modifier of the Tag Function, must be one of the following literal string values: [abstract] or [final]");
065                            String modifier=StringUtil.emptyIfNull(((Literal)expr).getString()).trim();
066                            if(!StringUtil.isEmpty(modifier) && !"abstract".equalsIgnoreCase(modifier) && !"final".equalsIgnoreCase(modifier))
067                                    throw new EvaluatorException("Attribute modifier of the Tag Function, must be one of the following literal string values: [abstract] or [final]");
068                            
069                            
070                            boolean abstr = "abstract".equalsIgnoreCase(modifier);
071                            if(abstr)throwIfNotEmpty(tag);
072                    }
073                    
074                    // cachedWithin
075                    Attribute attrCachedWithin = tag.getAttribute("cachedwithin");
076                    if(attrCachedWithin!=null) {
077                            Expression val = attrCachedWithin.getValue();
078                            tag.addAttribute(new Attribute(attrCachedWithin.isDynamicType(), attrCachedWithin.getName(), LitLong.toExpr(ASMUtil.timeSpanToLong(val), null, null), "numeric"));
079                    }
080                    
081                    // Attribute localMode
082                    Attribute attrLocalMode = tag.getAttribute("localmode");
083                    if(attrLocalMode!=null) {
084                            Expression expr = attrLocalMode.getValue();
085                            String str = ASMUtil.toString(expr,null);
086                            if(!StringUtil.isEmpty(str) && AppListenerUtil.toLocalMode(str, -1)==-1)
087                                    throw new EvaluatorException("Attribute localMode of the Tag Function, must be a literal value (modern, classic, true or false)");
088                            //boolean output = ((LitBoolean)expr).getBooleanValue();
089                            //if(!output) ASMUtil.removeLiterlChildren(tag, true);
090                    }
091                    
092                    
093                    // Attribute Output
094                    // "output=true" wird in "railo.transformer.cfml.attributes.impl.Function" geh�ndelt
095                    Attribute attrOutput = tag.getAttribute("output");
096                    if(attrOutput!=null) {
097                            Expression expr = CastBoolean.toExprBoolean(attrOutput.getValue());
098                            if(!(expr instanceof LitBoolean))
099                                    throw new EvaluatorException("Attribute output of the Tag Function, must be a literal boolean value (true or false, yes or no)");
100                            //boolean output = ((LitBoolean)expr).getBooleanValue();
101                            //if(!output) ASMUtil.removeLiterlChildren(tag, true);
102                    }
103                    
104                    Attribute attrBufferOutput = tag.getAttribute("bufferoutput");
105                    if(attrBufferOutput!=null) {
106                            Expression expr = CastBoolean.toExprBoolean(attrBufferOutput.getValue());
107                            if(!(expr instanceof LitBoolean))
108                                    throw new EvaluatorException("Attribute bufferOutput of the Tag Function, must be a literal boolean value (true or false, yes or no)");
109                            //boolean output = ((LitBoolean)expr).getBooleanValue();
110                            //if(!output) ASMUtil.removeLiterlChildren(tag, true);
111                    }
112                    
113                    
114            //if(ASMUtil.isRoot(pp)) {
115                    Map attrs = tag.getAttributes();
116                    Iterator it = attrs.keySet().iterator();
117                    Attribute attr;
118                    while(it.hasNext()) {
119                            attr=(Attribute) attrs.get(it.next());
120                            checkAttributeValue(tag,attr);
121                    }
122            //}
123            
124            }
125            
126            public static void checkFunctionName(String name, FunctionLib[] flibs) throws EvaluatorException {
127                    FunctionLibFunction flf;
128                    for (int i = 0; i < flibs.length; i++) {
129                            flf = flibs[i].getFunction(name);
130                            if(flf!=null && flf.getClazz()!=CFFunction.class) {
131                                    throw new EvaluatorException("The name ["+name+"] is already used by a built in Function");
132                            }
133                    }
134            }
135    
136            public static void throwIfNotEmpty(Tag tag) throws EvaluatorException {
137                    Body body = tag.getBody();
138                    List<Statement> statments = body.getStatements();
139                    Statement stat;
140                    Iterator<Statement> it = statments.iterator();
141                    TagLibTag tlt;
142                    
143                    while(it.hasNext()) {
144                            stat=it.next();
145                            if(stat instanceof Tag) {
146                                    tlt = ((Tag)stat).getTagLibTag();
147                                    if(!tlt.getTagClassName().equals("railo.runtime.tag.Argument"))
148                                            throw new EvaluatorException("tag "+tlt.getFullName()+" is not allowed inside a function declaration");
149                            }
150                            /*else if(stat instanceof PrintOut) {
151                                    //body.remove(stat);
152                            }*/
153                    }
154            }
155    
156            private void checkAttributeValue(Tag tag, Attribute attr) throws EvaluatorException {
157                    if(!(attr.getValue() instanceof Literal))
158                            throw new EvaluatorException("Attribute ["+attr.getName()+"] of the Tag ["+tag.getFullname()+"] must be a literal/constant value");
159            
160        }
161    }