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.exp;
020
021import java.sql.DatabaseMetaData;
022import java.sql.SQLException;
023import java.util.ArrayList;
024import java.util.List;
025
026import lucee.commons.lang.ExceptionUtil;
027import lucee.commons.lang.StringUtil;
028import lucee.runtime.PageContext;
029import lucee.runtime.config.Config;
030import lucee.runtime.db.DataSource;
031import lucee.runtime.db.DatasourceConnection;
032import lucee.runtime.db.SQL;
033import lucee.runtime.listener.ApplicationContextPro;
034import lucee.runtime.op.Caster;
035import lucee.runtime.type.KeyImpl;
036import lucee.runtime.type.util.KeyConstants;
037
038
039/**
040 * Database Exception Object
041 */
042
043
044
045public final class DatabaseException extends PageExceptionImpl {
046
047        private SQL sql;
048        private String sqlstate="";
049        private int errorcode=-1;
050        private DataSource datasource;
051
052        public DatabaseException(SQLException sqle,DatasourceConnection dc) {
053                super(
054                                sqle.getCause() instanceof SQLException?
055                                                (sqle=(SQLException)sqle.getCause()).getMessage():
056                                                sqle.getMessage(),"database");
057                
058                set(sqle);
059                set(dc);
060        }
061
062        public DatabaseException(String message,String detail,SQL sql,DatasourceConnection dc) {
063                super(message,"database");
064                
065                set(sql);
066                set(null,detail);
067                set(dc);
068        }
069        
070        /**
071         * Constructor of the class
072         * @param message error message
073         * @param detail detailed error message
074         * @param sqle
075         * @param sql
076         * @param dc
077         */
078        private DatabaseException(String message, String detail, SQLException sqle, SQL sql,DatasourceConnection dc) {
079                super(sqle.getCause() instanceof SQLException?message:"","database");
080                
081                set(sql);
082                set(sqle,detail);
083                set(sqle);
084                set(dc);
085        }
086        
087        private void set(SQL sql) {
088                this.sql=sql;
089                if(sql!=null) {
090                        setAdditional(KeyConstants._SQL,sql.toString());
091                }
092        }
093
094        private void set(SQLException sqle,String detail) {
095                String sqleMessage=sqle!=null?sqle.getMessage():"";
096                if(detail!=null){
097                        if(!StringUtil.isEmpty(sqleMessage))
098                                setDetail(detail+"\n"+sqleMessage);
099                        else 
100                                setDetail(detail);
101                }
102                else {
103                        if(!StringUtil.isEmpty(sqleMessage))
104                                setDetail(sqleMessage);
105                }
106        }
107
108        private void set(SQLException sqle) {
109                if(sqle!=null) {
110                        sqlstate=sqle.getSQLState();
111                        errorcode=sqle.getErrorCode();
112                        
113                        this.setStackTrace(sqle.getStackTrace());
114                }
115        }
116
117        private void set(DatasourceConnection dc) {
118                if(dc!=null) {
119                        datasource=dc.getDatasource();
120                        try {
121                                DatabaseMetaData md = dc.getConnection().getMetaData();
122                                md.getDatabaseProductName();
123                                setAdditional(KeyImpl.init("DatabaseName"),md.getDatabaseProductName());
124                                setAdditional(KeyImpl.init("DatabaseVersion"),md.getDatabaseProductVersion());
125                                setAdditional(KeyImpl.init("DriverName"),md.getDriverName());
126                                setAdditional(KeyImpl.init("DriverVersion"),md.getDriverVersion());
127                                //setAdditional("url",md.getURL());
128                                
129                                setAdditional(KeyConstants._Datasource,dc.getDatasource().getName());
130                                
131                                
132                        } 
133                        catch (SQLException e) {}
134                }
135        }
136
137        /**
138         * Constructor of the class
139         * @param message
140         * @param sqle
141         * @param sql
142        
143        public DatabaseException(String message, SQLException sqle, SQL sql,DatasourceConnection dc) {
144                this(message,null,sqle,sql,dc);
145        } */
146        
147        
148        /**
149         * Constructor of the class
150         * @param sqle
151         * @param sql
152         */
153        public DatabaseException(SQLException sqle, SQL sql,DatasourceConnection dc) {
154                this(sqle!=null?sqle.getMessage():null,null,sqle,sql,dc);
155        }
156        
157        /**
158         * Constructor of the class
159         * @param sqle
160         */
161        
162
163        @Override
164        public CatchBlock getCatchBlock(Config config) {
165            String strSQL=sql==null?"":sql.toString();
166            if(StringUtil.isEmpty(strSQL))strSQL=Caster.toString(getAdditional().get("SQL", ""),"");
167                
168            String datasourceName=datasource==null?"":datasource.getName();
169                if(StringUtil.isEmpty(datasourceName))datasourceName=Caster.toString(getAdditional().get("DataSource", ""),"");
170                
171                CatchBlock sct = super.getCatchBlock(config);
172                sct.setEL("NativeErrorCode",new Double(errorcode));
173                sct.setEL("DataSource",datasourceName);
174                sct.setEL("SQLState",sqlstate);
175                sct.setEL("Sql",strSQL);
176                sct.setEL("queryError",strSQL);
177                sct.setEL("where","");
178                return sct;
179        }
180
181        public static DatabaseException notFoundException(PageContext pc, String datasource) {
182                
183                
184                List<String> list=new ArrayList<String>();
185                
186                // application based datasources
187                DataSource[] datasources = ((ApplicationContextPro)pc.getApplicationContext()).getDataSources();
188                if(datasources!=null)for(int i=0;i<datasources.length;i++){
189                        list.add(datasources[i].getName());
190                }
191                
192                // config based datasources
193                datasources=pc.getConfig().getDataSources();
194                if(datasources!=null)for(int i=0;i<datasources.length;i++){
195                        list.add(datasources[i].getName());
196                }
197                
198                // create error detail
199                DatabaseException de = new DatabaseException("datasource ["+datasource+"] doesn't exist",null,null,null);
200                de.setDetail(ExceptionUtil.createSoundexDetail(datasource,list.iterator(),"datasource names"));
201                de.setAdditional(KeyConstants._Datasource,datasource);
202                return de;
203        }
204
205        private static ApplicationContextPro getApplicationContext() {
206                // TODO Auto-generated method stub
207                return null;
208        }
209}