001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019package lucee.intergral.fusiondebug.server;
020
021import java.util.ArrayList;
022import java.util.Collections;
023import java.util.Comparator;
024import java.util.Iterator;
025import java.util.List;
026import java.util.Map.Entry;
027
028import lucee.commons.lang.StringUtil;
029import lucee.intergral.fusiondebug.server.type.FDVariable;
030import lucee.intergral.fusiondebug.server.util.FDCaster;
031import lucee.runtime.PageContextImpl;
032import lucee.runtime.PageSource;
033import lucee.runtime.exp.PageException;
034import lucee.runtime.op.Caster;
035import lucee.runtime.type.Struct;
036import lucee.runtime.type.scope.ClusterNotSupported;
037import lucee.runtime.type.scope.Scope;
038import lucee.runtime.type.util.KeyConstants;
039
040import com.intergral.fusiondebug.server.FDLanguageException;
041import com.intergral.fusiondebug.server.IFDStackFrame;
042import com.intergral.fusiondebug.server.IFDThread;
043import com.intergral.fusiondebug.server.IFDVariable;
044
045public class FDStackFrameImpl implements IFDStackFrame {
046
047
048        private static final int[] SCOPES_AS_INT = new int[]{
049                Scope.SCOPE_VARIABLES,Scope.SCOPE_CGI,Scope.SCOPE_URL,Scope.SCOPE_FORM,
050                Scope.SCOPE_COOKIE,Scope.SCOPE_CLIENT,Scope.SCOPE_APPLICATION,Scope.SCOPE_CALLER,
051                Scope.SCOPE_CLUSTER,Scope.SCOPE_REQUEST,Scope.SCOPE_SERVER,Scope.SCOPE_SESSION
052        };
053        private static final String[] SCOPES_AS_STRING = new String[]{
054                "variables","cgi","url","form",
055                "cookie","client","application","caller",
056                "cluster","request","server","session"
057        };
058 
059        private PageContextImpl pc;
060        private FDThreadImpl thread;
061        private PageSource ps;
062
063        private int line;
064
065        private static Comparator comparator=new FDVariableComparator();
066
067        public FDStackFrameImpl(FDThreadImpl thread,PageContextImpl pc, StackTraceElement trace, PageSource ps){
068                this(thread, pc, ps, trace.getLineNumber());
069        } 
070        public FDStackFrameImpl(FDThreadImpl thread,PageContextImpl pc, PageSource ps, int line){
071                this.thread=thread;
072                this.pc=pc;
073                this.line=line;
074                this.ps=ps;
075        } 
076        
077        @Override
078        public IFDVariable evaluate(String expression) throws FDLanguageException {
079                try {
080                        return new FDVariable(this,expression,FDCaster.toFDValue(this,pc.evaluate(expression)));
081                } 
082                catch (PageException e) {
083                        throw new FDLanguageException(e);
084                }
085        }
086
087        @Override
088        public String getExecutionUnitName() {
089                return ps.getClassName();
090        }
091
092        @Override
093        public String getExecutionUnitPackage() {
094                return ps.getPackageName();
095        }
096
097        @Override
098        public int getLineNumber() {
099                return line;
100                
101        }
102        
103        @Override
104        public String getSourceFileName() {
105                return ps.getFileName();
106        }
107
108        @Override
109        public String getSourceFilePath() {
110                String name = getSourceFileName();
111                String path=ps.getDisplayPath();
112                if(StringUtil.endsWithIgnoreCase(path, name))
113                        path=path.substring(0,path.length()-name.length());
114                return path;
115        }
116
117        @Override
118        public IFDThread getThread() {
119                return thread;
120        }
121
122        @Override
123        public List<String> getScopeNames() {
124                List<String> implScopes = pc.undefinedScope().getScopeNames();
125                for(int i=0;i<SCOPES_AS_INT.length;i++){
126                        if(!implScopes.contains(SCOPES_AS_STRING[i]) && enabled(pc,SCOPES_AS_INT[i]))
127                                implScopes.add(SCOPES_AS_STRING[i]);
128                }
129                return implScopes;
130        }
131        public static List<String> testScopeNames(PageContextImpl pc) {
132                return new FDStackFrameImpl(null,pc,null,null).getScopeNames();
133        }
134        
135        private static boolean enabled(PageContextImpl pc,int scope) {
136                if(Scope.SCOPE_CLIENT==scope){
137                        return pc.getApplicationContext().isSetClientManagement();
138                }
139                if(Scope.SCOPE_SESSION==scope){
140                        return pc.getApplicationContext().isSetSessionManagement();
141                }
142                if(Scope.SCOPE_CALLER==scope){
143                        return pc.undefinedScope().get(KeyConstants._caller,null) instanceof Struct;
144                }
145                if(Scope.SCOPE_CLUSTER==scope){
146                        try {
147                                return !(pc.clusterScope() instanceof ClusterNotSupported);
148                        } catch (PageException e) {
149                                //e.printStackTrace();
150                                return false;
151                        }
152                }
153                return true;
154        }
155
156        @Override
157        public List getVariables() {
158                Iterator it = getScopeNames().iterator();
159                List list=new ArrayList();
160                
161                while(it.hasNext()){
162                        try {
163                                getVariables(this,pc,list, (String)it.next());
164                        } 
165                        catch (FDLanguageException e) {e.printStackTrace();}
166                }
167                return sort(list);
168        }
169
170        public static List testVariables(PageContextImpl pc) {
171                return new FDStackFrameImpl(null,pc,null,null).getVariables();
172        }
173        
174
175        @Override
176        public List getVariables(String strScope) throws FDLanguageException {
177                return sort(getVariables(this,pc,new ArrayList(), strScope));
178        }
179        
180
181        public static List testVariables(PageContextImpl pc,String strScope) throws FDLanguageException {
182                return new FDStackFrameImpl(null,pc,null,null).getVariables(strScope);
183        }
184        
185        private static List getVariables(FDStackFrameImpl frame,PageContextImpl pc,List list,String strScope) throws FDLanguageException {
186                Scope scope;
187                try {
188                        scope = pc.scope(strScope, null);
189                        if(scope!=null) return copyValues(frame,list,scope);
190                        
191                        Object value=pc.undefinedScope().get(strScope,null);
192                        if(value!=null) {
193                                if(value instanceof Struct)return copyValues(frame,new ArrayList(),(Struct)value);
194                                throw new FDLanguageException("["+strScope+"] is not of type scope, type is ["+Caster.toTypeName(value)+"]");
195                        }
196                        throw new FDLanguageException("["+strScope+"] does not exist in the current context");
197                } 
198                catch (PageException e) {
199                        throw new FDLanguageException(e);
200                }
201        }
202
203        /**
204         * copy all data from given struct to given list and translate it to a FDValue
205         * @param to list to fill with values
206         * @param from struct to read values from
207         * @return the given list
208         */
209        private static List copyValues(FDStackFrameImpl frame,List to,Struct from) {
210                Iterator it = from.entrySet().iterator();
211                Entry entry;
212                while(it.hasNext()){
213                        entry=(Entry) it.next();
214                        to.add(new FDVariable(frame,(String)entry.getKey(),FDCaster.toFDValue(frame,entry.getValue())));
215                }
216                return to;
217        }
218
219        private static List sort(List list) {
220                Collections.sort(list,comparator);
221                return list;
222        }
223
224        @Override
225        public String getFrameInformation() {
226                return ps.getFullRealpath();
227        }
228        
229        public String toString(){
230                return "path:"+getSourceFilePath()+";name:"+getSourceFileName()+";unit-pack:"+getExecutionUnitPackage()+";unit-name:"+getExecutionUnitName()+";line:"+getLineNumber();
231        }
232
233
234}
235
236class FDVariableComparator implements Comparator {
237
238        @Override
239        public int compare(Object o1, Object o2) {
240                return ((FDVariable)o1).getName().compareToIgnoreCase(((FDVariable)o2).getName());
241        }
242}