/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2003-2008, Open Source Geospatial Foundation (OSGeo) * * 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.oracle; import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.logging.Logger; import javax.sql.DataSource; import org.geotools.data.DataSourceException; import org.geotools.data.DataStore; import org.geotools.data.DataStoreFactorySpi; import org.geotools.data.jdbc.datasource.DataSourceUtil; import org.geotools.data.jdbc.datasource.ManageableDataSource; /** * Creates an OracleDataStore based on the correct params. * <p> * This factory should be registered in the META-INF/ folder, under services/ * in the DataStoreFactorySpi file. * </p> * * @author Jody Garnett, Refractions Research * @author Sean Geoghegan, Defence Science and Technology Organisation * * @source $URL$ */ public class OracleDataStoreFactory implements DataStoreFactorySpi { private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.data.oracle"); private static final String JDBC_DRIVER = "oracle.jdbc.driver.OracleDriver"; private static final String JDBC_PATH = "jdbc:oracle:thin:@"; /** * Creates a new instance of OracleDataStoreFactory */ public OracleDataStoreFactory() { } /** * Determines whether DataStore created by this factory can process the * parameters. * <p> * Required Parameters are: * </p> * <ul> * <li> * <code>dbtype</code> - must equal "oracle" * </li> * <li> * <code>host</code> * </li> * <li> * <code>port</code> * </li> * <li> * <code>user</code> * </li> * <li> * <code>passwd</code> * </li> * <li> * <code>instance</code> * </li> * </ul> * * <p> * There are no defaults since each parameter must be explicitly defined by the user, or * another DataSourceFactorySpi should be used. This behaviour is defined in the * DataStoreFactorySpi contract. * </p> * * @param params The parameter to check. * * @return True if all the required parameters are supplied. */ public boolean canProcess(Map params) { if (params != null) { if (params.get("dbtype") == null || !params.get("dbtype").toString().equalsIgnoreCase("oracle")) { return false; //short circuit test } Param arrayParameters[] = getParametersInfo(); for (int i = 0; i < arrayParameters.length; i++) { Param param = arrayParameters[i]; Object value; if( !params.containsKey( param.key ) ){ if( param.required ){ return false; // missing required key! } else { continue; } } try { value = param.lookUp( params ); } catch (IOException e) { LOGGER.warning( param.key+":"+e ); // could not upconvert/parse to expected type! // even if this parameter is not required // we are going to refuse to process // these params return false; } if( value == null ){ if (param.required) { return (false); } } else { if ( !param.type.isInstance( value )){ return false; // value was not of the required type } } } } else { return (false); } if (!(((String) params.get("dbtype")).equalsIgnoreCase("oracle"))) { return (false); } else { return (true); } } /** * Construct a postgis data store using the params. * * @param params The full set of information needed to construct a live * data source. Should have dbtype equal to postgis, as well as * host, user, passwd, database, and table. * * @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 DataSourceException Thrown if there were any problems creating * or connecting the datasource. */ public DataStore createDataStore(Map params) throws IOException { /* There are no defaults here. Calling canProcess verifies that * all these variables exist. */ String host = (String) HOST.lookUp( params ); Integer port = (Integer) PORT.lookUp( params ); String instance = (String) INSTANCE.lookUp( params ); String user = (String) USER.lookUp( params ); String passwd = (String) PASSWD.lookUp( params ); String schema = (String) SCHEMA.lookUp( params ); // checks uppercase String namespace = (String) NAMESPACE.lookUp( params ); String dbtype = (String) DBTYPE.lookUp( params ); Integer maxConn = (Integer) MAXCONN.lookUp(params); Integer minConn = (Integer) MINCONN.lookUp(params); Boolean validateConn = (Boolean) VALIDATECONN.lookUp(params); if( !"oracle".equals( dbtype )){ throw new IOException( "Parameter 'dbtype' must be oracle"); } if (!canProcess(params)) { throw new IOException("Cannot connect using provided parameters"); } boolean validate = validateConn != null && validateConn.booleanValue(); int maxActive = maxConn != null ? maxConn.intValue() : 10; int maxIdle = minConn != null ? minConn.intValue() : 4; DataSource source = getDefaultDataSource(host, user, passwd, port.intValue(), instance, maxActive, maxIdle, validate); OracleDataStore dataStore = new OracleDataStore(source, namespace, schema, new HashMap()); return dataStore; } public static ManageableDataSource getDefaultDataSource(String host, String user, String passwd, int port, String instance, int maxActive, int minIdle, boolean validate) throws DataSourceException { String dbUrl = null; if( instance.startsWith("(") ) dbUrl = JDBC_PATH + instance; else if( instance.startsWith("/") ) dbUrl = JDBC_PATH + "//" + host + ":" + port + instance; else dbUrl = JDBC_PATH + host + ":" + port + ":" + instance; return DataSourceUtil.buildDefaultDataSource(dbUrl, JDBC_DRIVER, user, passwd, maxActive, minIdle, validate ? "select sysdate from dual" : null, false, 0); } /** * Oracle cannot create a new database. * @param params * @throws UnsupportedOperationException Cannot create new database */ public DataStore createNewDataStore(Map params) throws IOException { throw new UnsupportedOperationException("Oracle cannot create a new Database"); } public String getDisplayName() { return "Oracle"; } /** * Describe the nature of the datastore constructed by this factory. * * @return A human readable description that is suitable for inclusion in a * list of available datasources. */ public String getDescription() { return "Oracle Spatial Database"; } // public DataSourceMetadataEnity createMetadata( Map params ) throws IOException { // String host = (String) HOST.lookUp( params ); // String port = (String) PORT.lookUp( params ); // String instance = (String) INSTANCE.lookUp( params ); // String user = (String) USER.lookUp( params ); // String schema = (String) SCHEMA.lookUp( params ); // checks uppercase // return new DataSourceMetadataEnity( host+":"+port, instance, "Connect to oracle using schema '"+schema+"' as "+user ); // } /** * Returns whether the OracleDataStoreFactory would actually be able to * generate a DataStore. Depends on whether the appropriate libraries * are on the classpath. For now just checks for the presence of the * JDBC driver, should probably check for SDOAPI as well. * * @return True if the classes to make an oracle connection are present. * @task Figure out a class to check the SDOAPI for, and check it. */ public boolean isAvailable() { try { Class.forName(JDBC_DRIVER); } catch (ClassNotFoundException cnfe) { return false; } return true; //check for sdoapi too? } static final Param DBTYPE = new Param("dbtype", String.class, "This must be 'oracle'.", true,"oracle"); static final Param HOST = new Param("host", String.class, "The host name of the server.", true); static final Param PORT = new Param("port", Integer.class, "The port oracle is running on. " + "(Default is 1521)", true, "1521"); static final Param USER = new Param("user", String.class, "The user name to log in with.", true); static final Param PASSWD = new Param("passwd", String.class, "The password.", true); 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 INSTANCE = new Param("instance", String.class, "The name of the Oracle instance to connect to.", true); /** Apparently Schema must be uppercase */ static final Param SCHEMA = new Param("schema", String.class, "The schema name to narrow down the exposed tables (must be upper case).", false){ public Object lookUp(Map map) throws IOException { if (!map.containsKey(key)) { if (required) { throw new IOException("Parameter " + key + " is required:" + description); } else { return null; } } Object value = map.get(key); if (value == null) { return null; } if (value instanceof String) { String text = (String) value; if( text == null ){ return null; } else if( text.equals( text.toUpperCase() ) ){ return text; } else { throw new IOException("Schema must be supplied in uppercase" ); } } else { throw new IOException( "String required for parameter " + key + ": not " + value.getClass().getName()); } } }; static final Param NAMESPACE = new Param("namespace", String.class, "The namespace to give the DataStore", false); /** * Describe parameters. * * @see org.geotools.data.DataStoreFactorySpi#getParametersInfo() */ public Param[] getParametersInfo() { return new Param[]{ DBTYPE, HOST, PORT, USER, PASSWD, INSTANCE, MAXCONN, MINCONN, VALIDATECONN, SCHEMA, NAMESPACE }; } /** * Returns the implementation hints. The default implementation returns en empty map. */ public Map getImplementationHints() { return Collections.EMPTY_MAP; } }