001    package railo.transformer.cfml.evaluator.impl;
002    
003    import railo.commons.lang.StringUtil;
004    import railo.runtime.config.ConfigImpl;
005    import railo.runtime.engine.ThreadLocalPageContext;
006    import railo.transformer.bytecode.Statement;
007    import railo.transformer.bytecode.cast.CastBoolean;
008    import railo.transformer.bytecode.cast.CastString;
009    import railo.transformer.bytecode.expression.Expression;
010    import railo.transformer.bytecode.literal.LitString;
011    import railo.transformer.bytecode.statement.tag.Attribute;
012    import railo.transformer.bytecode.statement.tag.Tag;
013    import railo.transformer.bytecode.statement.tag.TagLoop;
014    import railo.transformer.bytecode.util.ASMUtil;
015    import railo.transformer.cfml.ExprTransformer;
016    import railo.transformer.cfml.TransfomerSettings;
017    import railo.transformer.cfml.evaluator.EvaluatorException;
018    import railo.transformer.cfml.evaluator.EvaluatorSupport;
019    import railo.transformer.library.function.FunctionLib;
020    import railo.transformer.library.tag.TagLib;
021    import railo.transformer.library.tag.TagLibTag;
022    import railo.transformer.util.CFMLString;
023    
024    
025    
026    /**
027     * Prueft den Kontext des Tag loop.
028     * Die Anforderungen an das Tag unterscheiden sich je nach Definition der Attribute.
029     * Falls das Attribute list vorhanden ist, muss auch das Attribute index vorhanden sein.
030     * Falls das Attribute list nicht vorhanden ist, aber das Attribute index, muessen auch die Attribute from und to vorhanden sein.
031     * Wenn das Attribute condition vorhanden ist, muss dieses mithilfe des ExprTransformer noch transformiert werden. 
032     * Falls das Attribute collection verwendet wird, muss auch das Attribute item verwendet werden.
033     **/
034    public final class Loop extends EvaluatorSupport {
035            //�
036            /**
037             *
038             * @see railo.transformer.cfml.evaluator.EvaluatorSupport#evaluate(railo.transformer.bytecode.statement.tag.Tag, railo.transformer.library.tag.TagLibTag, railo.transformer.library.function.FunctionLib[])
039             */
040            public void evaluate(Tag tag,TagLibTag tagLibTag,FunctionLib[] flibs) throws EvaluatorException {
041                    TagLoop loop=(TagLoop) tag;
042                    
043                    // label
044                    if(ASMUtil.isLiteralAttribute(tag, "label", ASMUtil.TYPE_STRING, false, true)) {
045                            LitString ls=(LitString) CastString.toExprString(tag.getAttribute("label").getValue());
046                            String l = ls.getString();
047                            if(!StringUtil.isEmpty(l,true)) {
048                                    loop.setLabel(l.trim());
049                                    tag.removeAttribute("label");
050                            }
051                    }
052                    
053                    // attribute maxrows and endrow not allowd at the same time
054            if(tag.containsAttribute("maxrows") && tag.containsAttribute("endrow"))
055                    throw new EvaluatorException("Wrong Context, you cannot use attribute maxrows and endrow at the same time.");
056            
057                    // file loop      
058            if(tag.containsAttribute("file")) {
059                if(!tag.containsAttribute("index"))
060                    throw new EvaluatorException("Wrong Context, when you use attribute file you must also use attribute index");
061                loop.setType(TagLoop.TYPE_FILE);
062                return;
063            }
064            // list loop
065            if(tag.containsAttribute("list")){
066                            if(!tag.containsAttribute("index") && !tag.containsAttribute("item"))
067                                    throw new EvaluatorException("Wrong Context, when you use attribute list,you must define attribute index and/or item");
068                            loop.setType(TagLoop.TYPE_LIST);
069                return;
070                    }
071            // array loop
072            if(tag.containsAttribute("array")){
073                            if(!tag.containsAttribute("index") && !tag.containsAttribute("item"))
074                                    throw new EvaluatorException("Wrong Context, when you use attribute array, you must define attribute index and/or item");
075                            loop.setType(TagLoop.TYPE_ARRAY);
076                return;
077                    }
078            // collection loop      
079            if(tag.containsAttribute("collection")) {
080                    if(!tag.containsAttribute("index") && !tag.containsAttribute("item"))
081                                    throw new EvaluatorException("Wrong Context, when you use attribute collection,you must define attribute index and/or item");
082                            loop.setType(TagLoop.TYPE_COLLECTION);
083                return;
084            }
085                    // index loop   
086                    if(tag.containsAttribute("index")) {
087                            if(!tag.containsAttribute("from") || !tag.containsAttribute("to"))
088                                    throw new EvaluatorException("Wrong Context, when you use attribute index you must also use attribute from and to or list or file");
089                            loop.setType(TagLoop.TYPE_INDEX);
090                return;
091                    }
092                    // condition loop
093                    if(tag.containsAttribute("condition")){
094                            TagLib tagLib=tagLibTag.getTagLib();
095                            ExprTransformer transformer;
096                            String text=ASMUtil.getAttributeString(tag, "condition");
097    
098                            try {
099                                    ConfigImpl config=(ConfigImpl) ThreadLocalPageContext.getConfig();
100                                    transformer = tagLib.getExprTransfomer();
101                                    Expression expr=transformer.transform(ASMUtil.getAncestorPage(tag),null,flibs,config.getCoreTagLib().getScriptTags(),new CFMLString(text,"UTF-8"),TransfomerSettings.toSetting(ThreadLocalPageContext.getConfig()));
102                                    tag.addAttribute(new Attribute(false,"condition",CastBoolean.toExprBoolean(expr),"boolean"));
103                            }
104                            catch (Exception e) {
105                                    throw new EvaluatorException(e.getMessage());
106                            }
107                            loop.setType(TagLoop.TYPE_CONDITION);
108                return;
109                    }
110                    // query loop
111                    if(tag.containsAttribute("query")){
112                            loop.setType(TagLoop.TYPE_QUERY);
113                return;
114                    }
115                    Info info=getParentInfo(loop);
116                    // query group
117                    if(tag.containsAttribute("group") && info.hasParentWithQuery){
118                            loop.setType(TagLoop.TYPE_GROUP);
119                            return;
120                    }
121                    
122                    if(info.hasParentWithQuery) {
123                    if(info.hasParentWithGroup) loop.setType(TagLoop.TYPE_INNER_GROUP);
124                    else loop.setType(TagLoop.TYPE_INNER_QUERY);
125                    return;
126            }
127            /*
128             if(hasQuery) 
129                    output.setType(TagOutput.TYPE_QUERY);
130            
131            else if(tag.containsAttribute("group") && hasParentWithQuery)
132                    output.setType(TagOutput.TYPE_GROUP);
133            
134            else if(hasParentWithQuery) {
135                    if(hasParentWithGroup) output.setType(TagOutput.TYPE_INNER_GROUP);
136                    else output.setType(TagOutput.TYPE_INNER_QUERY);
137            }
138            else
139                     output.setType(TagOutput.TYPE_NORMAL);
140            
141           
142             */
143            
144                    loop.setType(TagLoop.TYPE_NOTHING);
145                    //throw new EvaluatorException("Wrong Context, invalid attributes in tag cfloop");
146                    
147            }
148    
149            private Info getParentInfo(TagLoop loop) {
150                    
151            // check if inside a query tag
152                    TagLoop parent = loop;
153                    Info info=new Info();
154                    info.hasParentWithGroup=false;
155                    info.hasParentWithQuery=false;
156                    //boolean hasQuery=loop.containsAttribute("query");
157                    
158                    while((parent=getParentTagLoop(parent))!=null) {
159                if(!info.hasParentWithQuery)info.hasParentWithQuery=parent.hasQuery();
160                if(!info.hasParentWithGroup)info.hasParentWithGroup=parent.hasGroup();
161                if(info.hasParentWithQuery && info.hasParentWithGroup)break;
162                    }
163                    return info;
164            }
165            
166    
167            
168            private static TagLoop getParentTagLoop(TagLoop stat) {
169                    Statement parent = stat;
170                    while(true)     {
171                            parent=parent.getParent();
172                            if(parent==null)return null;
173                            if(parent instanceof TagLoop)   return (TagLoop) parent;
174                    }
175            }
176            
177            class Info {
178                    private boolean hasParentWithGroup=false;
179                    private boolean hasParentWithQuery=false;
180            }
181    }