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