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.db; 020 021import java.sql.Connection; 022import java.sql.PreparedStatement; 023import java.sql.SQLException; 024import java.sql.Statement; 025 026import lucee.commons.lang.ExceptionUtil; 027import lucee.commons.lang.StringUtil; 028import lucee.runtime.config.Config; 029import lucee.runtime.config.ConfigImpl; 030import lucee.runtime.exp.PageException; 031import lucee.runtime.op.Caster; 032import lucee.runtime.spooler.Task; 033 034/** 035 * wrap for datasorce and connection from it 036 */ 037public final class DatasourceConnectionImpl implements DatasourceConnection,Task { 038 039 //private static final int MAX_PS = 100; 040 private Connection connection; 041 private DataSource datasource; 042 private long time; 043 private final long start; 044 private String username; 045 private String password; 046 private int transactionIsolationLevel=-1; 047 private int requestId=-1; 048 private Boolean supportsGetGeneratedKeys; 049 050 /** 051 * @param connection 052 * @param datasource 053 * @param pass 054 * @param user 055 */ 056 public DatasourceConnectionImpl(Connection connection, DataSource datasource, String username, String password) { 057 this.connection = connection; 058 this.datasource = datasource; 059 this.time=this.start=System.currentTimeMillis(); 060 this.username = username; 061 this.password = password; 062 063 if(username==null) { 064 this.username=datasource.getUsername(); 065 this.password=datasource.getPassword(); 066 } 067 if(this.password==null)this.password=""; 068 069 } 070 071 @Override 072 public Connection getConnection() { 073 return connection; 074 } 075 076 @Override 077 public DataSource getDatasource() { 078 return datasource; 079 } 080 081 @Override 082 public boolean isTimeout() { 083 int timeout=datasource.getConnectionTimeout(); 084 if(timeout <= 0) return false; 085 timeout*=60000; 086 return (time+timeout)<System.currentTimeMillis(); 087 } 088 089 public boolean isLifecycleTimeout() { 090 int timeout=datasource.getConnectionTimeout()*5;// fo3 the moment simply 5 times the idle timeout 091 if(timeout <= 0) return false; 092 timeout*=60000; 093 return (start+timeout)<System.currentTimeMillis(); 094 } 095 096 public DatasourceConnection using() { 097 time=System.currentTimeMillis(); 098 return this; 099 } 100 101 /** 102 * @return the password 103 */ 104 public String getPassword() { 105 return password; 106 } 107 108 /** 109 * @return the username 110 */ 111 public String getUsername() { 112 return username; 113 } 114 115 @Override 116 public boolean equals(Object obj) { 117 if(this==obj) return true; 118 119 if(!(obj instanceof DatasourceConnectionImpl)) return false; 120 return equals(this, (DatasourceConnection) obj); 121 122 123 /*if(!(obj instanceof DatasourceConnectionImpl)) return false; 124 DatasourceConnectionImpl other=(DatasourceConnectionImpl) obj; 125 126 if(!datasource.equals(other.datasource)) return false; 127 //print.out(username+".equals("+other.username+") && "+password+".equals("+other.password+")"); 128 return username.equals(other.username) && password.equals(other.password);*/ 129 } 130 131 public static boolean equals(DatasourceConnection left,DatasourceConnection right) { 132 133 if(!left.getDatasource().equals(right.getDatasource())) return false; 134 return StringUtil.emptyIfNull(left.getUsername()).equals(StringUtil.emptyIfNull(right.getUsername())) 135 && StringUtil.emptyIfNull(left.getPassword()).equals(StringUtil.emptyIfNull(right.getPassword())); 136 } 137 138 139 140 /** 141 * @return the transactionIsolationLevel 142 */ 143 public int getTransactionIsolationLevel() { 144 return transactionIsolationLevel; 145 } 146 147 148 public int getRequestId() { 149 return requestId; 150 } 151 public void setRequestId(int requestId) { 152 this.requestId=requestId; 153 } 154 155 @Override 156 public boolean supportsGetGeneratedKeys() { 157 if(supportsGetGeneratedKeys==null){ 158 try { 159 supportsGetGeneratedKeys=Caster.toBoolean(getConnection().getMetaData().supportsGetGeneratedKeys()); 160 } catch (Throwable t) { 161 ExceptionUtil.rethrowIfNecessary(t); 162 return false; 163 } 164 } 165 return supportsGetGeneratedKeys.booleanValue(); 166 } 167 168 //private Map<String,PreparedStatement> preparedStatements=new HashMap<String, PreparedStatement>(); 169 170 @Override 171 public PreparedStatement getPreparedStatement(SQL sql, boolean createGeneratedKeys,boolean allowCaching) throws SQLException { 172 if(createGeneratedKeys) return getConnection().prepareStatement(sql.getSQLString(),Statement.RETURN_GENERATED_KEYS); 173 return getConnection().prepareStatement(sql.getSQLString()); 174 } 175 176 177 /*public PreparedStatement getPreparedStatement(SQL sql, boolean createGeneratedKeys,boolean allowCaching) throws SQLException { 178 // create key 179 String strSQL=sql.getSQLString(); 180 String key=strSQL.trim()+":"+createGeneratedKeys; 181 try { 182 key = MD5.getDigestAsString(key); 183 } catch (IOException e) {} 184 PreparedStatement ps = allowCaching?preparedStatements.get(key):null; 185 if(ps!=null) { 186 if(DataSourceUtil.isClosed(ps,true)) 187 preparedStatements.remove(key); 188 else return ps; 189 } 190 191 192 if(createGeneratedKeys) ps= getConnection().prepareStatement(strSQL,Statement.RETURN_GENERATED_KEYS); 193 else ps=getConnection().prepareStatement(strSQL); 194 if(preparedStatements.size()>MAX_PS) 195 closePreparedStatements((preparedStatements.size()-MAX_PS)+1); 196 if(allowCaching)preparedStatements.put(key,ps); 197 return ps; 198 }*/ 199 200 201 202 @Override 203 public PreparedStatement getPreparedStatement(SQL sql, int resultSetType,int resultSetConcurrency) throws SQLException { 204 return getConnection().prepareStatement(sql.getSQLString(),resultSetType,resultSetConcurrency); 205 } 206 207 /* 208 209 public PreparedStatement getPreparedStatement(SQL sql, int resultSetType,int resultSetConcurrency) throws SQLException { 210 boolean allowCaching=false; 211 // create key 212 String strSQL=sql.getSQLString(); 213 String key=strSQL.trim()+":"+resultSetType+":"+resultSetConcurrency; 214 try { 215 key = MD5.getDigestAsString(key); 216 } catch (IOException e) {} 217 PreparedStatement ps = allowCaching?preparedStatements.get(key):null; 218 if(ps!=null) { 219 if(DataSourceUtil.isClosed(ps,true)) 220 preparedStatements.remove(key); 221 else return ps; 222 } 223 224 ps=getConnection().prepareStatement(strSQL,resultSetType,resultSetConcurrency); 225 if(preparedStatements.size()>MAX_PS) 226 closePreparedStatements((preparedStatements.size()-MAX_PS)+1); 227 if(allowCaching)preparedStatements.put(key,ps); 228 return ps; 229 } 230 */ 231 232 233 @Override 234 public void close() throws SQLException { 235 //closePreparedStatements(-1); 236 getConnection().close(); 237 } 238 239 @Override 240 public Object execute(Config config) throws PageException { 241 ((ConfigImpl)config).getDatasourceConnectionPool().releaseDatasourceConnection(this); 242 return null; 243 } 244 245}