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