001 package railo.runtime.exp; 002 003 import java.lang.reflect.Method; 004 import java.util.ArrayList; 005 import java.util.Iterator; 006 import java.util.List; 007 import java.util.Set; 008 009 import railo.commons.lang.StringUtil; 010 import railo.runtime.PageContext; 011 import railo.runtime.PageContextImpl; 012 import railo.runtime.dump.DumpData; 013 import railo.runtime.dump.DumpProperties; 014 import railo.runtime.engine.ThreadLocalPageContext; 015 import railo.runtime.op.Castable; 016 import railo.runtime.op.Caster; 017 import railo.runtime.op.Decision; 018 import railo.runtime.reflection.Reflector; 019 import railo.runtime.reflection.pairs.MethodInstance; 020 import railo.runtime.type.Collection; 021 import railo.runtime.type.KeyImpl; 022 import railo.runtime.type.Objects; 023 import railo.runtime.type.Struct; 024 import railo.runtime.type.StructImpl; 025 import railo.runtime.type.it.KeyIterator; 026 import railo.runtime.type.util.ArrayUtil; 027 import railo.runtime.type.util.StructUtil; 028 029 public class CatchBlock extends StructImpl implements Castable, Objects{ 030 031 private static final long serialVersionUID = -4868635413052937742L; 032 033 public static final Key MESSAGE = KeyImpl.intern("Message"); 034 public static final Key DETAIL = KeyImpl.intern("Detail"); 035 public static final Key ERROR_CODE = KeyImpl.intern("ErrorCode"); 036 public static final Key EXTENDED_INFO = KeyImpl.intern("ExtendedInfo"); 037 public static final Key TAG_CONTEXT = KeyImpl.intern("TagContext"); 038 public static final Key STACK_TRACE = KeyImpl.intern("StackTrace"); 039 public static final Key ADDITIONAL = KeyImpl.intern("additional"); 040 private static final Object NULL = new Object(); 041 042 private PageExceptionImpl exception; 043 044 045 public CatchBlock(PageExceptionImpl pe) { 046 this.exception=pe; 047 048 setEL(MESSAGE, new SpecialItem(pe, MESSAGE)); 049 setEL(DETAIL, new SpecialItem(pe, DETAIL)); 050 setEL(ERROR_CODE, new SpecialItem(pe, ERROR_CODE)); 051 setEL(EXTENDED_INFO, new SpecialItem(pe, EXTENDED_INFO)); 052 setEL(ADDITIONAL, new SpecialItem(pe, ADDITIONAL)); 053 setEL(TAG_CONTEXT, new SpecialItem(pe, TAG_CONTEXT)); 054 setEL(KeyImpl.TYPE, new SpecialItem(pe, KeyImpl.TYPE)); 055 setEL(STACK_TRACE, new SpecialItem(pe, STACK_TRACE)); 056 057 058 if(pe instanceof NativeException){ 059 Throwable throwable = ((NativeException)pe).getRootCause(); 060 Method[] mGetters = Reflector.getGetters(throwable.getClass()); 061 Method getter; 062 Collection.Key key; 063 if(!ArrayUtil.isEmpty(mGetters)){ 064 for(int i=0;i<mGetters.length;i++){ 065 getter=mGetters[i]; 066 if(getter.getDeclaringClass()==Throwable.class) { 067 continue; 068 } 069 key=KeyImpl.init(Reflector.removeGetterPrefix(getter.getName())); 070 setEL(key,new Pair(throwable,key, getter,false)); 071 } 072 } 073 } 074 } 075 076 077 class SpecialItem { 078 private PageExceptionImpl pe; 079 private Key key; 080 081 public SpecialItem(PageExceptionImpl pe, Key key) { 082 this.pe=pe; 083 this.key=key; 084 } 085 086 public Object get() { 087 if(key==MESSAGE) return StringUtil.emptyIfNull(pe.getMessage()); 088 if(key==DETAIL) return StringUtil.emptyIfNull(pe.getDetail()); 089 if(key==ERROR_CODE) return StringUtil.emptyIfNull(pe.getErrorCode()); 090 if(key==EXTENDED_INFO) return StringUtil.emptyIfNull(pe.getExtendedInfo()); 091 if(key==KeyImpl.TYPE) return StringUtil.emptyIfNull(pe.getTypeAsString()); 092 if(key==STACK_TRACE) return StringUtil.emptyIfNull(pe.getStackTraceAsString()); 093 if(key==ADDITIONAL) return pe.getAddional(); 094 if(key==TAG_CONTEXT) return pe.getTagContext(ThreadLocalPageContext.getConfig()); 095 return null; 096 } 097 098 public void set(Object o){ 099 try { 100 if(!(o instanceof Pair)) { 101 if(key==DETAIL) { 102 pe.setDetail(Caster.toString(o)); 103 return; 104 } 105 else if(key==ERROR_CODE) { 106 pe.setErrorCode(Caster.toString(o)); 107 return; 108 } 109 else if(key==EXTENDED_INFO) { 110 pe.setExtendedInfo(Caster.toString(o)); 111 return; 112 } 113 else if(key==STACK_TRACE) { 114 if(o instanceof StackTraceElement[]){ 115 pe.setStackTrace((StackTraceElement[])o); 116 return; 117 } 118 else if(Decision.isCastableToArray(o)) { 119 Object[] arr = Caster.toNativeArray(o); 120 StackTraceElement[] elements=new StackTraceElement[arr.length]; 121 for(int i=0;i<arr.length;i++) { 122 if(arr[i] instanceof StackTraceElement) 123 elements[i]=(StackTraceElement) arr[i]; 124 else 125 throw new CasterException(o, StackTraceElement[].class); 126 } 127 pe.setStackTrace(elements); 128 return; 129 130 } 131 } 132 } 133 } 134 catch(PageException pe){} 135 136 superSetEL(key,o); 137 138 139 } 140 public Object remove(){ 141 Object rtn=null; 142 if(key==DETAIL) { 143 rtn=pe.getDetail(); 144 pe.setDetail(""); 145 } 146 else if(key==ERROR_CODE) { 147 rtn=pe.getErrorCode(); 148 pe.setErrorCode("0"); 149 } 150 else if(key==EXTENDED_INFO) { 151 rtn=pe.getExtendedInfo(); 152 pe.setExtendedInfo(null); 153 } 154 return rtn; 155 156 } 157 } 158 159 160 /** 161 * FUTURE add to interface 162 * @return the pe 163 */ 164 public PageException getPageException() { 165 return exception; 166 } 167 168 /** 169 * 170 * @see railo.runtime.type.StructImpl#castToString() 171 */ 172 public String castToString() throws ExpressionException { 173 return castToString(null); 174 } 175 176 /** 177 * @see railo.runtime.type.util.StructSupport#castToString(java.lang.String) 178 */ 179 public String castToString(String defaultValue) { 180 return exception.getClass().getName(); 181 } 182 183 /** 184 * 185 * @see railo.runtime.type.StructImpl#containsValue(java.lang.Object) 186 */ 187 public boolean containsValue(Object value) { 188 Key[] keys = keys(); 189 for(int i=0;i<keys.length;i++){ 190 if(get(keys[i],null)==value) return true; 191 } 192 return false; 193 } 194 195 /** 196 * 197 * @see railo.runtime.type.StructImpl#duplicate(boolean) 198 */ 199 public Collection duplicate(boolean deepCopy) { 200 Struct sct=new StructImpl(); 201 StructUtil.copy(this, sct, true); 202 return sct; 203 } 204 205 /** 206 * 207 * @see railo.runtime.type.StructImpl#entrySet() 208 */ 209 public Set entrySet() { 210 return StructUtil.entrySet(this); 211 } 212 213 public void print(PageContext pc){ 214 ((PageContextImpl)pc).handlePageException(exception); 215 216 } 217 218 /** 219 * 220 * @see railo.runtime.type.StructImpl#get(railo.runtime.type.Collection.Key, java.lang.Object) 221 */ 222 public Object get(Key key, Object defaultValue) { 223 Object value = super.get(key,defaultValue); 224 if(value instanceof SpecialItem) { 225 return ((SpecialItem)value).get(); 226 } 227 else if(value instanceof Pair) { 228 Pair pair=(Pair) value; 229 try { 230 Object res = pair.getter.invoke(pair.throwable, new Object[]{}); 231 if(pair.doEmptyStringWhenNull && res==null) return ""; 232 return res; 233 } 234 catch (Exception e) { 235 return defaultValue; 236 } 237 } 238 return value; 239 } 240 241 /** 242 * @see railo.runtime.type.StructImpl#set(railo.runtime.type.Collection.Key, java.lang.Object) 243 */ 244 public Object set(Key key, Object value) throws PageException { 245 Object curr = super.get(key,null); 246 247 if(curr instanceof SpecialItem){ 248 ((SpecialItem)curr).set(value); 249 return value; 250 } 251 else if(curr instanceof Pair){ 252 Pair pair=(Pair) curr; 253 MethodInstance setter = Reflector.getSetter(pair.throwable, pair.name.getString(), value,null); 254 if(setter!=null){ 255 try { 256 setter.invoke(pair.throwable); 257 return value; 258 } catch (Exception e) { 259 throw Caster.toPageException(e); 260 } 261 } 262 } 263 264 return super.set(key, value); 265 } 266 267 /** 268 * @see railo.runtime.type.StructImpl#setEL(railo.runtime.type.Collection.Key, java.lang.Object) 269 */ 270 public Object setEL(Key key, Object value) { 271 Object curr = super.get(key,null); 272 if(curr instanceof SpecialItem){ 273 ((SpecialItem)curr).set(value); 274 return value; 275 } 276 else if(curr instanceof Pair){ 277 Pair pair=(Pair) curr; 278 MethodInstance setter = Reflector.getSetter(pair.throwable, pair.name.getString(), value,null); 279 if(setter!=null){ 280 try { 281 setter.invoke(pair.throwable); 282 } catch (Exception e) {} 283 return value; 284 } 285 } 286 return super.setEL(key, value); 287 } 288 289 private Object superSetEL(Key key, Object value) { 290 return super.setEL(key, value); 291 } 292 293 /** 294 * @see railo.runtime.type.StructImpl#size() 295 */ 296 public int size() { 297 return keys().length; 298 } 299 300 /** 301 * @see railo.runtime.type.StructImpl#keys() 302 */ 303 public Key[] keys() { 304 Key[] keys = super.keys(); 305 List<Key> list=new ArrayList<Key>(); 306 for(int i=0;i<keys.length;i++){ 307 if(get(keys[i], null)!=null)list.add(keys[i]); 308 } 309 return list.toArray(new Key[list.size()]); 310 } 311 312 /** 313 * @see railo.runtime.type.StructImpl#keysAsString() 314 */ 315 public String[] keysAsString() { 316 Key[] keys = keys(); 317 String[] strKeys=new String[keys.length]; 318 for(int i=0;i<keys.length;i++){ 319 strKeys[i]=keys[i].getString(); 320 } 321 return strKeys; 322 } 323 324 /* (non-Javadoc) 325 * @see railo.runtime.type.StructImpl#remove(railo.runtime.type.Collection.Key) 326 */ 327 @Override 328 public Object remove(Key key) throws PageException { 329 Object curr = super.get(key,null); 330 if(curr instanceof SpecialItem){ 331 return ((SpecialItem)curr).remove(); 332 } 333 else if(curr instanceof Pair){ 334 Pair pair=(Pair) curr; 335 MethodInstance setter = Reflector.getSetter(pair.throwable, pair.name.getString(), null,null); 336 if(setter!=null){ 337 try { 338 Object before = pair.getter.invoke(pair.throwable, new Object[0]); 339 setter.invoke(pair.throwable); 340 return before; 341 } catch (Exception e) { 342 throw Caster.toPageException(e); 343 } 344 } 345 } 346 return super.remove(key); 347 } 348 349 /** 350 * @see railo.runtime.type.StructImpl#keyIterator() 351 */ 352 public Iterator keyIterator() { 353 return new KeyIterator(keys()); 354 } 355 356 /** 357 * @see railo.runtime.type.util.StructSupport#keySet() 358 */ 359 public Set keySet() { 360 return StructUtil.keySet(this); 361 } 362 363 /** 364 * 365 * @see railo.runtime.type.StructImpl#values() 366 */ 367 public java.util.Collection values() { 368 throw new RuntimeException("not supported"); 369 } 370 371 372 /** 373 * 374 * @see railo.runtime.type.StructImpl#toDumpData(railo.runtime.PageContext, int) 375 */ 376 public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { 377 return StructUtil.toDumpTable(this,"Catch",pageContext,maxlevel,dp); 378 } 379 380 381 382 class Pair{ 383 Throwable throwable; 384 Collection.Key name; 385 Method getter; 386 private boolean doEmptyStringWhenNull; 387 388 public Pair(Throwable throwable,Key name, Method method,boolean doEmptyStringWhenNull) { 389 this.throwable = throwable; 390 this.name = name; 391 this.getter = method; 392 this.doEmptyStringWhenNull = doEmptyStringWhenNull; 393 } 394 public Pair(Throwable throwable,String name, Method method, boolean doEmptyStringWhenNull) { 395 this(throwable, KeyImpl.init(name), method,doEmptyStringWhenNull); 396 } 397 398 public String toString(){ 399 try { 400 return Caster.toString(getter.invoke(throwable, new Object[]{})); 401 } catch (Exception e) { 402 throw new PageRuntimeException(Caster.toPageException(e)); 403 } 404 } 405 } 406 407 public Object call(PageContext pc, String methodName, Object[] arguments) throws PageException { 408 Object obj=exception; 409 if(exception instanceof NativeException) obj=((NativeException)exception).getRootCause(); 410 try{ 411 return Reflector.callMethod(obj, methodName, arguments); 412 } 413 catch(PageException e){ 414 return Reflector.callMethod(exception, methodName, arguments); 415 } 416 } 417 418 419 420 421 public Object callWithNamedValues(PageContext pc, String methodName,Struct args) throws PageException { 422 throw new ApplicationException("named arguments not supported"); 423 } 424 425 public Object callWithNamedValues(PageContext pc, Key methodName,Struct args) throws PageException { 426 throw new ApplicationException("named arguments not supported"); 427 } 428 public boolean isInitalized() { 429 return true; 430 } 431 432 public Object set(PageContext pc, String propertyName, Object value) throws PageException { 433 return set(propertyName, value); 434 } 435 436 public Object set(PageContext pc, Key propertyName, Object value)throws PageException { 437 return set(propertyName, value); 438 } 439 440 public Object setEL(PageContext pc, String propertyName, Object value) { 441 return setEL(propertyName, value); 442 } 443 444 public Object setEL(PageContext pc, Key propertyName, Object value) { 445 return setEL(propertyName, value); 446 } 447 public Object get(Key key) throws PageException { 448 Object res = get(key,NULL); 449 if(res!=NULL) return res; 450 throw StructImpl.invalidKey(keysAsString(), key); 451 } 452 public Object get(PageContext pc, String key, Object defaultValue) { 453 return get(key,defaultValue); 454 } 455 456 public Object get(PageContext pc, Key key, Object defaultValue) { 457 return get(key,defaultValue); 458 } 459 460 public Object get(PageContext pc, String key) throws PageException { 461 return get(key); 462 } 463 464 public Object get(PageContext pc, Key key) throws PageException { 465 return get(key); 466 } 467 public Object call(PageContext pc, Key methodName, Object[] arguments) throws PageException { 468 return call(pc, methodName.getString(), arguments); 469 } 470 public Object remove(String key) throws PageException { 471 return remove(KeyImpl.init(key)); 472 } 473 public Object removeEL(Key key) { 474 try { 475 return remove(key); 476 } catch (PageException e) { 477 return null; 478 } 479 } 480 }