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