/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * (C) Copyright IBM Corporation, 2005-2007. All rights reserved. * * 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; * version 2.1 of the License. * * 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. * */ package org.geotools.data.db2; import org.geotools.data.AbstractDataStoreFactory; import org.geotools.data.DataSourceException; import org.geotools.data.DataStore; import org.geotools.data.DataStoreFactorySpi; import org.geotools.data.jdbc.ConnectionPool; import org.geotools.data.jdbc.JDBCDataStoreConfig; import org.geotools.data.jdbc.datasource.DataSourceUtil; import org.geotools.data.jdbc.datasource.ManageableDataSource; import java.io.IOException; import java.sql.SQLException; import java.util.Map; import java.util.logging.Logger; import javax.sql.DataSource; /** * Implements the DataStoreFactorySpi interface to create an instance of a * DB2DataStore. * * @author David Adler - IBM Corporation * @source $URL$ */ public class DB2DataStoreFactory extends AbstractDataStoreFactory implements DataStoreFactorySpi { public static final String DRIVERNAME = "com.ibm.db2.jcc.DB2Driver"; private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger( "org.geotools.data.db2"); // The DB2 JDBC universal driver class. isAvailable() uses this to // check whether the DB2 JDBC library is in the classpath private static final String DRIVER_CLASS = DRIVERNAME; private static boolean isAvailable = false; public static final Param DBTYPE = new Param("dbtype", String.class, "must be 'DB2'", true, "DB2"); public static final Param HOST = new Param("host", String.class, "DB2 host machine", true, "localhost"); public static final Param PORT = new Param("port", Integer.class, "DB2 connection port", true, new Integer(50000)); public static final Param DATABASE = new Param("database", String.class, "database name", true); public static final Param USER = new Param("user", String.class, "user name to login as", false); public static final Param PASSWD = new Param("passwd", String.class, "password used to login", false); public static final Param TABSCHEMA = new Param("tabschema", String.class, "default table schema", false); public static final Param MAXCONN = new Param("max connections", Integer.class, "maximum number of open connections", false, new Integer(10)); public static final Param MINCONN = new Param("min connections", Integer.class, "minimum number of pooled connection", false, new Integer(4)); public static final Param VALIDATECONN = new Param("validate connections", Boolean .class, "check connection is alive before using it", false, Boolean.FALSE); static final Param[] DB2PARMS = { DBTYPE, HOST, PORT, DATABASE, USER, PASSWD, TABSCHEMA, MAXCONN, MINCONN, VALIDATECONN }; /** * canProcess and lastParams are used to cut out processing when * 'canProcess' is called successively. */ private boolean canProcess = false; private Map lastParams = null; /** * Constructs a DB2 data store using the params. * * If the port number is zero we will try to use the JDBC type 2 driver * and if the port number is non-zer, we will try to use the JDBC type 4 * driver * * @param params The full set of information needed to construct a live * data source. Should have dbtype equal to DB2, as well as host, * user, passwd, database, and table schema. * * @return The created DataSource, this may be null if the required * resource was not found or if insufficent parameters were given. * Note that canProcess() should have returned false if the * problem is to do with insuficent parameters. * * @throws IOException See DataSourceException * @throws DataSourceException Thrown if there were any problems creating * or connecting the datasource. */ public DataStore createDataStore(Map params) throws IOException { if (!canProcess(params)) { throw new IOException("Invalid parameters"); } if (!isAvailable()) { throw new IOException("DB2 Driver not available"); } String host = (String) HOST.lookUp(params); String user = (String) USER.lookUp(params); String passwd = (String) PASSWD.lookUp(params); int port = ((Integer) PORT.lookUp(params)).intValue(); String database = (String) DATABASE.lookUp(params); String tabschema = (String) TABSCHEMA.lookUp(params); Integer maxConn = (Integer) MAXCONN.lookUp(params); Integer minConn = (Integer) MINCONN.lookUp(params); Boolean validateConn = (Boolean) VALIDATECONN.lookUp(params); boolean validate = validateConn != null && validateConn.booleanValue(); int maxActive = maxConn != null ? maxConn.intValue() : 10; int maxIdle = minConn != null ? minConn.intValue() : 4; String url = getJDBCUrl(host, port, database); DataSource source = getDefaultDataSource(url, user, passwd, maxActive, maxIdle, validate); // If the table schema is null or blank, uset the userid for the table schema if (tabschema == null || tabschema.length() == 0) { tabschema = user; } // if the table schema is not double-quoted, convert it to uppercase. // if it is double-quoted, remove the double quotes. if (tabschema.startsWith("\"")) { tabschema = tabschema.substring(1,tabschema.length()-1); } else { tabschema = tabschema.toUpperCase(); } // trim trailing blanks - just in case tabschema = tabschema.trim(); // Set the namespace and databaseSchemaName both to the table schema name // Set the timeout value to 100 seconds to force FeatureTypeHandler caching JDBCDataStoreConfig config = new JDBCDataStoreConfig(tabschema, tabschema, 10000); DB2DataStore ds; try { ds = new DB2DataStore(source, config, url); } catch (IOException e) { LOGGER.info("Create DB2Datastore failed: " + e); throw new DataSourceException("Could not create DB2DataStore", e); } LOGGER.info("Successfully created DB2Datastore for: " + host + ":" + port + "/" + database); return ds; } public static ManageableDataSource getDefaultDataSource(String url, String user, String passwd, int maxActive, int minIdle, boolean validate) throws DataSourceException { return DataSourceUtil.buildDefaultDataSource(url, DRIVER_CLASS, user, passwd, maxActive, minIdle, validate ? "select current date from sysibm.sysdummy1" : null, false, 0); } /** * Returns the JDBC url used for connecting to a specific database */ public static String getJDBCUrl(String host, int port, String database) { String url = null; if (port == 0) { url = "jdbc:db2:" + database; } else { url = "jdbc:db2://" + host + ":" + port + "/" + database; } return url; } /** * Creating a new DB2 database is not supported. * * @param params Doesn't much matter what this contains. * * @return DataStore But will always throw an exception * * @throws UnsupportedOperationException Cannot create new database */ public DataStore createNewDataStore(Map params) throws UnsupportedOperationException { throw new UnsupportedOperationException( "Creating a new DB2 database is not supported"); } /** * Provide a String description of this data store. * * @return the data store description. */ public String getDescription() { return "DB2 Data Store"; } /** * Name suitable for display to end user. * * <p> * A non localized display name for this data store type. * </p> * * @return A short name suitable for display in a user interface. */ public String getDisplayName() { return "DB2"; } /** * Returns the array of parameters used by DB2. * * @return Param[] Array of parameters. */ public Param[] getParametersInfo() { return DB2PARMS; } /** * Check whether the parameter list passed identifies it as a request for a * DB2DataStore. * * <p> * Most critical is the 'dbtype' parameter which must have the value 'DB2'. * If it is, then the remaining parameter values can be checked. * </p> * * @param params Key/Value parameter list containing values required to * identify a request for a DB2DataStore and remaining values to * identify the database to be connected to. * * @return true if dbtype equals DB2, and contains keys for host, user, * passwd, and database. */ public boolean canProcess(Map params) { String logInfo = ""; // Hopefully we won't be called with a null parameter list. if (params == null) { return false; } // Can't do anything if no dbtype or the dbtype is not DB2 String dbtype = (String) params.get("dbtype"); if (dbtype == null) { return (false); } if (!(dbtype.equalsIgnoreCase("DB2"))) { return (false); } // If the parameters are the same as last time and it was ok last time // it should still be ok. if (this.canProcess && (this.lastParams == params)) { return true; } if (!super.canProcess(params)) { return false; } this.lastParams = params; this.canProcess = true; return true; } /** * Check whether the DB2 JDBC type 4 driver is found in the classpath. * * <p> * If it isn't, there is a problem since the FactoryFinder found the * DB2DataStoreFactory but there is no driver to connect to a DB2 * database. * </p> * * <p> * The classpath should have db2jcc.jar and db2jcc_license_cu.jar * </p> * * @return true if a DB2 driver is available for the DB2DataStore to * connect to a DB2 database. */ public boolean isAvailable() { if (isAvailable) { return isAvailable; } try { Class.forName(DRIVER_CLASS); isAvailable = true; } catch (ClassNotFoundException e) { isAvailable = false; } LOGGER.info("DB2 driver found: " + isAvailable); return isAvailable; } }