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    }