package net.sourceforge.sqlexplorer.dbproduct; import java.beans.PropertyChangeListener; import java.io.File; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; import java.util.Collection; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Properties; import net.sourceforge.sqlexplorer.ExplorerException; import net.sourceforge.sqlexplorer.Messages; import net.sourceforge.sqlexplorer.SQLCannotConnectException; import net.sourceforge.sqlexplorer.plugin.SQLExplorerPlugin; import net.sourceforge.sqlexplorer.util.AliasAndManaDriverHelper; import net.sourceforge.squirrel_sql.fw.id.IIdentifier; import net.sourceforge.squirrel_sql.fw.persist.ValidationException; import net.sourceforge.squirrel_sql.fw.sql.ISQLDriver; import net.sourceforge.squirrel_sql.fw.util.beanwrapper.StringWrapper; import org.apache.log4j.Logger; import org.dom4j.Element; import org.dom4j.tree.DefaultElement; import org.talend.core.database.EDatabase4DriverClassName; import org.talend.core.database.EDatabaseTypeName; import org.talend.core.model.metadata.IMetadataConnection; import org.talend.core.model.metadata.builder.ConvertionHelper; import org.talend.core.model.metadata.builder.connection.DatabaseConnection; import org.talend.core.model.metadata.builder.database.DriverShim; import org.talend.core.model.metadata.builder.database.ExtractMetaDataUtils; import org.talend.core.model.metadata.builder.database.HotClassLoader; import org.talend.core.model.metadata.builder.database.JDBCDriverLoader; import org.talend.core.model.metadata.builder.database.PluginConstant; import org.talend.metadata.managment.hive.HiveClassLoaderFactory; import org.talend.utils.sql.ConnectionUtils; /** * Manages a JDBC Driver * * @author John Spackman */ public class ManagedDriver implements Comparable<ManagedDriver> { public class SQLDriver implements ISQLDriver { @Override public void addPropertyChangeListener(PropertyChangeListener listener) { } @Override public void assignFrom(ISQLDriver rhs) throws ValidationException { throw new ValidationException(Messages.getString("ManagedDriver.NotSupported")); //$NON-NLS-1$ } @Override public int compareTo(ISQLDriver rhs) { return ManagedDriver.this.getDriverClassName().compareTo(rhs.getDriverClassName()); } @Override public String getDriverClassName() { return ManagedDriver.this.getDriverClassName(); } @Override public IIdentifier getIdentifier() { return null; } @Override public String getJarFileName() { return null; } @Override public String[] getJarFileNames() { return (String[]) ManagedDriver.this.getJars().toArray(); } @Override public StringWrapper getJarFileNameWrapper(int idx) throws ArrayIndexOutOfBoundsException { return null; } @Override public StringWrapper[] getJarFileNameWrappers() { return null; } @Override public String getName() { return ManagedDriver.this.getDriverClassName(); } @Override public String getUrl() { return ManagedDriver.this.getUrl(); } @Override public String getWebSiteUrl() { return null; } @Override public boolean isJDBCDriverClassLoaded() { return ManagedDriver.this.isDriverClassLoaded(); } @Override public void removePropertyChangeListener(PropertyChangeListener listener) { } @Override public void setDriverClassName(String driverClassName) throws ValidationException { } @Override public void setJarFileName(String value) throws ValidationException { } @Override public void setJarFileNames(String[] values) { } @Override public void setJarFileNameWrapper(int idx, StringWrapper value) throws ArrayIndexOutOfBoundsException { } @Override public void setJarFileNameWrappers(StringWrapper[] value) { } @Override public void setJDBCDriverClassLoaded(boolean cl) { } @Override public void setName(String name) throws ValidationException { } @Override public void setUrl(String url) throws ValidationException { } @Override public void setWebSiteUrl(String url) throws ValidationException { } } private String id; private String name; private String driverClassName; private String url; private LinkedList<String> jars = new LinkedList<String>(); private Driver jdbcDriver; private static Logger log = Logger.getLogger(ManagedDriver.class); public ManagedDriver(String id) { this.id = id; } /** * Constructs a new ManagedDriver from a previously serialised version * * @param root result of previous call to describeAsXml() */ public ManagedDriver(Element root) { super(); id = root.attributeValue(DriverManager.ID); name = root.elementText(DriverManager.NAME); driverClassName = root.elementText(DriverManager.DRIVER_CLASS); url = root.elementText(DriverManager.URL); Element jarsElem = root.element(DriverManager.JARS); List<Element> list = jarsElem.elements(); if (list != null) { for (Element jarElem : list) { String jar = jarElem.getTextTrim(); if (jar != null) { jars.add(jar); } } } } /** * Describes this driver in XML; the result can be passed to the constructor to refabricate it late * * @return */ public Element describeAsXml() { Element root = new DefaultElement(DriverManager.DRIVER); root.addAttribute(DriverManager.ID, id); root.addElement(DriverManager.NAME).setText(name); if (driverClassName != null) { root.addElement(DriverManager.DRIVER_CLASS).setText(driverClassName); } root.addElement(DriverManager.URL).setText(url); Element jarsElem = root.addElement(DriverManager.JARS); for (String jar : jars) { jarsElem.addElement(DriverManager.JAR).setText(jar); } return root; } /** * Loads the Driver class * * @throws ExplorerException * @throws SQLException * @deprecated replace it with registerSQLDriver(String dbType, String dbVersion) */ @Deprecated public synchronized void registerSQLDriver() throws ClassNotFoundException { if (driverClassName == null || driverClassName.length() == 0) { return; } unregisterSQLDriver(); jdbcDriver = DatabaseProductFactory.loadDriver(this); } /** * regist jdbc driver except Hive by HotClassLoader. * * @param dbConnection * @return * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException */ public void registerSQLDriver(DatabaseConnection dbConn) throws ClassNotFoundException, InstantiationException, IllegalAccessException { String dbType = dbConn.getDatabaseType(); String dbVersion = dbConn.getDbVersionString(); String userName = dbConn.getUsername(); userName = userName != null ? userName : PluginConstant.EMPTY_STRING; String message = "fail to regist jdbc driver in SQLExplorer"; if (driverClassName == null || dbType == null || dbType.equalsIgnoreCase(EDatabaseTypeName.HIVE.getXmlName()) || dbType.equalsIgnoreCase(EDatabaseTypeName.IMPALA.getXmlName())) { log.error(message); return; } boolean isODBC = dbType.equalsIgnoreCase(EDatabaseTypeName.GODBC.getXmlName()); try { if (isODBC || isValidatedJars()) { // the jtds mode to connect sqlserver database only Instance driver once. if (dbType.equalsIgnoreCase(EDatabaseTypeName.MSSQL.getDisplayName()) && PluginConstant.EMPTY_STRING.equals(userName)) { instanceMSSqlJdbcDriver(dbType, dbVersion); } else { instanceJdbcDriver(dbType, dbVersion); } } } catch (Throwable e) { // TDQ-9711 catch all exceptions and errors. throw new RuntimeException(e); } finally { if (jdbcDriver == null) { log.error(message); } } } /** * regist jdbc driver except Hive by HotClassLoader. * * @param dbConnection * @return * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException * @deprecated using registerSQLDriver(DatabaseConnection dbConn) instead of. */ @Deprecated public void registerSQLDriver(String dbType, String dbVersion) throws ClassNotFoundException, InstantiationException, IllegalAccessException { boolean isODBC = dbType.equalsIgnoreCase(EDatabaseTypeName.GODBC.getXmlName()); if (driverClassName != null && !dbType.equalsIgnoreCase(EDatabaseTypeName.HIVE.getXmlName()) && (isODBC || isValidatedJars())) { unregisterSQLDriver(); JDBCDriverLoader jdbcDriverClassLoader = new JDBCDriverLoader(); HotClassLoader hotClassLoader = jdbcDriverClassLoader.getHotClassLoader(jars.toArray(new String[jars.size()]), dbType, dbVersion); Class<?> classDriver = Class.forName(driverClassName, true, hotClassLoader); if (classDriver != null) { jdbcDriver = (Driver) classDriver.newInstance(); } } if (jdbcDriver == null) { log.error("fail to regist jdbc driver in SQLExplorer"); } } /** * use jtds SSO mode to connect sqlserver database, only allow to instance driver once. * * @param dbType * @param dbVersion * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException */ private void instanceMSSqlJdbcDriver(String dbType, String dbVersion) throws ClassNotFoundException, InstantiationException, IllegalAccessException { Map<String, DriverShim> driverCache = ExtractMetaDataUtils.getInstance().getDriverCache(); if (driverCache.containsKey(EDatabase4DriverClassName.MSSQL.getDriverClass())) { DriverShim driverShim = driverCache.get(EDatabase4DriverClassName.MSSQL.getDriverClass()); jdbcDriver = driverShim; } else { instanceJdbcDriver(dbType, dbVersion); if (jdbcDriver != null) { DriverShim driverShim = new DriverShim(jdbcDriver); ExtractMetaDataUtils.getInstance().setDriverCache(driverShim); } } } /** * create a new jdbc instance. * * @param dbType * @param dbVersion * @throws ClassNotFoundException * @throws InstantiationException * @throws IllegalAccessException */ private void instanceJdbcDriver(String dbType, String dbVersion) throws ClassNotFoundException, InstantiationException, IllegalAccessException { unregisterSQLDriver(); JDBCDriverLoader jdbcDriverClassLoader = new JDBCDriverLoader(); HotClassLoader hotClassLoader = jdbcDriverClassLoader.getHotClassLoader(jars.toArray(new String[jars.size()]), dbType, dbVersion); Class<?> classDriver = Class.forName(driverClassName, true, hotClassLoader); if (classDriver != null) { jdbcDriver = (Driver) classDriver.newInstance(); } } /** * * register hive jdbc driver by DatabaseConnection * * @param dbConnection * @throws ClassNotFoundException * @throws IllegalAccessException * @throws InstantiationException * @throws Exception */ public synchronized void registerHiveSQLDriver(DatabaseConnection dbConnection) throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (dbConnection != null || driverClassName != null || driverClassName.length() != 0) { String dbType = dbConnection.getDatabaseType(); if (dbType.equalsIgnoreCase(EDatabaseTypeName.HIVE.getXmlName())) { unregisterSQLDriver(); IMetadataConnection metadataConn = ConvertionHelper.convert(dbConnection); ClassLoader classLoader = HiveClassLoaderFactory.getInstance().getClassLoader(metadataConn); Class<?> classDriver = Class.forName(driverClassName, true, classLoader); jdbcDriver = (Driver) classDriver.newInstance(); } else if (dbType.equalsIgnoreCase(EDatabaseTypeName.IMPALA.getXmlName())) { unregisterSQLDriver(); IMetadataConnection metadataConn = ConvertionHelper.convert(dbConnection); ClassLoader classLoader = AliasAndManaDriverHelper.getInstance().getImpalaClassLoader(metadataConn); Class<?> classDriver = Class.forName(driverClassName, true, classLoader); jdbcDriver = (Driver) classDriver.newInstance(); } } if (jdbcDriver == null) { log.error("fail to regist Hive jdbc driver in SQLExplorer"); } } /** * Unloads the class * */ public synchronized void unregisterSQLDriver() { jdbcDriver = null; } /** * Establishes a JDBC connection * * @param user * @return * @throws ExplorerException * @throws SQLException */ public SQLConnection getConnection(User user) throws SQLException { Properties props = new Properties(); // MOD msjian TDQ-8463: for the string "user" and "password", no need to do international.bacause some // jars(e.g:ojdbc14.jar) don't support international and cause to get connection error if (user.getUserName() != null) { props.put("user", user.getUserName()); //$NON-NLS-1$ } if (user.getPassword() != null) { props.put("password", user.getPassword());//$NON-NLS-1$ } if (!isDriverClassLoaded()) { try { DatabaseConnection dbConn = user.getDatabaseConnection(); if (dbConn != null) { registerSQLDriver(dbConn); } } catch (Exception e) { throw new SQLException(Messages.getString("ManagedDriver.CannotLoadDriver1", driverClassName) + " "//$NON-NLS-1$ //$NON-NLS-2$ + Messages.getString("ManagedDriver.CannotLoadDriver2"));//$NON-NLS-1$ } } if (!isDriverClassLoaded()) { throw new SQLException(Messages.getString("ManagedDriver.CannotLoadDriver1", driverClassName));//$NON-NLS-1$ } Connection jdbcConn = null; try { String dbUrl = user.getAlias().getUrl(); if (ConnectionUtils.isHsql(dbUrl)) { dbUrl = ConnectionUtils.addShutDownForHSQLUrl(dbUrl, user.getDatabaseConnection().getAdditionalParams()); } jdbcConn = jdbcDriver.connect(dbUrl, props); } catch (SQLException e) { throw new SQLCannotConnectException(user, e); } if (jdbcConn == null) { throw new SQLCannotConnectException(user); } return new SQLConnection(user, jdbcConn, this, getDatabaseProduct().describeConnection(jdbcConn)); } public boolean isDriverClassLoaded() { return jdbcDriver != null; } public String getDriverClassName() { return driverClassName; } public String getId() { return id; } public LinkedList<String> getJars() { return jars; } public Driver getJdbcDriver() { return jdbcDriver; } public String getName() { return name; } public String getUrl() { return url; } public void setJars(LinkedList<String> jars) { this.jars = jars; } public void setJars(String[] jars) { this.jars.clear(); for (String jar : jars) { this.jars.add(jar); } } public void setJdbcDriver(Driver jdbcDriver) { this.jdbcDriver = jdbcDriver; } public void setName(String name) { this.name = name; } public void setUrl(String url) { this.url = url; } public void setDriverClassName(String driverClassName) { this.driverClassName = driverClassName; } public DatabaseProduct getDatabaseProduct() { return DatabaseProductFactory.getInstance(this); } @Override public int compareTo(ManagedDriver that) { return name.compareTo(that.name); } public boolean isUsedByAliases() { Collection<Alias> aliases = SQLExplorerPlugin.getDefault().getAliasManager().getAliases(); for (Alias alias : aliases) { if (alias.getDriverId().equals(this.getId())) { return true; } } return false; } private boolean isValidatedJars() { boolean flag = false; if (jars.isEmpty()) { return false; } for (String jarPath : jars) { if (jarPath == null || jarPath.equals(PluginConstant.EMPTY_STRING)) { return false; } File jarFile = new File(jarPath); flag = jarFile.exists() && jarFile.isFile(); } return true; } }