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