001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2003-2006, Geotools Project Managment Committee (PMC)
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; either
009: * version 2.1 of the License, or (at your option) any later version.
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: package org.geotools.data.oracle;
017:
018: import java.io.IOException;
019: import java.util.Collections;
020: import java.util.HashMap;
021: import java.util.Map;
022: import java.util.logging.Logger;
023:
024: import javax.sql.DataSource;
025:
026: import org.geotools.data.DataSourceException;
027: import org.geotools.data.DataStore;
028: import org.geotools.data.DataStoreFactorySpi;
029: import org.geotools.data.jdbc.datasource.DataSourceUtil;
030: import org.geotools.data.jdbc.datasource.ManageableDataSource;
031:
032: /**
033: * Creates a PostgisDataStore baed on the correct params.
034: * <p>
035: * This factory should be registered in the META-INF/ folder, under services/
036: * in the DataStoreFactorySpi file.
037: * </p>
038: *
039: * @author Jody Garnett, Refractions Research
040: * @author Sean Geoghegan, Defence Science and Technology Organisation
041: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/oracle-spatial/src/main/java/org/geotools/data/oracle/OracleDataStoreFactory.java $
042: */
043: public class OracleDataStoreFactory implements DataStoreFactorySpi {
044: private static final Logger LOGGER = org.geotools.util.logging.Logging
045: .getLogger("org.geotools.data.oracle");
046: private static final String JDBC_DRIVER = "oracle.jdbc.driver.OracleDriver";
047: private static final String JDBC_PATH = "jdbc:oracle:thin:@";
048:
049: /**
050: * Creates a new instance of OracleDataStoreFactory
051: */
052: public OracleDataStoreFactory() {
053:
054: }
055:
056: /**
057: * Determines whether DataStore created by this factory can process the
058: * parameters.
059: * <p>
060: * Required Parameters are:
061: * </p>
062: * <ul>
063: * <li>
064: * <code>dbtype</code> - must equal "oracle"
065: * </li>
066: * <li>
067: * <code>host</code>
068: * </li>
069: * <li>
070: * <code>port</code>
071: * </li>
072: * <li>
073: * <code>user</code>
074: * </li>
075: * <li>
076: * <code>passwd</code>
077: * </li>
078: * <li>
079: * <code>instance</code>
080: * </li>
081: * </ul>
082: *
083: * <p>
084: * There are no defaults since each parameter must be explicitly defined by the user, or
085: * another DataSourceFactorySpi should be used. This behaviour is defined in the
086: * DataStoreFactorySpi contract.
087: * </p>
088: *
089: * @param params The parameter to check.
090: *
091: * @return True if all the required parameters are supplied.
092: */
093: public boolean canProcess(Map params) {
094: if (params != null) {
095: if (params.get("dbtype") == null
096: || !params.get("dbtype").toString()
097: .equalsIgnoreCase("oracle")) {
098: return false; //short circuit test
099: }
100: Param arrayParameters[] = getParametersInfo();
101: for (int i = 0; i < arrayParameters.length; i++) {
102: Param param = arrayParameters[i];
103: Object value;
104: if (!params.containsKey(param.key)) {
105: if (param.required) {
106: return false; // missing required key!
107: } else {
108: continue;
109: }
110: }
111: try {
112: value = param.lookUp(params);
113: } catch (IOException e) {
114: LOGGER.warning(param.key + ":" + e);
115: // could not upconvert/parse to expected type!
116: // even if this parameter is not required
117: // we are going to refuse to process
118: // these params
119: return false;
120: }
121: if (value == null) {
122: if (param.required) {
123: return (false);
124: }
125: } else {
126: if (!param.type.isInstance(value)) {
127: return false; // value was not of the required type
128: }
129: }
130: }
131: } else {
132: return (false);
133: }
134: if (!(((String) params.get("dbtype"))
135: .equalsIgnoreCase("oracle"))) {
136: return (false);
137: } else {
138: return (true);
139: }
140: }
141:
142: /**
143: * Construct a postgis data store using the params.
144: *
145: * @param params The full set of information needed to construct a live
146: * data source. Should have dbtype equal to postgis, as well as
147: * host, user, passwd, database, and table.
148: *
149: * @return The created DataSource, this may be null if the required
150: * resource was not found or if insufficent parameters were given.
151: * Note that canProcess() should have returned false if the
152: * problem is to do with insuficent parameters.
153: *
154: * @throws DataSourceException Thrown if there were any problems creating
155: * or connecting the datasource.
156: */
157: public DataStore createDataStore(Map params) throws IOException {
158: /* There are no defaults here. Calling canProcess verifies that
159: * all these variables exist.
160: */
161: String host = (String) HOST.lookUp(params);
162: Integer port = (Integer) PORT.lookUp(params);
163: String instance = (String) INSTANCE.lookUp(params);
164: String user = (String) USER.lookUp(params);
165: String passwd = (String) PASSWD.lookUp(params);
166: String schema = (String) SCHEMA.lookUp(params); // checks uppercase
167: String namespace = (String) NAMESPACE.lookUp(params);
168: String dbtype = (String) DBTYPE.lookUp(params);
169: Integer maxConn = (Integer) MAXCONN.lookUp(params);
170: Integer minConn = (Integer) MINCONN.lookUp(params);
171: Boolean validateConn = (Boolean) VALIDATECONN.lookUp(params);
172:
173: if (!"oracle".equals(dbtype)) {
174: throw new IOException("Parameter 'dbtype' must be oracle");
175: }
176:
177: if (!canProcess(params)) {
178: throw new IOException(
179: "Cannot connect using provided parameters");
180: }
181:
182: boolean validate = validateConn != null
183: && validateConn.booleanValue();
184: int maxActive = maxConn != null ? maxConn.intValue() : 10;
185: int maxIdle = minConn != null ? minConn.intValue() : 4;
186: DataSource source = getDefaultDataSource(host, user, passwd,
187: port.intValue(), instance, maxActive, maxIdle, validate);
188: OracleDataStore dataStore = new OracleDataStore(source,
189: namespace, schema, new HashMap());
190:
191: return dataStore;
192: }
193:
194: public static ManageableDataSource getDefaultDataSource(
195: String host, String user, String passwd, int port,
196: String instance, int maxActive, int minIdle,
197: boolean validate) throws DataSourceException {
198: String dbUrl = null;
199: if (instance.startsWith("("))
200: dbUrl = JDBC_PATH + instance;
201: else if (instance.startsWith("/"))
202: dbUrl = JDBC_PATH + "//" + host + ":" + port + instance;
203: else
204: dbUrl = JDBC_PATH + host + ":" + port + ":" + instance;
205:
206: return DataSourceUtil.buildDefaultDataSource(dbUrl,
207: JDBC_DRIVER, user, passwd, maxActive, minIdle,
208: validate ? "select sysdate from dual" : null, false, 0);
209: }
210:
211: /**
212: * Oracle cannot create a new database.
213: * @param params
214: * @throws UnsupportedOperationException Cannot create new database
215: */
216: public DataStore createNewDataStore(Map params) throws IOException {
217: throw new UnsupportedOperationException(
218: "Oracle cannot create a new Database");
219: }
220:
221: public String getDisplayName() {
222: return "Oracle";
223: }
224:
225: /**
226: * Describe the nature of the datastore constructed by this factory.
227: *
228: * @return A human readable description that is suitable for inclusion in a
229: * list of available datasources.
230: */
231: public String getDescription() {
232: return "Oracle Spatial Database";
233: }
234:
235: // public DataSourceMetadataEnity createMetadata( Map params ) throws IOException {
236: // String host = (String) HOST.lookUp( params );
237: // String port = (String) PORT.lookUp( params );
238: // String instance = (String) INSTANCE.lookUp( params );
239: // String user = (String) USER.lookUp( params );
240: // String schema = (String) SCHEMA.lookUp( params ); // checks uppercase
241: // return new DataSourceMetadataEnity( host+":"+port, instance, "Connect to oracle using schema '"+schema+"' as "+user );
242: // }
243: /**
244: * Returns whether the OracleDataStoreFactory would actually be able to
245: * generate a DataStore. Depends on whether the appropriate libraries
246: * are on the classpath. For now just checks for the presence of the
247: * JDBC driver, should probably check for SDOAPI as well.
248: *
249: * @return True if the classes to make an oracle connection are present.
250: * @task Figure out a class to check the SDOAPI for, and check it.
251: */
252: public boolean isAvailable() {
253: try {
254: Class.forName(JDBC_DRIVER);
255: } catch (ClassNotFoundException cnfe) {
256: return false;
257: }
258: return true;
259: //check for sdoapi too?
260: }
261:
262: static final Param DBTYPE = new Param("dbtype", String.class,
263: "This must be 'oracle'.", true, "oracle");
264: static final Param HOST = new Param("host", String.class,
265: "The host name of the server.", true);
266: static final Param PORT = new Param("port", Integer.class,
267: "The port oracle is running on. " + "(Default is 1521)",
268: true, "1521");
269: static final Param USER = new Param("user", String.class,
270: "The user name to log in with.", true);
271: static final Param PASSWD = new Param("passwd", String.class,
272: "The password.", true);
273: public static final Param MAXCONN = new Param("max connections",
274: Integer.class, "maximum number of open connections", false,
275: new Integer(10));
276: public static final Param MINCONN = new Param("min connections",
277: Integer.class, "minimum number of pooled connection",
278: false, new Integer(4));
279: public static final Param VALIDATECONN = new Param(
280: "validate connections", Boolean.class,
281: "check connection is alive before using it", false,
282: Boolean.FALSE);
283: static final Param INSTANCE = new Param("instance", String.class,
284: "The name of the Oracle instance to connect to.", true);
285:
286: /** Apparently Schema must be uppercase */
287: static final Param SCHEMA = new Param(
288: "schema",
289: String.class,
290: "The schema name to narrow down the exposed tables (must be upper case).",
291: false) {
292: public Object lookUp(Map map) throws IOException {
293: if (!map.containsKey(key)) {
294: if (required) {
295: throw new IOException("Parameter " + key
296: + " is required:" + description);
297: } else {
298: return null;
299: }
300: }
301: Object value = map.get(key);
302: if (value == null) {
303: return null;
304: }
305: if (value instanceof String) {
306: String text = (String) value;
307: if (text == null) {
308: return null;
309: } else if (text.equals(text.toUpperCase())) {
310: return text;
311: } else {
312: throw new IOException(
313: "Schema must be supplied in uppercase");
314: }
315: } else {
316: throw new IOException("String required for parameter "
317: + key + ": not " + value.getClass().getName());
318: }
319: }
320: };
321: static final Param NAMESPACE = new Param("namespace", String.class,
322: "The namespace to give the DataStore", false);
323:
324: /**
325: * Describe parameters.
326: *
327: * @see org.geotools.data.DataStoreFactorySpi#getParametersInfo()
328: */
329: public Param[] getParametersInfo() {
330: return new Param[] { DBTYPE, HOST, PORT, USER, PASSWD,
331: INSTANCE, MAXCONN, MINCONN, VALIDATECONN, SCHEMA,
332: NAMESPACE };
333: }
334:
335: /**
336: * Returns the implementation hints. The default implementation returns en empty map.
337: */
338: public Map getImplementationHints() {
339: return Collections.EMPTY_MAP;
340: }
341: }
|