/* * RapidMiner * * Copyright (C) 2001-2011 by Rapid-I and the contributors * * Complete list of developers available at our web site: * * http://rapid-i.com * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program 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 Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see http://www.gnu.org/licenses/. */ package com.rapidminer.tools.jdbc; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.nio.charset.Charset; import java.sql.Driver; import java.sql.DriverManager; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.logging.Level; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Attr; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import com.rapidminer.RapidMiner; import com.rapidminer.io.process.XMLTools; import com.rapidminer.tools.FileSystemService; import com.rapidminer.tools.LogService; import com.rapidminer.tools.ParameterService; import com.rapidminer.tools.Tools; import com.rapidminer.tools.XMLException; /** * This service class dynamically registers (additional) JDBC drivers. Please note that drivers * cannot be created by Class.forName() but will just be instantiated automatically via * DriverManager.getConnection(...). * * @author Ingo Mierswa * */ public class DatabaseService { private static List<JDBCProperties> jdbcProperties = new ArrayList<JDBCProperties>(); public static void init() { // use the delivered default properties in the resources (e.g. in the jar file) URL propertyURL = Tools.getResource("jdbc_properties.xml"); if (propertyURL != null) { InputStream in = null; try { in = propertyURL.openStream(); loadJDBCProperties(in, "resource jdbc_properties.xml", false); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "Cannot load JDBC properties from program resources.", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "Cannot close connection for JDBC properties file in the resources.", e); } } } } if (RapidMiner.getExecutionMode().canAccessFilesystem()) { File globalJDBCFile = ParameterService.getGlobalConfigFile("jdbc_properties.xml"); if (globalJDBCFile != null) { loadJDBCProperties(globalJDBCFile, false); } File userProperties = getUserJDBCPropertiesFile(); if ((userProperties!= null) && userProperties.exists()) { loadJDBCProperties(userProperties, true); } } else { LogService.getRoot().config("Ignoring jdbc_properties.xml files in execution mode "+RapidMiner.getExecutionMode()+"."); } } private static File getUserJDBCPropertiesFile() { return FileSystemService.getUserConfigFile("jdbc_properties.xml"); } public static void loadJDBCProperties(File jdbcProperties, boolean userDefined) { InputStream in = null; try { in = new FileInputStream(jdbcProperties); loadJDBCProperties(in, jdbcProperties.getAbsolutePath(), userDefined); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "Cannot load JDBC properties from etc directory.", e); } finally { if (in != null) { try { in.close(); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "Cannot close connection for JDBC properties file in the etc directory.", e); } } } } /* private static void registerAllJDBCDrivers(File jdbcDirectory, boolean searchForJDBDriversInLibDirectory, boolean searchForJDBCDriversInClasspath) { if (!RapidMiner.getExecutionMode().canAccessFilesystem()) { LogService.getRoot().config("Skipping JDBC driver registration in execution mode "+RapidMiner.getExecutionMode()+"."); return; } if (searchForJDBDriversInLibDirectory) { if ((jdbcDirectory != null) && (jdbcDirectory.exists())) { File[] allFiles = jdbcDirectory.listFiles(); if (allFiles != null) { for (File f : allFiles) { if ((f.getName().endsWith(".jar")) || ((f.getName().endsWith(".zip")))) { registerDynamicJDBCDrivers(f); } } } } } if (searchForJDBCDriversInClasspath) { String classpath = System.getProperty("java.class.path"); String pathComponents[] = classpath.split(File.pathSeparator); for (int i = 0; i < pathComponents.length; i++) { String path = pathComponents[i].trim(); if ((path.endsWith(".jar")) || ((path.endsWith(".zip")))) { registerClasspathJDBCDrivers(new File(path).getAbsoluteFile()); } } } } */ /* private static void registerDynamicJDBCDrivers(File file) { URLClassLoader ucl = null; try { URL u = new URL("jar:file:" + file.getAbsolutePath() + "!/"); ucl = new URLClassLoader(new URL[] { u }); } catch (MalformedURLException e) { LogService.getRoot().log(Level.WARNING, "DatabaseService: cannot create class loader for file '" + file + "': " + e.getMessage(), e); } if (ucl != null) { try { JarFile jarFile = new JarFile(file); List<String> driverNames = new LinkedList<String>(); Tools.findImplementationsInJar(ucl, jarFile, java.sql.Driver.class, driverNames); Iterator<String> i = driverNames.iterator(); while (i.hasNext()) { String driverName = i.next(); registerDynamicJDBCDriver(ucl, driverName); } } catch (Exception e) { LogService.getRoot().log(Level.WARNING, "DatabaseService: cannot register drivers for file '" + file + "': " + e.getMessage(), e); } } } */ /* private static void registerDynamicJDBCDriver(ClassLoader ucl, String driverName) throws ClassNotFoundException, InstantiationException, IllegalAccessException, SQLException { if (!driverName.equals(DriverAdapter.class.getName())) { Driver d = (Driver)Class.forName(driverName, true, ucl).newInstance(); DriverManager.registerDriver(new DriverAdapter(d)); } } */ /* private static void registerClasspathJDBCDrivers(File file) { JarFile jarFile = null; try { jarFile = new JarFile(file); } catch (IOException e) { LogService.getRoot().log(Level.WARNING, "DatabaseService: cannot register drivers from file '" + file + "': " + e.getMessage(), e); return; } List<String> driverNames = new LinkedList<String>(); Tools.findImplementationsInJar(jarFile, java.sql.Driver.class, driverNames); Iterator<String> i = driverNames.iterator(); while (i.hasNext()) { String driverName = i.next(); try { Class.forName(driverName); } catch (Exception e) { LogService.getRoot().log(Level.WARNING, "DatabaseService: cannot register driver '"+driverName+"' from file '" + file + "': " + e.getMessage(), e); } } } */ public static void loadJDBCProperties(InputStream in, String name, boolean userDefined) { //jdbcProperties.clear(); LogService.getRoot().config("Loading JDBC driver information from '" + name + "'."); Document document = null; try { document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(in); } catch (Exception e) { LogService.getRoot().log(Level.WARNING, "Cannot read JDBC driver description file '" + name + "': no valid XML: " + e.getMessage(), e); } if (document != null) { if (!document.getDocumentElement().getTagName().toLowerCase().equals("drivers")) { LogService.getRoot().log(Level.WARNING, "JDBC driver description file '" + name + "': outermost tag must be <drivers>!"); return; } NodeList driverTags = document.getDocumentElement().getElementsByTagName("driver"); for (int i = 0; i < driverTags.getLength(); i++) { Element currentElement = (Element) driverTags.item(i); try { addDriverInformation(currentElement, userDefined); } catch (Exception e) { Attr currentNameAttr = currentElement.getAttributeNode("name"); if (currentNameAttr != null) { LogService.getRoot().log(Level.WARNING, "JDBC driver description: cannot register '" + currentNameAttr.getValue() + "': " + e, e); } else { LogService.getRoot().log(Level.WARNING, "JDBC driver registration: cannot register '" + currentElement + "': " + e, e); } } } } } private static void addDriverInformation(Element driverElement, boolean userDefined) throws Exception { JDBCProperties properties = new JDBCProperties(driverElement, userDefined); properties.registerDrivers(); for (JDBCProperties other : jdbcProperties) { if (other.getName().equals(properties.getName())) { LogService.getRoot().config("Merging jdbc driver information for "+other.getName()); other.merge(properties); return; } } jdbcProperties.add(properties); } private static Enumeration<Driver> getAllDrivers() { return DriverManager.getDrivers(); } public static DriverInfo[] getAllDriverInfos() { List<DriverInfo> predefinedDriverList = new LinkedList<DriverInfo>(); // Find driver for all defined JDBCProperties for (JDBCProperties properties : getJDBCProperties()) { Enumeration<Driver> drivers = getAllDrivers(); boolean accepted = false; while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); try { if (driver.acceptsURL(properties.getUrlPrefix())) { DriverInfo info = new DriverInfo(driver, properties); predefinedDriverList.add(info); accepted = true; break; } } catch (SQLException e) { // do nothing } } // found no driver, add empty info if (!accepted) { predefinedDriverList.add(new DriverInfo(null, properties)); } } // now, find drivers for which we don't have JDBCProperties List<DriverInfo> driverList = new LinkedList<DriverInfo>(); Enumeration<Driver> drivers = getAllDrivers(); while (drivers.hasMoreElements()) { Driver driver = drivers.nextElement(); boolean accepted = true; for (DriverInfo predefinedInfo : predefinedDriverList) { if ((predefinedInfo.getDriver() != null) && (predefinedInfo.getDriver().equals(driver))) { accepted = false; break; } } if (accepted) { // if ((!info.getShortName().startsWith("NonRegistering")) && // (!info.getShortName().startsWith("Replication"))) { driverList.add(new DriverInfo(driver, null)); } } driverList.addAll(predefinedDriverList); Collections.sort(driverList); DriverInfo[] driverArray = new DriverInfo[driverList.size()]; driverList.toArray(driverArray); return driverArray; } public static JDBCProperties getJDBCProperties(String name) { for (JDBCProperties properties : jdbcProperties) { if (properties.getName().equals(name)) { return properties; } } return null; } // @Deprecated // public static JDBCProperties getJProperties(String systemName) { // JDBCProperties result = null; // for (JDBCProperties properties : jdbcProperties) { // if (properties.getName().equalsIgnoreCase(systemName)) { // result = properties; // break; // } // } // return result; // } public static List<JDBCProperties> getJDBCProperties() { return jdbcProperties; } public static void addJDBCProperties(JDBCProperties newProps) { jdbcProperties.add(newProps); } public static void removeJDBCProperties(JDBCProperties newProps) { jdbcProperties.remove(newProps); } public static String[] getDBSystemNames() { String[] names = new String[jdbcProperties.size()]; int counter = 0; Iterator<JDBCProperties> i = jdbcProperties.iterator(); while (i.hasNext()) { names[counter++] = i.next().getName(); } return names; } public static void saveUserDefinedProperties() throws XMLException { Document doc; try { doc = DocumentBuilderFactory.newInstance().newDocumentBuilder().newDocument(); } catch (ParserConfigurationException e) { throw new XMLException("Failed to create document: "+e, e); } Element root = doc.createElement("drivers"); doc.appendChild(root); for (JDBCProperties props : getJDBCProperties()) { if (props.isUserDefined()) { root.appendChild(props.getXML(doc)); } } XMLTools.stream(doc, getUserJDBCPropertiesFile(), Charset.forName("UTF-8")); } // /** Sets whether the lib directory is scanned for JDBC drivers. */ // public static void setScanLibForJDBCDrivers(boolean scan) { // System.setProperty(RapidMiner.PROPERTY_RAPIDMINER_INIT_JDBC_LIB, Boolean.toString(scan)); // } // // /** Sets whether the entire classpath is scanned for JDBC drivers (very time consuming). */ // public static void setScanClasspathForJDBCDrivers(boolean scan) { // System.setProperty(RapidMiner.PROPERTY_RAPIDMINER_INIT_JDBC_CLASSPATH, Boolean.toString(scan)); // } // // /** Sets the firectory to scan for JDBC drivers. */ // public static void setJDBCDriversLibDirectory(String directory) { // System.setProperty(RapidMiner.PROPERTY_RAPIDMINER_INIT_JDBC_LIB_LOCATION, directory); // } }