package railo.runtime.exp; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Set; import railo.commons.lang.StringUtil; import railo.runtime.PageContext; import railo.runtime.PageContextImpl; import railo.runtime.dump.DumpData; import railo.runtime.dump.DumpProperties; import railo.runtime.engine.ThreadLocalPageContext; import railo.runtime.op.Castable; import railo.runtime.op.Caster; import railo.runtime.op.Decision; import railo.runtime.reflection.Reflector; import railo.runtime.reflection.pairs.MethodInstance; import railo.runtime.type.Collection; import railo.runtime.type.KeyImpl; import railo.runtime.type.Objects; import railo.runtime.type.Struct; import railo.runtime.type.StructImpl; import railo.runtime.type.it.EntryIterator; import railo.runtime.type.it.KeyIterator; import railo.runtime.type.it.StringIterator; import railo.runtime.type.it.ValueIterator; import railo.runtime.type.util.ArrayUtil; import railo.runtime.type.util.KeyConstants; import railo.runtime.type.util.StructUtil; public class CatchBlockImpl extends StructImpl implements CatchBlock,Castable,Objects{ private static final long serialVersionUID = -3680961614605720352L; public static final Key ERROR_CODE = KeyImpl.intern("ErrorCode"); public static final Key EXTENDEDINFO = KeyImpl.intern("ExtendedInfo"); public static final Key EXTENDED_INFO = KeyImpl.intern("Extended_Info"); public static final Key TAG_CONTEXT = KeyImpl.intern("TagContext"); public static final Key STACK_TRACE = KeyImpl.intern("StackTrace"); public static final Key ADDITIONAL = KeyImpl.intern("additional"); private static final Object NULL = new Object(); private PageExceptionImpl exception; public CatchBlockImpl(PageExceptionImpl pe) { this.exception=pe; setEL(KeyConstants._Message, new SpecialItem(pe, KeyConstants._Message)); setEL(KeyConstants._Detail, new SpecialItem(pe, KeyConstants._Detail)); setEL(ERROR_CODE, new SpecialItem(pe, ERROR_CODE)); setEL(EXTENDEDINFO, new SpecialItem(pe, EXTENDEDINFO)); setEL(EXTENDED_INFO, new SpecialItem(pe, EXTENDED_INFO)); setEL(ADDITIONAL, new SpecialItem(pe, ADDITIONAL)); setEL(TAG_CONTEXT, new SpecialItem(pe, TAG_CONTEXT)); setEL(KeyConstants._type, new SpecialItem(pe, KeyConstants._type)); setEL(STACK_TRACE, new SpecialItem(pe, STACK_TRACE)); if(pe instanceof NativeException){ Throwable throwable = ((NativeException)pe).getRootCause(); Method[] mGetters = Reflector.getGetters(throwable.getClass()); Method getter; Collection.Key key; if(!ArrayUtil.isEmpty(mGetters)){ for(int i=0;i<mGetters.length;i++){ getter=mGetters[i]; if(getter.getDeclaringClass()==Throwable.class) { continue; } key=KeyImpl.init(Reflector.removeGetterPrefix(getter.getName())); if(STACK_TRACE.equalsIgnoreCase(key)) continue; setEL(key,new Pair(throwable,key, getter,false)); } } } } class SpecialItem { private PageExceptionImpl pe; private Key key; public SpecialItem(PageExceptionImpl pe, Key key) { this.pe=pe; this.key=key; } public Object get() { if(key==KeyConstants._Message) return StringUtil.emptyIfNull(pe.getMessage()); if(key==KeyConstants._Detail) return StringUtil.emptyIfNull(pe.getDetail()); if(key==ERROR_CODE) return StringUtil.emptyIfNull(pe.getErrorCode()); if(key==EXTENDEDINFO) return StringUtil.emptyIfNull(pe.getExtendedInfo()); if(key==EXTENDED_INFO) return StringUtil.emptyIfNull(pe.getExtendedInfo()); if(key==KeyConstants._type) return StringUtil.emptyIfNull(pe.getTypeAsString()); if(key==STACK_TRACE) return StringUtil.emptyIfNull(pe.getStackTraceAsString()); if(key==ADDITIONAL) return pe.getAddional(); if(key==TAG_CONTEXT) return pe.getTagContext(ThreadLocalPageContext.getConfig()); return null; } public void set(Object o){ try { if(!(o instanceof Pair)) { if(key==KeyConstants._Detail) { pe.setDetail(Caster.toString(o)); return; } else if(key==ERROR_CODE) { pe.setErrorCode(Caster.toString(o)); return; } else if(key==EXTENDEDINFO || key==EXTENDED_INFO) { pe.setExtendedInfo(Caster.toString(o)); return; } else if(key==STACK_TRACE) { if(o instanceof StackTraceElement[]){ pe.setStackTrace((StackTraceElement[])o); return; } else if(Decision.isCastableToArray(o)) { Object[] arr = Caster.toNativeArray(o); StackTraceElement[] elements=new StackTraceElement[arr.length]; for(int i=0;i<arr.length;i++) { if(arr[i] instanceof StackTraceElement) elements[i]=(StackTraceElement) arr[i]; else throw new CasterException(o, StackTraceElement[].class); } pe.setStackTrace(elements); return; } } } } catch(PageException pe){} superSetEL(key,o); } public Object remove(){ Object rtn=null; if(key==KeyConstants._Detail) { rtn=pe.getDetail(); pe.setDetail(""); } else if(key==ERROR_CODE) { rtn=pe.getErrorCode(); pe.setErrorCode("0"); } else if(key==EXTENDEDINFO || key==EXTENDED_INFO) { rtn=pe.getExtendedInfo(); pe.setExtendedInfo(null); } return rtn; } } /** * @return the pe */ public PageException getPageException() { return exception; } @Override public String castToString() throws ExpressionException { return castToString(null); } @Override public String castToString(String defaultValue) { return exception.getClass().getName(); } @Override public boolean containsValue(Object value) { Key[] keys = keys(); for(int i=0;i<keys.length;i++){ if(get(keys[i],null)==value) return true; } return false; } @Override public Collection duplicate(boolean deepCopy) { Struct sct=new StructImpl(); StructUtil.copy(this, sct, true); return sct; } @Override public Set entrySet() { return StructUtil.entrySet(this); } public void print(PageContext pc){ ((PageContextImpl)pc).handlePageException(exception); } @Override public Object get(Key key, Object defaultValue) { Object value = super.get(key,defaultValue); if(value instanceof SpecialItem) { return ((SpecialItem)value).get(); } else if(value instanceof Pair) { Pair pair=(Pair) value; try { Object res = pair.getter.invoke(pair.throwable, new Object[]{}); if(pair.doEmptyStringWhenNull && res==null) return ""; return res; } catch (Exception e) { return defaultValue; } } return value; } @Override public Object set(Key key, Object value) throws PageException { Object curr = super.get(key,null); if(curr instanceof SpecialItem){ ((SpecialItem)curr).set(value); return value; } else if(curr instanceof Pair){ Pair pair=(Pair) curr; MethodInstance setter = Reflector.getSetter(pair.throwable, pair.name.getString(), value,null); if(setter!=null){ try { setter.invoke(pair.throwable); return value; } catch (Exception e) { throw Caster.toPageException(e); } } } return super.set(key, value); } @Override public Object setEL(Key key, Object value) { Object curr = super.get(key,null); if(curr instanceof SpecialItem){ ((SpecialItem)curr).set(value); return value; } else if(curr instanceof Pair){ Pair pair=(Pair) curr; MethodInstance setter = Reflector.getSetter(pair.throwable, pair.name.getString(), value,null); if(setter!=null){ try { setter.invoke(pair.throwable); } catch (Exception e) {} return value; } } return super.setEL(key, value); } private Object superSetEL(Key key, Object value) { return super.setEL(key, value); } @Override public int size() { return keys().length; } @Override public Key[] keys() { Key[] keys = super.keys(); List<Key> list=new ArrayList<Key>(); for(int i=0;i<keys.length;i++){ if(get(keys[i], null)!=null)list.add(keys[i]); } return list.toArray(new Key[list.size()]); } @Override public Object remove(Key key) throws PageException { Object curr = super.get(key,null); if(curr instanceof SpecialItem){ return ((SpecialItem)curr).remove(); } else if(curr instanceof Pair){ Pair pair=(Pair) curr; MethodInstance setter = Reflector.getSetter(pair.throwable, pair.name.getString(), null,null); if(setter!=null){ try { Object before = pair.getter.invoke(pair.throwable, new Object[0]); setter.invoke(pair.throwable); return before; } catch (Exception e) { throw Caster.toPageException(e); } } } return super.remove(key); } @Override public Iterator<Collection.Key> keyIterator() { return new KeyIterator(keys()); } @Override public Iterator<String> keysAsStringIterator() { return new StringIterator(keys()); } @Override public Iterator<Entry<Key, Object>> entryIterator() { return new EntryIterator(this, keys()); } @Override public Iterator<Object> valueIterator() { return new ValueIterator(this, keys()); } @Override public java.util.Collection values() { return StructUtil.values(this); } @Override public DumpData toDumpData(PageContext pageContext, int maxlevel, DumpProperties dp) { return StructUtil.toDumpTable(this,"Catch",pageContext,maxlevel,dp); } class Pair{ Throwable throwable; Collection.Key name; Method getter; private boolean doEmptyStringWhenNull; public Pair(Throwable throwable,Key name, Method method,boolean doEmptyStringWhenNull) { this.throwable = throwable; this.name = name; this.getter = method; this.doEmptyStringWhenNull = doEmptyStringWhenNull; } public Pair(Throwable throwable,String name, Method method, boolean doEmptyStringWhenNull) { this(throwable, KeyImpl.init(name), method,doEmptyStringWhenNull); } public String toString(){ try { return Caster.toString(getter.invoke(throwable, new Object[]{})); } catch (Exception e) { throw new PageRuntimeException(Caster.toPageException(e)); } } } public Object call(PageContext pc, String methodName, Object[] arguments) throws PageException { Object obj=exception; if(exception instanceof NativeException) obj=((NativeException)exception).getRootCause(); if("dump".equalsIgnoreCase(methodName)){ print(pc); return null; } try{ return Reflector.callMethod(obj, methodName, arguments); } catch(PageException e){ return Reflector.callMethod(exception, methodName, arguments); } } public Object callWithNamedValues(PageContext pc, String methodName,Struct args) throws PageException { throw new ApplicationException("named arguments not supported"); } public Object callWithNamedValues(PageContext pc, Key methodName,Struct args) throws PageException { throw new ApplicationException("named arguments not supported"); } public boolean isInitalized() { return true; } public Object set(PageContext pc, String propertyName, Object value) throws PageException { return set(propertyName, value); } public Object set(PageContext pc, Key propertyName, Object value)throws PageException { return set(propertyName, value); } public Object setEL(PageContext pc, String propertyName, Object value) { return setEL(propertyName, value); } public Object setEL(PageContext pc, Key propertyName, Object value) { return setEL(propertyName, value); } public Object get(Key key) throws PageException { Object res = get(key,NULL); if(res!=NULL) return res; throw StructImpl.invalidKey(null,this, key); } public Object get(PageContext pc, String key, Object defaultValue) { return get(key,defaultValue); } public Object get(PageContext pc, Key key, Object defaultValue) { return get(key,defaultValue); } public Object get(PageContext pc, String key) throws PageException { return get(key); } public Object get(PageContext pc, Key key) throws PageException { return get(key); } public Object call(PageContext pc, Key methodName, Object[] arguments) throws PageException { return call(pc, methodName.getString(), arguments); } /*public Object remove (String key) throws PageException { return remove(KeyImpl.init(key)); }*/ public Object removeEL(Key key) { try { return remove(key); } catch (PageException e) { return null; } } }