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.orm.hibernate;
020
021import java.lang.reflect.Method;
022
023import lucee.commons.io.res.util.ResourceUtil;
024import lucee.loader.engine.CFMLEngineFactory;
025import lucee.runtime.Component;
026import lucee.runtime.db.DataSource;
027import lucee.runtime.exp.PageException;
028import lucee.runtime.orm.ORMSession;
029import lucee.runtime.type.Collection.Key;
030import lucee.runtime.type.util.ListUtil;
031
032public class ExceptionUtil {
033
034
035        private static Method setAdditional;
036
037
038        public static PageException createException(SessionFactoryData data, Component cfc, String msg, String detail) {
039                
040                PageException pe = createException((ORMSession)null,cfc,msg,detail);
041                if(data!=null)setAddional(pe,data);
042                return pe;
043        }
044        public static PageException createException(SessionFactoryData data, Component cfc, Throwable t) {
045                PageException pe = createException((ORMSession)null,cfc,t);
046                if(data!=null)setAddional(pe,data);
047                return pe;
048        }
049
050        
051        public static PageException createException(ORMSession session,Component cfc,Throwable t) {
052                PageException pe = CFMLEngineFactory.getInstance().getExceptionUtil().createApplicationException(t.getMessage());
053                pe.setStackTrace(t.getStackTrace());
054                if(session!=null)setAddional(session,pe);
055                if(cfc!=null)setContext(pe,cfc);
056                return pe;
057        }
058        
059
060        public static PageException createException(ORMSession session,Component cfc,String message,String detail) {
061                PageException pe = CFMLEngineFactory.getInstance().getExceptionUtil().createApplicationException(message);
062                if(session!=null)setAddional(session,pe);
063                if(cfc!=null)setContext(pe,cfc);
064                return pe;
065        }
066        
067
068        private static void setContext(PageException pe,Component cfc) {
069                if(cfc!=null && getPageDeep(pe)==0)pe.addContext(cfc.getPageSource(), 1, 1, null);
070        }
071        
072
073        private static void setAddional(PageException pe,SessionFactoryData data) {
074                setAdditional(pe,CommonUtil.createKey("Entities"), ListUtil.listToList2(data.getEntityNames(), ", "));
075                setAddional(pe,data.getDataSources());
076        }
077        
078        private static void setAddional(ORMSession session,PageException pe) {
079                String[] names = session.getEntityNames();
080                
081                setAdditional(pe, CommonUtil.createKey("Entities"),  CommonUtil.toList(names, ", "));
082                setAddional(pe,session.getDataSources());
083        }
084        
085        private static void setAddional(PageException pe,DataSource... sources) {
086                if(sources!=null && sources.length>0){
087                        StringBuilder sb=new StringBuilder();
088                        for(int i=0;i<sources.length;i++){
089                                if(i>0) sb.append(", ");
090                                sb.append(sources[i].getName());
091                        }
092                        setAdditional(pe, CommonUtil.createKey("_Datasource"), sb.toString());
093                }
094        }
095        
096        private static int getPageDeep(PageException pe) {
097                StackTraceElement[] traces = getStackTraceElements(pe);
098                
099                String template="",tlast;
100                StackTraceElement trace=null;
101                int index=0;
102                for(int i=0;i<traces.length;i++) {
103                        trace=traces[i];
104                        tlast=template;
105                        template=trace.getFileName();
106                        if(trace.getLineNumber()<=0 || template==null || ResourceUtil.getExtension(template,"").equals("java")) continue;
107                        if(!(tlast==null?"":tlast).equals(template))index++;
108                        
109                }
110                return index;
111        }
112        
113        private static StackTraceElement[] getStackTraceElements(Throwable t) {
114                lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
115        StackTraceElement[] st=getStackTraceElements(t,true);
116        if(st==null) st= getStackTraceElements(t,false);
117        return st;
118    }
119    
120    private static StackTraceElement[] getStackTraceElements(Throwable t, boolean onlyWithCML) {
121                lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
122        StackTraceElement[] st;
123        Throwable cause=t.getCause();
124        if(cause!=null){
125                st = getStackTraceElements(cause,onlyWithCML);
126                if(st!=null) return st;
127        }
128        
129        st=t.getStackTrace();
130        if(!onlyWithCML || hasCFMLinStacktrace(st)){
131                return st;
132        }
133        return null;
134        }
135    
136    
137    private static boolean hasCFMLinStacktrace(StackTraceElement[] traces) {
138                for(int i=0;i<traces.length;i++) {
139                        if(traces[i].getFileName()!=null && !traces[i].getFileName().endsWith(".java")) return true;
140                }
141                return false;
142        }
143    
144
145        public static void setAdditional(PageException pe, Key name, Object value) { 
146                try{
147                        if(setAdditional==null || setAdditional.getDeclaringClass()!=pe.getClass()) {
148                                setAdditional=pe.getClass().getMethod("setAdditional", new Class[]{Key.class,Object.class});
149                        }
150                        setAdditional.invoke(pe, new Object[]{name,value});
151                }
152                catch(Throwable t){
153                        lucee.commons.lang.ExceptionUtil.rethrowIfNecessary(t);
154                }
155        }
156}