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.runtime.debug;
020
021import java.io.IOException;
022import java.util.ArrayList;
023import java.util.Collections;
024import java.util.Comparator;
025import java.util.HashMap;
026import java.util.Iterator;
027import java.util.List;
028import java.util.ListIterator;
029import java.util.Map;
030
031import lucee.commons.io.SystemUtil;
032import lucee.commons.io.res.util.ResourceSnippet;
033import lucee.commons.io.res.util.ResourceSnippetsMap;
034import lucee.commons.lang.ExceptionUtil;
035import lucee.commons.lang.StringUtil;
036import lucee.runtime.Component;
037import lucee.runtime.Page;
038import lucee.runtime.PageContext;
039import lucee.runtime.PageContextImpl;
040import lucee.runtime.PageSource;
041import lucee.runtime.PageSourceImpl;
042import lucee.runtime.config.Config;
043import lucee.runtime.config.ConfigImpl;
044import lucee.runtime.db.SQL;
045import lucee.runtime.engine.ThreadLocalPageContext;
046import lucee.runtime.exp.CatchBlock;
047import lucee.runtime.exp.DatabaseException;
048import lucee.runtime.exp.PageException;
049import lucee.runtime.exp.PageExceptionImpl;
050import lucee.runtime.op.Caster;
051import lucee.runtime.type.Array;
052import lucee.runtime.type.ArrayImpl;
053import lucee.runtime.type.Collection;
054import lucee.runtime.type.Collection.Key;
055import lucee.runtime.type.DebugQueryColumn;
056import lucee.runtime.type.KeyImpl;
057import lucee.runtime.type.Query;
058import lucee.runtime.type.QueryColumn;
059import lucee.runtime.type.QueryImpl;
060import lucee.runtime.type.Struct;
061import lucee.runtime.type.StructImpl;
062import lucee.runtime.type.dt.DateTimeImpl;
063import lucee.runtime.type.util.KeyConstants;
064
065
066/**
067 * Class to debug the application
068 */
069public final class DebuggerImpl implements DebuggerPro {
070        private static final long serialVersionUID = 3957043879267494311L;
071
072        private static final Collection.Key IMPLICIT_ACCESS= KeyImpl.intern("implicitAccess");
073        private static final Collection.Key PAGE_PARTS= KeyImpl.intern("pageParts");
074        //private static final Collection.Key OUTPUT_LOG= KeyImpl.intern("outputLog");
075
076        private static final int MAX_PARTS = 100;
077
078        private Map<String,DebugEntryTemplateImpl> entries=new HashMap<String,DebugEntryTemplateImpl>();
079        private Map<String,DebugEntryTemplatePartImpl> partEntries;
080        private ResourceSnippetsMap snippetsMap = new ResourceSnippetsMap( 1024, 128 );
081
082        private List<QueryEntry> queries=new ArrayList<QueryEntry>();
083        private List<DebugTimerImpl> timers=new ArrayList<DebugTimerImpl>();
084        private List<DebugTraceImpl> traces=new ArrayList<DebugTraceImpl>();
085        private List<DebugDump> dumps=new ArrayList<DebugDump>();
086        private List<CatchBlock> exceptions=new ArrayList<CatchBlock>();
087        private Map<String,ImplicitAccessImpl> implicitAccesses=new HashMap<String,ImplicitAccessImpl>();
088        
089        private boolean output=true;
090        private long lastEntry;
091        private long lastTrace;
092        private Array historyId=new ArrayImpl();
093        private Array historyLevel=new ArrayImpl();
094
095        private long starttime=System.currentTimeMillis();
096
097        private DebugOutputLog outputLog;
098
099        final static Comparator DEBUG_ENTRY_TEMPLATE_COMPARATOR = new DebugEntryTemplateComparator();
100        final static Comparator DEBUG_ENTRY_TEMPLATE_PART_COMPARATOR = new DebugEntryTemplatePartComparator();
101
102        private static final Key CACHE_TYPE = KeyImpl.init("cacheType");
103
104        @Override
105        public void reset() {
106                entries.clear();
107                if(partEntries!=null)partEntries.clear();
108                queries.clear();
109                implicitAccesses.clear();
110                timers.clear();
111                traces.clear();
112                dumps.clear();
113                exceptions.clear();
114                historyId.clear();
115                historyLevel.clear();
116                output=true;
117                outputLog=null;
118        }
119
120        public DebuggerImpl() { 
121        }
122
123        @Override
124        public DebugEntryTemplate getEntry(PageContext pc,PageSource source) {
125        return getEntry(pc,source,null);
126    }
127
128        @Override
129        public DebugEntryTemplate getEntry(PageContext pc,PageSource source, String key) {
130        lastEntry = System.currentTimeMillis();
131        String src=DebugEntryTemplateImpl.getSrc(source==null?"":source.getDisplayPath(),key);
132        
133        DebugEntryTemplateImpl de= entries.get(src);
134        if(de!=null ){
135            de.countPP();
136                        historyId.appendEL(de.getId());
137                        historyLevel.appendEL(Caster.toInteger(pc.getCurrentLevel()));
138            return de;
139        }
140        de=new DebugEntryTemplateImpl(source,key);
141        entries.put(src,de);
142                historyId.appendEL(de.getId());
143                historyLevel.appendEL(Caster.toInteger(pc.getCurrentLevel()));
144        return de;
145    }
146
147
148        @Override
149        public DebugEntryTemplatePart getEntry(PageContext pc, PageSource source, int startPos, int endPos) {
150        String src=DebugEntryTemplatePartImpl.getSrc(source==null?"":source.getDisplayPath(),startPos,endPos);
151        DebugEntryTemplatePartImpl de=null;
152        if(partEntries!=null){
153                de=partEntries.get(src);
154                if(de!=null ){
155                    de.countPP();
156                    return de;
157                }
158        }
159        else {
160                partEntries=new HashMap<String, DebugEntryTemplatePartImpl>();
161        }
162
163                ResourceSnippet snippet = snippetsMap.getSnippet( source, startPos, endPos, ((PageContextImpl)pc).getResourceCharset().name());
164        de=new DebugEntryTemplatePartImpl(source, startPos, endPos, snippet.getStartLine(), snippet.getEndLine(), snippet.getContent());
165        partEntries.put(src,de);
166        return de;
167    }
168
169        private ArrayList<DebugEntryTemplate> toArray() {
170        ArrayList<DebugEntryTemplate> arrPages=new ArrayList<DebugEntryTemplate>(entries.size());
171        Iterator<String> it = entries.keySet().iterator();
172        while(it.hasNext()) {
173            DebugEntryTemplate page =entries.get(it.next());
174            page.resetQueryTime();
175            arrPages.add(page);
176            
177        }
178        Collections.sort(arrPages, DEBUG_ENTRY_TEMPLATE_COMPARATOR);
179        
180
181        // Queries
182        int len=queries.size();
183        for(int i=0;i<len;i++) {
184            QueryEntryPro entry=(QueryEntryPro) queries.get(i);
185            String path=entry.getSrc();
186            Object o=entries.get(path);
187            
188            if(o!=null) {
189                DebugEntryTemplate oe=(DebugEntryTemplate) o;
190                oe.updateQueryTime(entry.getExecutionTime());
191            }
192        }
193        
194        return arrPages;
195    }
196
197        /*private DumpData _toDumpData(int value) {
198        return new SimpleDumpData(_toString(value));
199    }
200        private DumpData _toDumpData(long value) {
201        return new SimpleDumpData(_toString(value));
202    }*/
203        
204        private String _toString(long value) {
205        if(value<=0) return "0";
206        return String.valueOf(value);
207    }
208        private String _toString(int value) {
209        if(value<=0) return "0";
210        return String.valueOf(value);
211    }
212        
213        @Override
214        public void addQuery(Query query,String datasource,String name,SQL sql, int recordcount, PageSource src,int time) {
215                addQuery(query, datasource, name, sql, recordcount, src, (long)time);
216        }
217        
218        @Override
219        public void addQuery(Query query,String datasource,String name,SQL sql, int recordcount, PageSource src,long time) {
220                String path="";
221                if(src!=null) path=src.getDisplayPath();
222                queries.add(new QueryEntryImpl(query,datasource,name,sql,recordcount,path,time));
223        }
224        
225        @Override
226        public void setOutput(boolean output) {
227                this.output = output;
228        }
229    
230        @Override
231        public List<QueryEntry> getQueries() {
232        return queries;
233    }
234
235        @Override
236        public void writeOut(PageContext pc) throws IOException {
237        //stop();
238        if(!output)return;
239        String addr = pc.getHttpServletRequest().getRemoteAddr();
240        lucee.runtime.config.DebugEntry debugEntry = ((ConfigImpl)pc.getConfig()).getDebugEntry(addr, null);
241                
242        // no debug File 
243
244                if(debugEntry==null) {
245                    //pc.forceWrite(pc.getConfig().getDefaultDumpWriter().toString(pc,toDumpData(pc, 9999,DumpUtil.toDumpProperties()),true)); 
246                    return;
247                } 
248                
249                Struct args=new StructImpl();
250                args.setEL(KeyConstants._custom, debugEntry.getCustom());
251                try {
252                        args.setEL(KeyConstants._debugging, pc.getDebugger().getDebuggingData(pc));
253                } catch (PageException e1) {}
254                
255                try {
256                        String path = debugEntry.getPath();
257                        PageSource[] arr = ((PageContextImpl)pc).getPageSources(path);
258                        Page p = PageSourceImpl.loadPage(pc, arr,null);
259                        
260                        // patch for old path
261                        String fullname = debugEntry.getFullname();
262                        if(p==null) {
263                                if(path!=null) {
264                                        boolean changed=false;
265                                        if(path.endsWith("/Modern.cfc") || path.endsWith("\\Modern.cfc")) {
266                                                path="/lucee-server/admin/debug/Modern.cfc";
267                                                fullname="lucee-server.admin.debug.Modern";
268                                                changed=true;
269                                        }
270                                        else if(path.endsWith("/Classic.cfc") || path.endsWith("\\Classic.cfc")) {
271                                                path="/lucee-server/admin/debug/Classic.cfc";
272                                                fullname="lucee-server.admin.debug.Classic";
273                                                changed=true;
274                                        }
275                                        else if(path.endsWith("/Comment.cfc") || path.endsWith("\\Comment.cfc")) {
276                                                path="/lucee-server/admin/debug/Comment.cfc";
277                                                fullname="lucee-server.admin.debug.Comment";
278                                                changed=true;
279                                        }
280                                        if(changed)pc.write("<span style='color:red'>Please update your debug template defintions in the lucee admin by going into the detail view and hit the \"update\" button.</span>");
281                                        
282                                }
283                                
284                                arr = ((PageContextImpl)pc).getPageSources(path);
285                                p = PageSourceImpl.loadPage(pc, arr);
286                        }
287                        
288                        
289                        pc.addPageSource(p.getPageSource(), true);
290                        try{
291                                Component cfc = pc.loadComponent(fullname);
292                                cfc.callWithNamedValues(pc, "output", args);
293                        }
294                        finally {
295                                pc.removeLastPageSource(true);
296                        }
297        } 
298                catch (PageException e) {
299            pc.handlePageException(e);
300        }
301    }
302
303        @Override
304        public Struct getDebuggingData(PageContext pc) throws DatabaseException {
305        return getDebuggingData(pc, false);
306    }
307    
308        @Override
309        public Struct getDebuggingData(PageContext pc, boolean addAddionalInfo) throws DatabaseException {
310                List<QueryEntry> queries = getQueries();
311            Struct qryExe=new StructImpl();
312            ListIterator<QueryEntry> qryIt = queries.listIterator();
313        Collection.Key[] cols = new Collection.Key[]{
314                        KeyConstants._name,
315                        KeyConstants._time,
316                        KeyConstants._sql,
317                        KeyConstants._src,
318                        KeyConstants._count,
319                        KeyConstants._datasource,
320                        KeyConstants._usage,
321                        CACHE_TYPE};
322        String[] types = new String[]{"VARCHAR","DOUBLE","VARCHAR","VARCHAR","DOUBLE","VARCHAR","ANY","VARCHAR"};
323        
324        //queries
325        Query qryQueries=null;
326        try {
327            qryQueries = new QueryImpl(cols,types,queries.size(),"query");
328        } catch (DatabaseException e) {
329            qryQueries = new QueryImpl(cols,queries.size(),"query");
330        }
331                int row=0;
332                try {
333                    while(qryIt.hasNext()) {
334                        row++;
335                        QueryEntryPro qe=(QueryEntryPro) qryIt.next();
336                                qryQueries.setAt(KeyConstants._name,row,qe.getName()==null?"":qe.getName());
337                        qryQueries.setAt(KeyConstants._time,row,Long.valueOf(qe.getExecutionTime()));
338                        qryQueries.setAt(KeyConstants._sql,row,qe.getSQL().toString());
339                                qryQueries.setAt(KeyConstants._src,row,qe.getSrc());
340                qryQueries.setAt(KeyConstants._count,row,Integer.valueOf(qe.getRecordcount()));
341                qryQueries.setAt(KeyConstants._datasource,row,qe.getDatasource());
342                qryQueries.setAt(CACHE_TYPE,row,qe.getCacheType());
343                
344                Struct usage = getUsage(qe);
345                if(usage!=null) qryQueries.setAt(KeyConstants._usage,row,usage);
346
347                        Object o=qryExe.get(KeyImpl.init(qe.getSrc()),null);
348                        if(o==null) qryExe.setEL(KeyImpl.init(qe.getSrc()),Long.valueOf(qe.getExecutionTime()));
349                        else qryExe.setEL(KeyImpl.init(qe.getSrc()),Long.valueOf(((Long)o).longValue()+qe.getExecutionTime()));
350                    }
351                }
352                catch(PageException dbe) {}
353                
354            // Pages
355            // src,load,app,query,total
356            Struct debugging=new StructImpl();
357            row=0;
358        ArrayList<DebugEntryTemplate> arrPages = toArray();
359                int len=arrPages.size();
360        Query qryPage=new QueryImpl(
361                new Collection.Key[]{
362                                KeyConstants._id,
363                                KeyConstants._count,
364                                KeyConstants._min,
365                                KeyConstants._max,
366                                KeyConstants._avg
367                                ,KeyConstants._app,
368                                KeyConstants._load,
369                                KeyConstants._query,
370                                KeyConstants._total,
371                                KeyConstants._src},
372                len,"query");
373
374                try {
375            DebugEntryTemplate de;
376            //PageSource ps;
377                    for(int i=0;i<len;i++) {
378                        row++;
379                        de=arrPages.get(i);
380                //ps = de.getPageSource();
381                
382                        qryPage.setAt(KeyConstants._id,row,de.getId());
383                        qryPage.setAt(KeyConstants._count,row,_toString(de.getCount()));
384                qryPage.setAt(KeyConstants._min,row,_toString(de.getMin()));
385                qryPage.setAt(KeyConstants._max,row,_toString(de.getMax()));
386                qryPage.setAt(KeyConstants._avg,row,_toString(de.getExeTime()/de.getCount()));
387                qryPage.setAt(KeyConstants._app,row,_toString(de.getExeTime()-de.getQueryTime()));
388                qryPage.setAt(KeyConstants._load,row,_toString(de.getFileLoadTime()));
389                        qryPage.setAt(KeyConstants._query,row,_toString(de.getQueryTime()));
390                qryPage.setAt(KeyConstants._total,row,_toString( de.getFileLoadTime() + de.getExeTime()));
391                        qryPage.setAt(KeyConstants._src,row,de.getSrc());    
392                        }
393                }
394                catch(PageException dbe) {}
395
396
397            // Pages Parts
398                List<DebugEntryTemplatePart> filteredPartEntries = null;
399                boolean hasParts=partEntries!=null && !partEntries.isEmpty() && !arrPages.isEmpty();
400                int qrySize=0;
401
402                if(hasParts) {
403
404                        String slowestTemplate = arrPages.get( 0 ).getPath();
405
406                        filteredPartEntries = new ArrayList();
407
408                        java.util.Collection<DebugEntryTemplatePartImpl> col = partEntries.values();
409                        for ( DebugEntryTemplatePart detp : col ) {
410
411                                if ( detp.getPath().equals( slowestTemplate ) )
412                                        filteredPartEntries.add( detp );
413                        }
414
415                        qrySize = Math.min( filteredPartEntries.size(), MAX_PARTS );
416                }
417
418                Query qryPart = new QueryImpl(
419            new Collection.Key[]{
420                 KeyConstants._id
421                ,KeyConstants._count
422                ,KeyConstants._min
423                ,KeyConstants._max
424                ,KeyConstants._avg
425                ,KeyConstants._total
426                ,KeyConstants._path
427                ,KeyConstants._start
428                ,KeyConstants._end
429                ,KeyConstants._startLine
430                ,KeyConstants._endLine
431                ,KeyConstants._snippet
432            }, qrySize, "query" );
433
434                if(hasParts) {
435                        row=0;
436                Collections.sort( filteredPartEntries, DEBUG_ENTRY_TEMPLATE_PART_COMPARATOR );
437
438                        DebugEntryTemplatePart[] parts = new DebugEntryTemplatePart[ qrySize ];
439
440                        if ( filteredPartEntries.size() > MAX_PARTS )
441                                parts = filteredPartEntries.subList(0, MAX_PARTS).toArray( parts );
442                        else
443                                parts = filteredPartEntries.toArray( parts );
444
445                        try {
446                    DebugEntryTemplatePart de;
447                    //PageSource ps;
448                            for(int i=0;i<parts.length;i++) {
449                                row++;
450                                de=parts[i];
451                        
452                                qryPart.setAt(KeyConstants._id,row,de.getId());
453                                qryPart.setAt(KeyConstants._count,row,_toString(de.getCount()));
454                                qryPart.setAt(KeyConstants._min,row,_toString(de.getMin()));
455                                qryPart.setAt(KeyConstants._max,row,_toString(de.getMax()));
456                                qryPart.setAt(KeyConstants._avg,row,_toString(de.getExeTime()/de.getCount()));
457                                qryPart.setAt(KeyConstants._start,row,_toString(de.getStartPosition()));
458                                qryPart.setAt(KeyConstants._end,row,_toString(de.getEndPosition()));
459                                qryPart.setAt(KeyConstants._total,row,_toString(de.getExeTime()));
460                                qryPart.setAt(KeyConstants._path,row,de.getPath());
461
462                    if ( de instanceof DebugEntryTemplatePartImpl ) {
463
464                        qryPart.setAt( KeyConstants._startLine, row, _toString( ((DebugEntryTemplatePartImpl)de).getStartLine() ) );
465                        qryPart.setAt( KeyConstants._endLine, row, _toString( ((DebugEntryTemplatePartImpl)de).getEndLine() ));
466                        qryPart.setAt( KeyConstants._snippet, row, ((DebugEntryTemplatePartImpl)de).getSnippet() );
467                    }
468                                }
469                        }
470                        catch(PageException dbe) {}
471                }
472                
473                
474                
475
476                // exceptions
477                len = exceptions==null?0:exceptions.size();
478                
479        Array arrExceptions=new ArrayImpl();
480        if(len>0) {
481                        Iterator<CatchBlock> it = exceptions.iterator();
482                        row=0;
483                        while(it.hasNext()) {
484                                arrExceptions.appendEL(it.next());  
485                        }
486                        
487        }
488
489                // output log
490        //Query qryOutputLog=getOutputText();
491        
492        
493
494                // timers
495                len=timers==null?0:timers.size();
496        Query qryTimers=new QueryImpl(
497                new Collection.Key[]{KeyConstants._label,KeyConstants._time,KeyConstants._template},
498                len,"timers");
499        if(len>0) {
500                try {
501                        Iterator<DebugTimerImpl> it = timers.iterator();
502                        DebugTimer timer;
503                        row=0;
504                        while(it.hasNext()) {
505                                timer=it.next();
506                                row++;
507                                qryTimers.setAt(KeyConstants._label,row,timer.getLabel()); 
508                                qryTimers.setAt(KeyConstants._template,row,timer.getTemplate()); 
509                                qryTimers.setAt(KeyConstants._time,row,Caster.toDouble(timer.getTime()));    
510                        }
511                        }
512                        catch(PageException dbe) {}
513        }
514        
515     // dumps
516                len=dumps==null?0:dumps.size();
517                if(!((ConfigImpl)pc.getConfig()).hasDebugOptions(ConfigImpl.DEBUG_DUMP))len=0;
518        Query qryDumps=new QueryImpl(
519                new Collection.Key[]{
520                                KeyConstants._output,
521                                KeyConstants._template,
522                                KeyConstants._line},
523                len,"dumps");
524        if(len>0) {
525                try {
526                        Iterator<DebugDump> it = dumps.iterator();
527                        DebugDump dd;
528                        row=0;
529                        while(it.hasNext()) {
530                                dd= it.next();
531                                row++;
532                                qryDumps.setAt(KeyConstants._output,row,dd.getOutput());  
533                                if(!StringUtil.isEmpty(dd.getTemplate()))qryDumps.setAt(KeyConstants._template,row,dd.getTemplate()); 
534                                if(dd.getLine()>0)qryDumps.setAt(KeyConstants._line,row,new Double(dd.getLine())); 
535                        }
536                        }
537                        catch(PageException dbe) {}
538        }
539
540                // traces
541                len=traces==null?0:traces.size();
542                if(!((ConfigImpl)pc.getConfig()).hasDebugOptions(ConfigImpl.DEBUG_TRACING))len=0;
543        Query qryTraces=new QueryImpl(
544                new Collection.Key[]{
545                                KeyConstants._type,
546                                KeyConstants._category,
547                                KeyConstants._text,
548                                KeyConstants._template,
549                                KeyConstants._line,
550                                KeyConstants._action,
551                                KeyConstants._varname,
552                                KeyConstants._varvalue,
553                                KeyConstants._time},
554                len,"traces");
555        if(len>0) {
556                try {
557                        Iterator<DebugTraceImpl> it = traces.iterator();
558                        DebugTraceImpl trace;
559                        row=0;
560                        while(it.hasNext()) {
561                                trace= it.next();
562                                row++;
563                                qryTraces.setAt(KeyConstants._type,row,DebugTraceImpl.toType(trace.getType(), "INFO"));  
564                                if(!StringUtil.isEmpty(trace.getCategory()))qryTraces.setAt(KeyConstants._category,row,trace.getCategory()); 
565                                if(!StringUtil.isEmpty(trace.getText()))qryTraces.setAt(KeyConstants._text,row,trace.getText()); 
566                                if(!StringUtil.isEmpty(trace.getTemplate()))qryTraces.setAt(KeyConstants._template,row,trace.getTemplate()); 
567                                if(trace.getLine()>0)qryTraces.setAt(KeyConstants._line,row,new Double(trace.getLine())); 
568                                if(!StringUtil.isEmpty(trace.getAction()))qryTraces.setAt(KeyConstants._action,row,trace.getAction()); 
569                                if(!StringUtil.isEmpty(trace.getVarName()))qryTraces.setAt(KeyImpl.init("varname"),row,trace.getVarName()); 
570                                if(!StringUtil.isEmpty(trace.getVarValue()))qryTraces.setAt(KeyImpl.init("varvalue"),row,trace.getVarValue()); 
571                                qryTraces.setAt(KeyConstants._time,row,new Double(trace.getTime())); 
572                        }
573                        }
574                        catch(PageException dbe) {}
575        }
576        
577
578
579                // scope access
580                len=implicitAccesses==null?0:implicitAccesses.size();
581        Query qryImplicitAccesseses=new QueryImpl(
582                new Collection.Key[]{
583                                KeyConstants._template,
584                                KeyConstants._line,
585                                KeyConstants._scope,
586                                KeyConstants._count,
587                                KeyConstants._name},
588                len,"implicitAccess");
589        if(len>0) {
590                try {
591                        Iterator<ImplicitAccessImpl> it = implicitAccesses.values().iterator();
592                        ImplicitAccessImpl das;
593                        row=0;
594                        while(it.hasNext()) {
595                                das= it.next();
596                                row++;
597                                qryImplicitAccesseses.setAt(KeyConstants._template,row,das.getTemplate()); 
598                                qryImplicitAccesseses.setAt(KeyConstants._line,row,new Double(das.getLine()));
599                                qryImplicitAccesseses.setAt(KeyConstants._scope,row,das.getScope()); 
600                                qryImplicitAccesseses.setAt(KeyConstants._count,row,new Double(das.getCount())); 
601                                qryImplicitAccesseses.setAt(KeyConstants._name,row,das.getName());  
602                                
603                        }
604                        }
605                        catch(PageException dbe) {}
606        }
607        
608        Query history=new QueryImpl(new Collection.Key[]{},0,"history");
609        try {
610                        history.addColumn(KeyConstants._id, historyId);
611                history.addColumn(KeyConstants._level, historyLevel);
612                } catch (PageException e) {
613                }
614                
615                if(addAddionalInfo) {
616                        debugging.setEL(KeyConstants._cgi,pc.cgiScope());
617                        debugging.setEL(KeyImpl.init("starttime"),new DateTimeImpl(starttime,false));
618                        debugging.setEL(KeyConstants._id,pc.getId());
619                }
620
621                debugging.setEL(KeyConstants._pages,qryPage);
622                debugging.setEL(PAGE_PARTS,qryPart);
623                debugging.setEL(KeyConstants._queries,qryQueries);
624                debugging.setEL(KeyConstants._timers,qryTimers);
625                debugging.setEL(KeyConstants._traces,qryTraces);
626                debugging.setEL("dumps",qryDumps);
627                debugging.setEL(IMPLICIT_ACCESS,qryImplicitAccesseses);
628                //debugging.setEL(OUTPUT_LOG,qryOutputLog);
629                
630                
631                
632                
633                debugging.setEL(KeyConstants._history,history);
634                debugging.setEL(KeyConstants._exceptions,arrExceptions);
635                
636                return debugging;
637    }
638    
639        private static Struct getUsage(QueryEntry qe) throws PageException {
640                Query qry = ((QueryEntryImpl)qe).getQry();
641        
642        QueryColumn c;
643        DebugQueryColumn dqc;
644        outer:if(qry!=null) {
645                Struct usage=null;
646                Collection.Key[] columnNames = qry.getColumnNames();
647                Collection.Key columnName; 
648                for(int i=0;i<columnNames.length;i++){
649                        columnName=columnNames[i];
650                        c = qry.getColumn(columnName);
651                        if(!(c instanceof DebugQueryColumn)) break outer;
652                        dqc=(DebugQueryColumn) c;
653                        if(usage==null) usage=new StructImpl();
654                        usage.setEL(columnName, Caster.toBoolean(dqc.isUsed()));
655                }
656                return usage;
657        }
658        return null;
659        }
660
661        /*private static String getUsageList(QueryEntry qe) throws PageException  {
662                Query qry = ((QueryEntryImpl)qe).getQry();
663        StringBuilder sb=new StringBuilder();
664        QueryColumn c;
665        DebugQueryColumn dqc;
666        outer:if(qry!=null) {
667                String[] columnNames = qry.getColumns();
668                Collection.Key colName;
669                for(int i=0;i<columnNames.length;i++){
670                        colName=KeyImpl.init(columnNames[i]);
671                        c = qry.getColumn(colName);
672                        if(!(c instanceof DebugQueryColumn)) break outer;
673                        dqc=(DebugQueryColumn) c;
674                        if(!dqc.isUsed()){
675                                if(sb.length()>0) sb.append(", ");
676                                sb.append(colName.getString());
677                        }
678                }
679        }
680        return sb.toString();
681        }*/
682
683        @Override
684        public DebugTimer addTimer(String label, long time, String template) {
685                DebugTimerImpl t;
686                timers.add(t=new DebugTimerImpl(label,time,template));
687                return t;
688        }
689        
690
691        @Override
692        public DebugTrace addTrace(int type, String category, String text, PageSource page,String varName,String varValue) {
693                
694                long _lastTrace =(traces.isEmpty())?lastEntry: lastTrace;
695                lastTrace = System.currentTimeMillis();
696                
697                DebugTraceImpl t=new DebugTraceImpl(type,category,text,page.getDisplayPath(),SystemUtil.getCurrentContext().line,"",varName,varValue,lastTrace-_lastTrace);
698                traces.add(t);
699                return t;
700        }
701        
702        
703        public DebugDump addDump(PageSource ps,String dump) {
704                
705                DebugDump dt=new DebugDumpImpl(ps.getDisplayPath(),SystemUtil.getCurrentContext().line,dump);
706                dumps.add(dt);
707                return dt;
708        }
709        
710        @Override
711        public DebugTrace addTrace(int type, String category, String text, String template,int line,String action,String varName,String varValue) {
712                
713                long _lastTrace =(traces.isEmpty())?lastEntry: lastTrace;
714                lastTrace = System.currentTimeMillis();
715        
716                DebugTraceImpl t=new DebugTraceImpl(type,category,text,template,line,action,varName,varValue,lastTrace-_lastTrace);
717                traces.add(t);
718                return t;
719        }
720        
721        @Override
722        public DebugTrace[] getTraces() {
723                return getTraces(ThreadLocalPageContext.get());
724        }
725
726        public DebugTrace[] getTraces(PageContext pc) {
727                if(pc!=null && ((ConfigImpl)pc.getConfig()).hasDebugOptions(ConfigImpl.DEBUG_TRACING))
728                        return traces.toArray(new DebugTrace[traces.size()]);
729                return new DebugTrace[0];
730        }
731        
732        @Override
733        public void addException(Config config,PageException pe) {
734                if(exceptions.size()>1000) return;
735                try {
736                        exceptions.add(((PageExceptionImpl)pe).getCatchBlock(config));
737                }
738                catch(Throwable t){
739                ExceptionUtil.rethrowIfNecessary(t);
740        }
741        }
742        
743        @Override
744        public CatchBlock[] getExceptions() {
745                return exceptions.toArray(new CatchBlock[exceptions.size()]);
746        }
747
748        public void init(Config config) {
749                this.starttime=System.currentTimeMillis()+config.getTimeServerOffset();
750        }
751
752        @Override
753        public void addImplicitAccess(String scope, String name) {
754                if(implicitAccesses.size()>1000) return;
755                try {
756                        SystemUtil.TemplateLine tl = SystemUtil.getCurrentContext(); 
757                        String key=tl+":"+scope+":"+name;
758                        ImplicitAccessImpl dsc = implicitAccesses.get(key);
759                        if(dsc!=null)
760                                dsc.inc();
761                        else 
762                                implicitAccesses.put(key,new ImplicitAccessImpl(scope,name,tl.template,tl.line));
763                }
764                catch(Throwable t){
765                ExceptionUtil.rethrowIfNecessary(t);
766        }
767        }
768
769        @Override
770        public ImplicitAccess[] getImplicitAccesses(int scope, String name) {
771                return implicitAccesses.values().toArray(new ImplicitAccessImpl[implicitAccesses.size()]);
772        }
773
774        public void setOutputLog(DebugOutputLog outputLog) { 
775                this.outputLog=outputLog;
776        }
777        
778        public DebugTextFragment[] getOutputTextFragments() { 
779                return this.outputLog.getFragments();
780        }
781        
782        public Query getOutputText() throws DatabaseException { 
783                DebugTextFragment[] fragments = outputLog.getFragments();
784                int len = fragments==null?0:fragments.length;
785                Query qryOutputLog=new QueryImpl(
786                new Collection.Key[]{
787                                KeyConstants._line
788                                ,KeyConstants._template,
789                                KeyConstants._text},
790                len,"query");
791                
792                
793        if(len>0) {
794                        for(int i=0;i<fragments.length;i++) {
795                                qryOutputLog.setAtEL(KeyConstants._line,i+1,fragments[i].line);
796                                qryOutputLog.setAtEL(KeyConstants._template,i+1,fragments[i].template);
797                                qryOutputLog.setAtEL(KeyConstants._text,i+1,fragments[i].text);  
798                        }
799        }
800        return qryOutputLog;
801        
802        }
803
804        public void resetTraces() {
805                traces.clear();
806        }
807
808}
809
810final class DebugEntryTemplateComparator implements Comparator<DebugEntryTemplate> {
811    
812        public int compare(DebugEntryTemplate de1,DebugEntryTemplate de2) {
813                long result = ((de2.getExeTime()+de2.getFileLoadTime())-(de1.getExeTime()+de1.getFileLoadTime()));
814        // we do this additional step to try to avoid ticket LUCEE-2076
815        return result>0L?1:(result<0L?-1:0);
816    }
817}
818
819final class DebugEntryTemplatePartComparator implements Comparator<DebugEntryTemplatePart> {
820        
821        @Override
822        public int compare(DebugEntryTemplatePart de1,DebugEntryTemplatePart de2) {
823                long result=de2.getExeTime()-de1.getExeTime();
824                // we do this additional step to try to avoid ticket LUCEE-2076
825        return result>0L?1:(result<0L?-1:0);
826    }
827}