/**
* Copyright (c) 2014, the Railo Company Ltd.
* Copyright (c) 2015, Lucee Assosication Switzerland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
*/
package lucee.runtime.db;
import java.sql.Connection;
import java.sql.Driver;
import java.sql.SQLException;
import java.util.Map;
import java.util.TimeZone;
import lucee.commons.io.log.Log;
import lucee.commons.lang.ClassException;
import lucee.runtime.config.Config;
import lucee.runtime.config.ConfigImpl;
import lucee.runtime.engine.ThreadLocalPageContext;
import lucee.transformer.library.ClassDefinitionImpl;
import org.apache.commons.collections4.map.ReferenceMap;
import org.osgi.framework.BundleException;
public abstract class DataSourceSupport implements DataSource, Cloneable {
private static final int NETWORK_TIMEOUT_IN_SECONDS = 10;
private ClassDefinition cd;
private final boolean blob;
private final boolean clob;
private final int connectionLimit;
private final int connectionTimeout;
private final long metaCacheTimeout;
private final TimeZone timezone;
private final String name;
private final boolean storage;
protected final int allow;
private final boolean readOnly;
private final String username;
private final String password;
private Map<String,ProcMetaCollection> procedureColumnCache;
private Driver driver;
protected final JDBCDriver jdbc;
private final Log log;
public DataSourceSupport(Config config, JDBCDriver jdbc, String name, ClassDefinition cd,String username, String password, boolean blob,boolean clob,int connectionLimit, int connectionTimeout, long metaCacheTimeout, TimeZone timezone, int allow, boolean storage, boolean readOnly, Log log) {
this.jdbc=jdbc;
this.name=name;
this.cd=_initializeCD(jdbc,cd, config);
this.blob=blob;
this.clob=clob;
this.connectionLimit=connectionLimit;
this.connectionTimeout=connectionTimeout;
this.metaCacheTimeout=metaCacheTimeout;
this.timezone=timezone;
this.allow=allow;
this.storage=storage;
this.readOnly=readOnly;
this.username=username;
this.password=password;
this.log=log;
}
@Override
public Connection getConnection(Config config,String user, String pass) throws ClassException, BundleException, SQLException {
try {
if(user == null) user=username;
if(pass==null)pass=password;
return _getConnection(config,initialize(config),getConnectionStringTranslated(), user, pass);
}
catch (InstantiationException e) {
throw new RuntimeException(e);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
public static Connection _getConnection(Config config,Driver driver, String connStrTrans, String user, String pass) throws SQLException {
java.util.Properties props = new java.util.Properties();
if(user != null) props.put("user", user);
if (pass != null) props.put("password", pass);
return driver.connect(connStrTrans, props);
}
private Driver initialize(Config config) throws ClassException, BundleException, InstantiationException, IllegalAccessException {
if(driver==null) {
//cd=_initializeCD(jdbc,cd, config);
driver=_initializeDriver(cd,config);
}
return driver;
}
private static ClassDefinition _initializeCD(JDBCDriver jdbc,ClassDefinition cd, Config config) {
// try to link the class defintion with a jdbc driver defintion
if(!cd.isBundle()) {
if("com.microsoft.jdbc.sqlserver.SQLServerDriver".equals(cd.getClassName())) {
cd=new ClassDefinitionImpl("com.microsoft.sqlserver.jdbc.SQLServerDriver",
cd.getName(),cd.getVersionAsString(),null);
}
ConfigImpl ci = ((ConfigImpl)ThreadLocalPageContext.getConfig(config));
JDBCDriver tmp = jdbc!=null? ci.getJDBCDriverById(jdbc.cd.getId(), null):null;
if(tmp==null)tmp = ((ConfigImpl)config).getJDBCDriverByClassName(cd.getClassName(), null);
// we have a matching jdbc driver found
if(tmp!=null) {
cd=tmp.cd;
}
}
return cd;
}
private static Driver _initializeDriver(ClassDefinition cd, Config config) throws ClassException, BundleException, InstantiationException, IllegalAccessException {
// load the class
Class clazz = cd.getClazz();
return (Driver)clazz.newInstance();
}
public static void verify(Config config,JDBCDriver jdbc,ClassDefinition cd, String connStrTranslated, String user, String pass) throws ClassException, BundleException, SQLException {
try {
Driver driver=_initializeDriver(_initializeCD(jdbc,cd, config), config);
_getConnection(config, driver, connStrTranslated, user, pass);
}
catch (InstantiationException e) {
throw new RuntimeException(e);
}
catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
@Override
public Object clone() {
return cloneReadOnly();
}
public Map<String,ProcMetaCollection> getProcedureColumnCache() {
if(procedureColumnCache==null)
procedureColumnCache=new ReferenceMap<String,ProcMetaCollection>();
return procedureColumnCache;
}
@Override
public final boolean isBlob() {
return blob;
}
@Override
public final boolean isClob() {
return clob;
}
@Override
public final int getConnectionLimit() {
return connectionLimit;
}
@Override
public final int getConnectionTimeout() {
return connectionTimeout;
}
@Override
public final long getMetaCacheTimeout() {
return metaCacheTimeout;
}
@Override
public final TimeZone getTimeZone() {
return timezone;
}
@Override
public final ClassDefinition getClassDefinition() {
return cd;
}
@Override
public final String getName() {
return name;
}
@Override
public final boolean isStorage() {
return storage;
}
@Override
public final boolean hasAllow(int allow) {
return (this.allow&allow)>0;
}
@Override
public final boolean hasSQLRestriction() {
return this.allow!=DataSource.ALLOW_ALL;
}
@Override
public final boolean isReadOnly() {
return readOnly;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public int getNetworkTimeout() {
return NETWORK_TIMEOUT_IN_SECONDS;
}
@Override
public Log getLog() {
return log;
}
@Override
public boolean equals(Object obj) {
if(this==obj)return true;
if(!(obj instanceof DataSource)) return false;
DataSource ds = (DataSource)obj;
return id().equals(ds.id());
}
@Override
public int hashCode() {
return id().hashCode();
}
@Override
public String id() {
return new StringBuilder(getConnectionStringTranslated())
.append(':')
.append(getConnectionLimit())
.append(':')
.append(getConnectionTimeout())
.append(':')
.append(getMetaCacheTimeout())
.append(':')
.append(getName().toLowerCase())
.append(':')
.append(getUsername())
.append(':')
.append(getPassword())
.append(':')
.append(cd.toString())
.append(':')
.append((getTimeZone()==null?"null":getTimeZone().getID()))
.append(':')
.append(isBlob())
.append(':')
.append(isClob())
.append(':')
.append(isReadOnly())
.append(':')
.append(isStorage()).toString();
}
@Override
public String toString() {
return id();
}
}