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 }