001    package railo.runtime.exp;
002    
003    import java.io.IOException;
004    import java.io.PrintStream;
005    import java.io.PrintWriter;
006    import java.io.StringWriter;
007    import java.lang.reflect.InvocationTargetException;
008    import java.util.Iterator;
009    import java.util.LinkedList;
010    
011    import railo.commons.io.IOUtil;
012    import railo.commons.io.res.Resource;
013    import railo.commons.io.res.util.ResourceUtil;
014    import railo.commons.lang.StringUtil;
015    import railo.runtime.Info;
016    import railo.runtime.PageContext;
017    import railo.runtime.PageContextImpl;
018    import railo.runtime.PageSource;
019    import railo.runtime.config.Config;
020    import railo.runtime.dump.DumpData;
021    import railo.runtime.dump.DumpProperties;
022    import railo.runtime.dump.DumpTable;
023    import railo.runtime.dump.SimpleDumpData;
024    import railo.runtime.engine.ThreadLocalPageContext;
025    import railo.runtime.err.ErrorPage;
026    import railo.runtime.op.Caster;
027    import railo.runtime.type.Array;
028    import railo.runtime.type.ArrayImpl;
029    import railo.runtime.type.Collection;
030    import railo.runtime.type.Collection.Key;
031    import railo.runtime.type.KeyImpl;
032    import railo.runtime.type.Struct;
033    import railo.runtime.type.StructImpl;
034    import railo.runtime.type.dt.DateTimeImpl;
035    import railo.runtime.type.util.KeyConstants;
036    import railo.runtime.type.util.ListUtil;
037    import railo.runtime.writer.CFMLWriter;
038    
039    /**
040     * Railo Runtime Page Exception, all runtime Exception are sub classes of this class
041     */
042    public abstract class PageExceptionImpl extends PageException {
043    
044            private static final Collection.Key RAW_TRACE = KeyImpl.intern("raw_trace");
045            private static final Collection.Key CODE_PRINT_HTML = KeyImpl.intern("codePrintHTML");
046            private static final Collection.Key CODE_PRINT_PLAIN = KeyImpl.intern("codePrintPlain");
047            
048            
049            
050            
051            private Array tagContext=new ArrayImpl();
052            private Struct additional=new StructImpl(Struct.TYPE_LINKED);
053            /**
054             * Field <code>detail</code>
055             */
056            protected String detail="";
057            //private Throwable rootCause;
058            private int tracePointer;
059            private String errorCode="0";
060            private String extendedInfo=null;
061    
062            private String type;
063            private String customType;
064            private boolean isInitTagContext=false;
065            private LinkedList sources=new LinkedList();
066            private String varName;
067    
068    
069            /**
070             * Class Constructor
071             * @param message Exception Message
072             * @param type Type as String
073             */
074            public PageExceptionImpl(String message,String type) {
075                    this(message,type,null);
076            }
077            /**
078             * Class Constructor
079             * @param message Exception Message
080             * @param type Type as String
081             * @param customType CUstom Type as String
082             */
083            public PageExceptionImpl(String message,String type, String customType) {
084                    super(message==null?"":message);
085                    //rootCause=this;
086                    this.type=type.toLowerCase().trim();
087                    this.customType=customType;
088            //setAdditional("customType",getCustomTypeAsString());
089            }
090            
091            /**
092             * Class Constructor
093             * @param e exception
094             * @param type Type as String
095             */
096            public PageExceptionImpl(Throwable e,String type) {
097                    this(e,type,null);
098            }
099            
100            /**
101             * Class Constructor
102             * @param e exception
103             * @param type Type as String
104             * @param customType CUstom Type as String
105             */
106            public PageExceptionImpl(Throwable e,String type, String customType) {
107                    super(StringUtil.isEmpty(e.getMessage(),true)?e.getClass().getName():e.getMessage());
108                    if(e instanceof InvocationTargetException)e=((InvocationTargetException)e).getTargetException();
109            
110            //this.i
111            initCause(e);
112            //this.setStackTrace(e.getStackTrace());
113            
114                    if(e instanceof IPageException) {
115                IPageException pe=(IPageException)e;
116                            this.additional=pe.getAddional();
117                            this.setDetail(pe.getDetail());
118                            this.setErrorCode(pe.getErrorCode());
119                            this.setExtendedInfo(pe.getExtendedInfo());
120                    }
121                    
122                    //else if(e.getCause()!=null)rootCause=e.getCause();
123                    //else rootCause=e;
124    
125                    this.type=type.trim();
126                    this.customType=(customType==null)?this.type:customType;
127            }
128        
129        @Override
130            public String getDetail() { 
131                    if(detail==null || detail.equals(getMessage()))return "";
132                    return detail; 
133            }
134            
135            @Override
136            public String getErrorCode() { return errorCode==null?"":errorCode; }
137            
138            @Override
139            public String getExtendedInfo() { return extendedInfo==null?"":extendedInfo; }
140            
141            @Override
142            public void setDetail(String detail) {
143                    this.detail=detail;
144            }
145            @Override
146            public void setErrorCode(String errorCode) {
147                    this.errorCode=errorCode;
148            }
149            @Override
150            public void setExtendedInfo(String extendedInfo) {
151                    this.extendedInfo=extendedInfo;
152            }
153            
154            public final Struct getCatchBlock() {
155                    return getCatchBlock(ThreadLocalPageContext.getConfig());
156            }
157            
158            @Override
159            public final Struct getCatchBlock(PageContext pc) {
160                    return getCatchBlock(ThreadLocalPageContext.getConfig(pc));
161            }
162            
163            @Override
164            public CatchBlock getCatchBlock(Config config) {
165                    return new CatchBlockImpl(this);
166            }
167            
168            public Array getTagContext(Config config) {
169                    if(isInitTagContext) return tagContext;
170                    _getTagContext( config,tagContext,this,sources);
171                    isInitTagContext=true;
172                    return tagContext;
173            }
174            
175    
176            public static Array getTagContext(Config config,StackTraceElement[] traces) {
177                    Array tagContext=new ArrayImpl();
178                    _getTagContext( config,tagContext,traces,new LinkedList());
179                    return tagContext;
180            }
181            
182    
183            private static void _getTagContext(Config config, Array tagContext, Throwable t, LinkedList sources) {
184                    _getTagContext(config, tagContext, getStackTraceElements(t), sources);
185            }
186            
187            private static void _getTagContext(Config config, Array tagContext, StackTraceElement[] traces, 
188                            LinkedList sources) {
189                    //StackTraceElement[] traces = getStackTraceElements(t);
190                    
191                    int line=0;
192                    String template="",tlast;
193                    Struct item;
194                    StackTraceElement trace=null;
195                    int index=-1;
196                    PageSource ps;
197                    for(int i=0;i<traces.length;i++) {
198                            trace=traces[i];
199                            tlast=template;
200                            template=trace.getFileName();
201                            if(trace.getLineNumber()<=0 || template==null || ResourceUtil.getExtension(template,"").equals("java")) continue;
202                            // content
203                            if(!StringUtil.emptyIfNull(tlast).equals(template))index++;
204                            
205                            String[] content=null;
206                            try {
207                                    
208                                    Resource res = config.getResource(template);
209                                    
210                                    // never happens i think
211                                    if(!res.exists()) {
212                                            res = ResourceUtil.toResourceNotExisting(ThreadLocalPageContext.get(), template);
213                                    }
214                                     
215                                    if(res.exists())        
216                                            content=IOUtil.toStringArray(IOUtil.getReader(res,config.getTemplateCharset()));
217                                    else {
218                                            if(sources.size()>index)ps=(PageSource) sources.get(index);
219                                            else ps=null;
220                                            if(ps!=null && trace.getClassName().equals(ps.getFullClassName())) {
221                                                    if(ps.physcalExists())
222                                                            content=IOUtil.toStringArray(IOUtil.getReader(ps.getPhyscalFile(), config.getTemplateCharset()));
223                                                    template=ps.getDisplayPath();
224                                            }
225                                    }       
226                            } 
227                            catch (Throwable th) {
228                                    //th.printStackTrace();
229                            }
230                            
231                            // check last
232                            if(tagContext.size()>0){
233                                    try {
234                                            Struct last=(Struct) tagContext.getE(tagContext.size());
235                                            if(last.get(RAW_TRACE).equals(trace.toString()))continue;
236                                    } 
237                                    catch (Exception e) {
238                                            //e.printStackTrace();
239                                    }
240                            }
241                            
242                            item=new StructImpl();
243                            line=trace.getLineNumber();
244                            item.setEL(KeyConstants._template,template);
245                            item.setEL(KeyConstants._line,new Double(line));
246                            item.setEL(KeyConstants._id,"??");
247                            item.setEL(RAW_TRACE,trace.toString());
248                            item.setEL(KeyConstants._type,"cfml");
249                            item.setEL(KeyConstants._column,new Double(0));
250                            if(content!=null) {
251                                    item.setEL(CODE_PRINT_HTML,getCodePrint(content,line,true));
252                                    item.setEL(CODE_PRINT_PLAIN,getCodePrint(content,line,false));
253                            }
254                            else {
255                                    item.setEL(CODE_PRINT_HTML,"");
256                                    item.setEL(CODE_PRINT_PLAIN,"");
257                            }
258                            // FUTURE id 
259                            tagContext.appendEL(item);
260                    }
261            }
262            
263            
264            
265            public int getPageDeep() {
266                    StackTraceElement[] traces = getStackTraceElements(this);
267                    
268                    String template="",tlast;
269                    StackTraceElement trace=null;
270                    int index=0;
271                    for(int i=0;i<traces.length;i++) {
272                            trace=traces[i];
273                            tlast=template;
274                            template=trace.getFileName();
275                            if(trace.getLineNumber()<=0 || template==null || ResourceUtil.getExtension(template,"").equals("java")) continue;
276                            if(!StringUtil.emptyIfNull(tlast).equals(template))index++;
277                            
278                    }
279                    return index;
280            }
281            
282            
283            @Override
284            public Struct getErrorBlock(PageContext pc,ErrorPage ep) {
285                    Struct struct=new StructImpl();
286    
287                    struct.setEL("browser",pc.cgiScope().get("HTTP_USER_AGENT",""));
288                    struct.setEL("datetime",new DateTimeImpl(pc));
289                    struct.setEL("diagnostics",getMessage()+' '+getDetail()+"<br>The error occurred on line "+getLine(pc.getConfig())+" in file "+getFile(pc.getConfig())+".");
290                    struct.setEL("GeneratedContent",getGeneratedContent(pc));
291                    struct.setEL("HTTPReferer",pc.cgiScope().get("HTTP_REFERER",""));
292                    struct.setEL("mailto",ep.getMailto());
293                    struct.setEL(KeyConstants._message,getMessage());
294                    struct.setEL("QueryString",StringUtil.emptyIfNull(pc. getHttpServletRequest().getQueryString()));
295                    struct.setEL("RemoteAddress",pc.cgiScope().get("REMOTE_ADDR",""));
296                    struct.setEL("RootCause",getCatchBlock(pc));
297                    struct.setEL("StackTrace",getStackTraceAsString());
298                    struct.setEL(KeyConstants._template,pc. getHttpServletRequest().getServletPath());
299                    
300                            struct.setEL(KeyConstants._Detail,getDetail());
301                            struct.setEL("ErrorCode",getErrorCode());
302                            struct.setEL("ExtendedInfo",getExtendedInfo());
303                            struct.setEL(KeyConstants._type,getTypeAsString());
304                            struct.setEL("TagContext",getTagContext(pc.getConfig()));
305                            struct.setEL("additional",additional);
306                            // TODO RootCause,StackTrace
307                    
308                    return struct;
309            }
310            
311            private String getGeneratedContent(PageContext pc){
312                    PageContextImpl pci=(PageContextImpl)pc;
313                    CFMLWriter ro=pci.getRootOut();
314                    String gc=ro.toString();
315                    try{
316                            ro.clearBuffer();
317                    }
318                    catch(IOException ioe){}
319                    if(gc==null) return "";
320                    return gc;
321            }
322            
323            
324            /**
325             * @return return the file where the failure occurred
326             */
327            private String getFile(Config config) {
328            if(getTagContext(config).size()==0) return "";
329            
330            Struct sct=(Struct) getTagContext(config).get(1,null);
331            return Caster.toString(sct.get("template",""),"");
332        }
333        
334            public String getLine(Config config) {
335            if(getTagContext(config).size()==0) return "";
336            
337            Struct sct=(Struct) getTagContext(config).get(1,null);
338            return Caster.toString(sct.get("line",""),"");
339        }
340        
341            @Override
342            public void addContext(PageSource pr, int line, int column, StackTraceElement element) {
343                    if(line==-187) {
344                            sources.add(pr);
345                            return;
346                    }
347            
348                    Struct struct=new StructImpl();
349            //print.out(pr.getDisplayPath());
350                    try {
351                            String[] content=pr.getSource();
352                            struct.set(KeyConstants._template,pr.getDisplayPath());
353                            struct.set(KeyConstants._line,new Double(line));
354                            struct.set(KeyConstants._id,"??");
355                            struct.set("Raw_Trace",(element!=null)?element.toString():"");
356                            struct.set(KeyConstants._Type,"cfml");
357                            struct.set(KeyConstants._column,new Double(column));
358                            if(content!=null){
359                                    struct.set(CODE_PRINT_HTML,getCodePrint(content,line,true));
360                                    struct.set(CODE_PRINT_PLAIN,getCodePrint(content,line,false));
361                            }
362                            tagContext.append(struct);
363                    } 
364                    catch (Exception e) {}
365            }
366            
367            private static String getCodePrint(String[] content,int line, boolean asHTML ) {
368                    StringBuffer sb=new StringBuffer();
369                    // bad Line
370                    for(int i=line-2;i<line+3;i++) {
371                            if(i>0 && i<=content.length) {
372                                    if(asHTML && i==line)sb.append("<b>");
373                                    if(asHTML)sb.append(i+": "+StringUtil.escapeHTML(content[i-1]));
374                                    else sb.append(i+": "+(content[i-1]));
375                                    if(asHTML && i==line)sb.append("</b>");
376                                    if(asHTML)sb.append("<br>");
377                                    sb.append('\n');
378                            }
379                    }
380                    return sb.toString();
381            }
382            
383            @Override
384            public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) {
385                    
386                    //FFFFCF
387            DumpTable htmlBox = new DumpTable("exception","#ff9900","#FFCC00","#000000");
388                    htmlBox.setTitle("Railo ["+Info.getVersionAsString()+"] - Error ("+StringUtil.ucFirst(getTypeAsString())+")");
389                    
390                    
391                    // Message
392                    htmlBox.appendRow(1,new SimpleDumpData("Message"),new SimpleDumpData(getMessage()));
393                    
394                    // Detail
395                    String detail=getDetail();
396                    if(!StringUtil.isEmpty(detail,true))
397                            htmlBox.appendRow(1,new SimpleDumpData("Detail"),new SimpleDumpData(detail));
398                    
399                    // additional
400                    Iterator<Key> it = additional.keyIterator();
401                    Collection.Key k;
402                    while(it.hasNext()) {
403                            k=it.next();
404                            htmlBox.appendRow(1,new SimpleDumpData(k.getString()),new SimpleDumpData(additional.get(k,"").toString()));
405                    }
406                    
407                    Array tagContext = getTagContext(pageContext.getConfig());
408                    // Context MUSTMUST
409                    if(tagContext.size()>0) {
410                            //Collection.Key[] keys=tagContext.keys();
411                            Iterator<Object> vit = tagContext.valueIterator();
412                            //Entry<Key, Object> te;
413                            DumpTable context=new DumpTable("#ff9900","#FFCC00","#000000");
414                            //context.setTitle("The Error Occurred in");
415                            //context.appendRow(0,new SimpleDumpData("The Error Occurred in"));
416                            context.appendRow(7,
417                                            new SimpleDumpData(""),
418                                            new SimpleDumpData("template"),
419                                            new SimpleDumpData("line"));
420                            try {
421                                    boolean first=true;
422                                    while(vit.hasNext()) {
423                                            Struct struct=(Struct)vit.next();
424                                            context.appendRow(1,
425                                                            new SimpleDumpData(first?"called from ":"occurred in"),
426                                                            new SimpleDumpData(struct.get(KeyConstants._template,"")+""),
427                                                            new SimpleDumpData(Caster.toString(struct.get(KeyConstants._line,null))));
428                                            first=false;
429                                    }
430                                    htmlBox.appendRow(1,new SimpleDumpData("Context"),context);
431                                    
432                                    
433                                    // Code
434                                    String strCode=((Struct)tagContext.get(1,null)).get("codePrintPlain","").toString();
435                                    String[] arrCode = ListUtil.listToStringArray(strCode, '\n');
436                                    arrCode=ListUtil.trim(arrCode);
437                                    DumpTable code=new DumpTable("#ff9900","#FFCC00","#000000");
438                                    
439                                    for(int i=0;i<arrCode.length;i++) {
440                                            code.appendRow(i==2?1:0,new SimpleDumpData(arrCode[i]));
441                                    }
442                                    htmlBox.appendRow(1,new SimpleDumpData("Code"),code);
443    
444                            } 
445                catch (PageException e) {}
446                    }
447                    
448                    
449                    // Java Stacktrace
450                    String strST=getStackTraceAsString();
451                    String[] arrST = ListUtil.listToStringArray(strST, '\n');
452                    arrST=ListUtil.trim(arrST);
453                    DumpTable st=new DumpTable("#ff9900","#FFCC00","#000000");
454                    
455                    for(int i=0;i<arrST.length;i++) {
456                            st.appendRow(i==0?1:0,new SimpleDumpData(arrST[i]));
457                    }
458                    htmlBox.appendRow(1,new SimpleDumpData("Java Stacktrace"),st);
459    
460                    return htmlBox; 
461            }       
462            
463            @Override
464            public String getStackTraceAsString() {
465                    
466            StringWriter sw=new StringWriter();
467                PrintWriter pw=new PrintWriter(sw);
468            printStackTrace(pw);
469            pw.flush();
470            return sw.toString();
471        }
472        
473        
474        
475        @Override
476        public void printStackTrace() {
477            printStackTrace(System.err);
478        }
479        
480        @Override
481        public void printStackTrace(PrintStream s) {
482            StackTraceElement[] traces = getStackTraceElements(this);
483            StackTraceElement trace;
484            
485            s.println(getMessage());
486            for(int i=0;i<traces.length;i++){
487                trace=traces[i];
488                s.println("\tat "+trace);
489            }
490        }
491        
492        @Override
493        public void printStackTrace(PrintWriter s) {
494            StackTraceElement[] traces = getStackTraceElements(this);
495            StackTraceElement trace;
496            
497            s.println(getMessage());
498            for(int i=0;i<traces.length;i++){
499                trace=traces[i];
500                s.println("\tat "+trace+":"+trace.getLineNumber());
501            }
502        }
503        
504    
505        private static StackTraceElement[] getStackTraceElements(Throwable t) {
506            StackTraceElement[] st=getStackTraceElements(t,true);
507            if(st==null) st= getStackTraceElements(t,false);
508            return st;
509        }
510        
511        private static StackTraceElement[] getStackTraceElements(Throwable t, boolean onlyWithCML) {
512            StackTraceElement[] st;
513            Throwable cause=t.getCause();
514            if(cause!=null){
515                    st = getStackTraceElements(cause,onlyWithCML);
516                    if(st!=null) return st;
517            }
518            
519            st=t.getStackTrace();
520            if(!onlyWithCML || hasCFMLinStacktrace(st)){
521                    return st;
522            }
523            return null;
524            }
525        
526    
527        private static boolean hasCFMLinStacktrace(StackTraceElement[] traces) {
528                    for(int i=0;i<traces.length;i++) {
529                            if(traces[i].getFileName()!=null && !traces[i].getFileName().endsWith(".java")) return true;
530                    }
531                    return false;
532            }
533        /*ths code has produced duplettes
534         * private static void fillStackTraceElements(ArrayList<StackTraceElement> causes, Throwable t) {
535                    if(t==null) return;
536                    fillStackTraceElements(causes, t.getCause());
537                    StackTraceElement[] traces = t.getStackTrace();
538                    for(int i=0;i<traces.length;i++) {
539                            //if(causes.contains(traces[i]))
540                            causes.add(traces[i]);
541                    }
542            }*/
543        
544            /**
545             * set a additional key value
546             * @param key
547             * @param value
548             */
549            public void setAdditional(Collection.Key key, Object value) {
550                    additional.setEL(key,StringUtil.toStringEmptyIfNull(value));
551            }
552            
553            
554            @Override
555            public Throwable getRootCause() {
556            Throwable cause=this; 
557            Throwable temp; 
558            
559            while((temp=cause.getCause())!=null)cause=temp;
560            return cause;
561            }
562    
563            @Override
564            public int getTracePointer() {
565                    return tracePointer;
566            }
567            @Override
568            public void setTracePointer(int tracePointer) {
569                    this.tracePointer = tracePointer;
570            }
571            
572            @Override
573        public boolean typeEqual(String type) {
574            if(type==null) return true;
575            type=StringUtil.toUpperCase(type);
576            // ANY
577            if(type.equals("ANY")) return true;// MUST check
578            // Type Compare
579            if(getTypeAsString().equalsIgnoreCase(type)) return true;
580            return getClass().getName().equalsIgnoreCase(type);
581        }
582        
583        @Override
584            public String getTypeAsString() {
585                    return type;
586            }
587            
588            @Override
589            public String getCustomTypeAsString() {
590                    return customType==null?type:customType;
591            }
592        
593        @Override
594            public Struct getAdditional() {
595            return additional;
596        }public Struct getAddional() {
597            return additional;
598        }
599        
600        @Override
601        public StackTraceElement[] getStackTrace() {
602            return super.getStackTrace();
603        }
604        
605        /*public static void printStackTrace(PrintWriter s,Throwable t) {
606            
607            //while((temp=cause.getCause())!=null)cause=temp;
608            
609            StackTraceElement[] traces = t.getStackTrace();
610            StackTraceElement trace;
611            
612            s.println(t.getMessage());
613            for(int i=0;i<traces.length;i++){
614                trace=traces[i];
615                s.println("\tat "+trace+":"+trace.getLineNumber());
616            }
617            t=t.getCause();
618            if(t!=null)printStackTrace(s,t);
619        }*/
620        
621        
622        
623    }