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.commons.lang;
020
021import java.io.IOException;
022import java.io.PrintWriter;
023import java.io.StringWriter;
024import java.lang.reflect.InvocationTargetException;
025import java.util.Arrays;
026import java.util.Iterator;
027
028import lucee.runtime.exp.NativeException;
029import lucee.runtime.exp.PageException;
030import lucee.runtime.exp.PageExceptionImpl;
031import lucee.runtime.type.Collection;
032import lucee.runtime.type.util.CollectionUtil;
033import lucee.runtime.type.util.KeyConstants;
034import lucee.runtime.type.util.ListUtil;
035
036public final class ExceptionUtil {
037        
038        public static String getStacktrace(Throwable t, boolean addMessage) {
039                StringWriter sw = new StringWriter();
040                PrintWriter pw = new PrintWriter(sw);
041                t.printStackTrace(pw);
042                pw.close();
043                String st = sw.toString();
044                String msg=t.getMessage();
045                if(addMessage && !StringUtil.isEmpty(msg) && !st.startsWith(msg.trim()))
046                        st=msg+"\n"+st;
047                return st;
048                
049        }
050        
051
052        public static String getMessage(Throwable t) {
053                String msg=t.getMessage();
054                if(StringUtil.isEmpty(msg,true)) msg=t.getClass().getName();
055                
056                StringBuilder sb=new StringBuilder(msg);
057                
058                if(t instanceof PageException){
059                        PageException pe=(PageException)t;
060                        String detail = pe.getDetail();
061                        if(!StringUtil.isEmpty(detail,true)) {
062                                sb.append('\n');
063                                sb.append(detail);
064                        }
065                }
066                return sb.toString();
067        }
068
069        public static PageException addHint(PageExceptionImpl pe,String hint) {
070                pe.setAdditional(KeyConstants._Hint, hint);
071                return pe;
072        }
073        
074        
075        /**
076         * creates a message for key not found with soundex check for similar key
077         * @param keys
078         * @param keyLabel
079         * @return
080         */
081        public static String similarKeyMessage(Collection.Key[] _keys,String keySearched, String keyLabel, String keyLabels, boolean listAll) {
082                boolean empty=_keys.length==0;
083                if(listAll && (_keys.length>50 || empty)) {
084                        listAll=false;
085                }
086                
087                String list=null;
088                if(listAll) {
089                        Arrays.sort(_keys);
090                        list=ListUtil.arrayToList(_keys, ",");
091                }
092                String keySearchedSoundex=StringUtil.soundex(keySearched);
093                
094                for(int i=0;i<_keys.length;i++){
095                        if(StringUtil.soundex(_keys[i].getString()).equals(keySearchedSoundex)) {
096                                String appendix;
097                                if(listAll) appendix=". Here is a complete list of all available "+keyLabels+": ["+list+"].";
098                                else if(empty) appendix=". The structure is empty";
099                                else appendix=".";
100                                
101                                return "The "+keyLabel+" ["+keySearched+"] does not exist, but there is a similar "+keyLabel+" with name ["+_keys[i].getString()+"] available"+appendix;
102                        }
103                }
104                String appendix;
105                if(listAll) appendix=", only the following "+keyLabels+" are available: ["+list+"].";
106                else if(empty) appendix=", the structure is empty";
107                else appendix=".";
108                return "The "+keyLabel+" ["+keySearched+"] does not exist"+appendix;
109        }
110        
111
112        public static String similarKeyMessage(Collection coll,String keySearched, String keyLabel, String keyLabels, boolean listAll) {
113                return similarKeyMessage(CollectionUtil.keys(coll), keySearched, keyLabel, keyLabels,listAll);
114        }
115
116        public static IOException toIOException(Throwable t) {
117                ExceptionUtil.rethrowIfNecessary(t);
118                if(t instanceof IOException) return (IOException) t;
119                if(t instanceof InvocationTargetException) return toIOException(((InvocationTargetException) t).getCause());
120                if(t instanceof NativeException) return toIOException(((NativeException)t).getCause());
121                
122                IOException ioe = new IOException(t.getClass().getName()+":"+t.getMessage());
123                ioe.setStackTrace(t.getStackTrace());
124                return ioe;
125        }
126
127
128        public static String createSoundexDetail(String name, Iterator<String> it, String keyName) {
129                StringBuilder sb=new StringBuilder();
130                String k ,sname=StringUtil.soundex(name);
131                while(it.hasNext()){
132                        k = it.next();
133                        if(StringUtil.soundex(k).equals(sname))
134                                return "did you mean ["+k+"]";
135                        if(sb.length()!=0)sb.append(',');
136                        sb.append(k);
137                }
138                return "available "+keyName+" are ["+sb+"]";
139        }
140
141        public static RuntimeException toRuntimeException(Throwable t) {
142                ExceptionUtil.rethrowIfNecessary(t);
143                return new RuntimeException(t);
144        }
145        
146        public static void rethrowIfNecessary(Throwable t) {
147                if(t instanceof ThreadDeath) throw (ThreadDeath)t; // never catch this rethrow
148        }
149}