001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) Copyright IBM Corporation, 2005-2007. All rights reserved.
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: */
017: package org.geotools.data.db2;
018:
019: import org.geotools.data.AbstractDataStoreFactory;
020: import org.geotools.data.DataSourceException;
021: import org.geotools.data.DataStore;
022: import org.geotools.data.DataStoreFactorySpi;
023: import org.geotools.data.jdbc.ConnectionPool;
024: import org.geotools.data.jdbc.JDBCDataStoreConfig;
025: import org.geotools.data.jdbc.datasource.DataSourceUtil;
026: import org.geotools.data.jdbc.datasource.ManageableDataSource;
027:
028: import java.io.IOException;
029: import java.sql.SQLException;
030: import java.util.Map;
031: import java.util.logging.Logger;
032:
033: import javax.sql.DataSource;
034:
035: /**
036: * Implements the DataStoreFactorySpi interface to create an instance of a
037: * DB2DataStore.
038: *
039: * @author David Adler - IBM Corporation
040: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/db2/src/main/java/org/geotools/data/db2/DB2DataStoreFactory.java $
041: */
042: public class DB2DataStoreFactory extends AbstractDataStoreFactory
043: implements DataStoreFactorySpi {
044: public static final String DRIVERNAME = "com.ibm.db2.jcc.DB2Driver";
045:
046: private static final Logger LOGGER = org.geotools.util.logging.Logging
047: .getLogger("org.geotools.data.db2");
048:
049: // The DB2 JDBC universal driver class. isAvailable() uses this to
050: // check whether the DB2 JDBC library is in the classpath
051: private static final String DRIVER_CLASS = DRIVERNAME;
052: private static boolean isAvailable = false;
053: private static final Param DBTYPE = new Param("dbtype",
054: String.class, "must be 'DB2'", true, "DB2");
055: private static final Param HOST = new Param("host", String.class,
056: "DB2 host machine", true, "localhost");
057: private static final Param PORT = new Param("port", Integer.class,
058: "DB2 connection port", true, new Integer(50000));
059: private static final Param DATABASE = new Param("database",
060: String.class, "database name", true);
061: private static final Param USER = new Param("user", String.class,
062: "user name to login as", false);
063: private static final Param PASSWD = new Param("passwd",
064: String.class, "password used to login", false);
065: private static final Param TABSCHEMA = new Param("tabschema",
066: String.class, "default table schema", false);
067: public static final Param MAXCONN = new Param("max connections",
068: Integer.class, "maximum number of open connections", false,
069: new Integer(10));
070:
071: public static final Param MINCONN = new Param("min connections",
072: Integer.class, "minimum number of pooled connection",
073: false, new Integer(4));
074:
075: public static final Param VALIDATECONN = new Param(
076: "validate connections", Boolean.class,
077: "check connection is alive before using it", false,
078: Boolean.FALSE);
079: static final Param[] DB2PARMS = { DBTYPE, HOST, PORT, DATABASE,
080: USER, PASSWD, TABSCHEMA, MAXCONN, MINCONN, VALIDATECONN };
081:
082: /**
083: * canProcess and lastParams are used to cut out processing when
084: * 'canProcess' is called successively.
085: */
086: private boolean canProcess = false;
087: private Map lastParams = null;
088:
089: /**
090: * Constructs a DB2 data store using the params.
091: *
092: * If the port number is zero we will try to use the JDBC type 2 driver
093: * and if the port number is non-zer, we will try to use the JDBC type 4
094: * driver
095: *
096: * @param params The full set of information needed to construct a live
097: * data source. Should have dbtype equal to DB2, as well as host,
098: * user, passwd, database, and table schema.
099: *
100: * @return The created DataSource, this may be null if the required
101: * resource was not found or if insufficent parameters were given.
102: * Note that canProcess() should have returned false if the
103: * problem is to do with insuficent parameters.
104: *
105: * @throws IOException See DataSourceException
106: * @throws DataSourceException Thrown if there were any problems creating
107: * or connecting the datasource.
108: */
109: public DataStore createDataStore(Map params) throws IOException {
110: if (!canProcess(params)) {
111: throw new IOException("Invalid parameters");
112: }
113:
114: String host = (String) HOST.lookUp(params);
115: String user = (String) USER.lookUp(params);
116: String passwd = (String) PASSWD.lookUp(params);
117: int port = ((Integer) PORT.lookUp(params)).intValue();
118: String database = (String) DATABASE.lookUp(params);
119: String tabschema = (String) TABSCHEMA.lookUp(params);
120: Integer maxConn = (Integer) MAXCONN.lookUp(params);
121: Integer minConn = (Integer) MINCONN.lookUp(params);
122: Boolean validateConn = (Boolean) VALIDATECONN.lookUp(params);
123:
124: boolean validate = validateConn != null
125: && validateConn.booleanValue();
126: int maxActive = maxConn != null ? maxConn.intValue() : 10;
127: int maxIdle = minConn != null ? minConn.intValue() : 4;
128: String url = getJDBCUrl(host, port, database);
129: DataSource source = getDefaultDataSource(url, user, passwd,
130: maxActive, maxIdle, validate);
131:
132: // If the table schema is null or blank, uset the userid for the table schema
133: if (tabschema == null || tabschema.length() == 0) {
134: tabschema = user;
135: }
136: // if the table schema is not double-quoted, convert it to uppercase.
137: // if it is double-quoted, remove the double quotes.
138: if (tabschema.startsWith("\"")) {
139: tabschema = tabschema.substring(1, tabschema.length() - 1);
140: } else {
141: tabschema = tabschema.toUpperCase();
142: }
143: // Set the namespace and databaseSchemaName both to the table schema name
144: // Set the timeout value to 100 seconds to force FeatureTypeHandler caching
145: JDBCDataStoreConfig config = new JDBCDataStoreConfig(tabschema,
146: tabschema, 10000);
147: DB2DataStore ds;
148:
149: try {
150: ds = new DB2DataStore(source, config, url);
151: } catch (IOException e) {
152: LOGGER.info("Create DB2Datastore failed: " + e);
153: throw new DataSourceException(
154: "Could not create DB2DataStore", e);
155: }
156:
157: LOGGER.info("Successfully created DB2Datastore for: " + host
158: + ":" + port + "/" + database);
159:
160: return ds;
161: }
162:
163: public static ManageableDataSource getDefaultDataSource(String url,
164: String user, String passwd, int maxActive, int minIdle,
165: boolean validate) throws DataSourceException {
166: return DataSourceUtil.buildDefaultDataSource(url, DRIVER_CLASS,
167: user, passwd, maxActive, minIdle,
168: validate ? "select current date from sysibm.sysdummy1"
169: : null, false, 0);
170: }
171:
172: /**
173: * Returns the JDBC url used for connecting to a specific database
174: */
175: public static String getJDBCUrl(String host, int port,
176: String database) {
177: return "jdbc:db2://" + host + ":" + port + "/" + database;
178: }
179:
180: /**
181: * Creating a new DB2 database is not supported.
182: *
183: * @param params Doesn't much matter what this contains.
184: *
185: * @return DataStore But will always throw an exception
186: *
187: * @throws UnsupportedOperationException Cannot create new database
188: */
189: public DataStore createNewDataStore(Map params)
190: throws UnsupportedOperationException {
191: throw new UnsupportedOperationException(
192: "Creating a new DB2 database is not supported");
193: }
194:
195: /**
196: * Provide a String description of this data store.
197: *
198: * @return the data store description.
199: */
200: public String getDescription() {
201: return "DB2 Data Store";
202: }
203:
204: /**
205: * Name suitable for display to end user.
206: *
207: * <p>
208: * A non localized display name for this data store type.
209: * </p>
210: *
211: * @return A short name suitable for display in a user interface.
212: */
213: public String getDisplayName() {
214: return "DB2";
215: }
216:
217: /**
218: * Returns the array of parameters used by DB2.
219: *
220: * @return Param[] Array of parameters.
221: */
222: public Param[] getParametersInfo() {
223: return DB2PARMS;
224: }
225:
226: /**
227: * Check whether the parameter list passed identifies it as a request for a
228: * DB2DataStore.
229: *
230: * <p>
231: * Most critical is the 'dbtype' parameter which must have the value 'DB2'.
232: * If it is, then the remaining parameter values can be checked.
233: * </p>
234: *
235: * @param params Key/Value parameter list containing values required to
236: * identify a request for a DB2DataStore and remaining values to
237: * identify the database to be connected to.
238: *
239: * @return true if dbtype equals DB2, and contains keys for host, user,
240: * passwd, and database.
241: */
242: public boolean canProcess(Map params) {
243: String logInfo = "";
244:
245: // Hopefully we won't be called with a null parameter list.
246: if (params == null) {
247: return false;
248: }
249:
250: // Can't do anything if no dbtype or the dbtype is not DB2
251: String dbtype = (String) params.get("dbtype");
252:
253: if (dbtype == null) {
254: return (false);
255: }
256:
257: if (!(dbtype.equalsIgnoreCase("DB2"))) {
258: return (false);
259: }
260:
261: // If the parameters are the same as last time and it was ok last time
262: // it should still be ok.
263: if (this .canProcess && (this .lastParams == params)) {
264: return true;
265: }
266:
267: if (!super .canProcess(params)) {
268: return false;
269: }
270:
271: this .lastParams = params;
272: this .canProcess = true;
273:
274: return true;
275: }
276:
277: /**
278: * Check whether the DB2 JDBC type 4 driver is found in the classpath.
279: *
280: * <p>
281: * If it isn't, there is a problem since the FactoryFinder found the
282: * DB2DataStoreFactory but there is no driver to connect to a DB2
283: * database.
284: * </p>
285: *
286: * <p>
287: * The classpath should have db2jcc.jar and db2jcc_license_cu.jar
288: * </p>
289: *
290: * @return true if a DB2 driver is available for the DB2DataStore to
291: * connect to a DB2 database.
292: */
293: public boolean isAvailable() {
294: if (isAvailable) {
295: return isAvailable;
296: }
297:
298: try {
299: Class.forName(DRIVER_CLASS);
300: isAvailable = true;
301: } catch (ClassNotFoundException e) {
302: isAvailable = false;
303: }
304:
305: LOGGER.info("DB2 driver found: " + isAvailable);
306:
307: return isAvailable;
308: }
309: }
|