001: /*
002: * Geotools2 - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2002, 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;
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.geometryless;
018:
019: import java.io.IOException;
020: import java.nio.charset.Charset;
021: import java.sql.SQLException;
022: import java.util.Map;
023: import java.util.logging.Logger;
024:
025: import javax.sql.DataSource;
026:
027: import org.geotools.data.DataSourceException;
028: import org.geotools.data.DataStore;
029: import org.geotools.data.jdbc.ConnectionPool;
030: import org.geotools.data.jdbc.datasource.DataSourceUtil;
031: import org.geotools.factory.AbstractFactory;
032:
033: /**
034: * Creates a Geometryless JDBC based on the conection params.
035: *
036: * <p>
037: * This factory should be registered in the META-INF/ folder, under services/
038: * in the DataStoreFactorySpi file.
039: * </p>
040: *
041: * <p>
042: * REVISIT: I believe the use of the namespace param needs to be revisited. GeoServer
043: * is going to start making use of this, as the XML namespace that the feature
044: * type should be created with. The use of namespace in this package is that
045: * of a database schema name. Though investigating futher it looks like all
046: * the dbs use it that way. So this is just a note that xml namespace and
047: * database namespace need to be reconciled. The work done in this package
048: * seems to be begging some datastore hierarchy refactoring, hopefully when
049: * we do that we can also get jdbc datastore factories in a hierarchy, instead
050: * of each just doing their own thing. -ch
051: * </p>
052: *
053: * @author Rob Atkinson, Social Change Online
054: * @author Chris Holmes, TOPP
055: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/unsupported/geometryless/src/main/java/org/geotools/data/geometryless/BBOXDataStoreFactory.java $
056: * @version $Id: BBOXDataStoreFactory.java 27862 2007-11-12 19:51:19Z desruisseaux $
057: */
058: public class BBOXDataStoreFactory extends AbstractFactory implements
059: org.geotools.data.DataStoreFactorySpi {
060:
061: private static final Logger LOGGER = org.geotools.util.logging.Logging
062: .getLogger("org.geotools.data.geometryless");
063:
064: private static final String GEOM_NAME_DEFAULT = "the_geom";
065:
066: /** Specified JDBC driver class. */
067: static final Param DRIVER = new Param("driver", String.class,
068: "Java Class name of installed driver", true,
069: "org.geotools.data.geometryless.wrapper.PGConnectionPool");
070:
071: /** Specified JDBC driver class calling URL */
072: static final Param URLPREFIX = new Param("urlprefix", String.class,
073: "complete jdbc URL for the database connection", true,
074: "jdbc:postgresql://localhost:5432/postgres");
075:
076: /** Param, package visibiity for JUnit tests */
077: static final Param DBTYPE = new Param("dbtype", String.class,
078: "must be 'bbox'", true, "BBOX");
079:
080: /** Param, package visibiity for JUnit tests */
081: static final Param MINXCOLUMN = new Param(
082: "minxcolumn",
083: String.class,
084: "name of JDBC results column containing eastmost easting (x, longitude etc)",
085: true, "minx");
086:
087: /** Param, package visibiity for JUnit tests */
088: static final Param MINYCOLUMN = new Param(
089: "minycolumn",
090: String.class,
091: "name of JDBC results column containing southmost northing (y, latitude etc)",
092: true, "miny");
093:
094: /** Param, package visibiity for JUnit tests */
095: static final Param MAXXCOLUMN = new Param(
096: "maxxcolumn",
097: String.class,
098: "name of JDBC results column containing westmost easting (x, longitude etc)",
099: true, "maxx");
100:
101: /** Param, package visibiity for JUnit tests */
102: static final Param MAXYCOLUMN = new Param(
103: "maxycolumn",
104: String.class,
105: "name of JDBC results column containing northmost northing (y, latitude etc)",
106: true, "maxy");
107:
108: static final Param GEOMNAME = new Param(
109: "geom_name",
110: String.class,
111: "the "
112: + "name of the geometry attribute to generate from the bbox columns",
113: false, GEOM_NAME_DEFAULT);
114:
115: /** Param, package visibiity for JUnit tests */
116: static final Param USER = new Param("user", String.class,
117: "user name to login as", true, "");
118:
119: /** Param, package visibiity for JUnit tests */
120: static final Param PASSWD = new Param("passwd", String.class,
121: "password used to login", true, "");
122:
123: /**
124: * Param, package visibiity for JUnit tests.
125: *
126: * <p>
127: * Example of a non simple Param type where custom parse method is
128: * required.
129: * </p>
130: *
131: * <p>
132: * When we convert to BeanInfo custom PropertyEditors will be required for
133: * this Param.
134: * </p>
135: */
136: static final Param CHARSET = new Param("charset", Charset.class,
137: "character set", false, Charset.forName("ISO-8859-1")) {
138: public Object parse(String text) throws IOException {
139: return Charset.forName(text);
140: }
141:
142: public String text(Object value) {
143: return ((Charset) value).name();
144: }
145: };
146:
147: /** Param, package visibiity for JUnit tests */
148: static final Param SCHEMA = new Param("schema", String.class,
149: "database schema", false);
150:
151: /** Param, package visibiity for JUnit tests */
152: static final Param NAMESPACE = new Param("namespace", String.class,
153: "namespace prefix used", false);
154:
155: /** Array with all of the params */
156: static final Param[] arrayParameters = { DBTYPE, SCHEMA, USER,
157: PASSWD, CHARSET, NAMESPACE, DRIVER, URLPREFIX, MINXCOLUMN,
158: MINYCOLUMN, MAXXCOLUMN, MAXYCOLUMN, GEOMNAME };
159:
160: /**
161: * Creates a new instance of - this constructor needed for factory finder apparently
162: */
163: public BBOXDataStoreFactory() {
164:
165: }
166:
167: /**
168: * Creates a new instance of PostgisDataStoreFactory.
169: * <p>
170: * Note: the map of thins is used when constructing datastore instandces,
171: * as such it needs to be passed onto the datastores so that they can make use of this
172: * information when creating content.
173: * </p>
174: */
175: public BBOXDataStoreFactory(Map hints) {
176: this .hints.putAll(hints);
177: }
178:
179: /**
180: * Checks to see if all the postgis params are there.
181: * <p>
182: * Should have:
183: * </p>
184: *
185: * <ul>
186: * <li>
187: * dbtype: equal to postgis
188: * </li>
189: * <li>
190: * host
191: * </li>
192: * <li>
193: * user
194: * </li>
195: * <li>
196: * passwd
197: * </li>
198: * <li>
199: * database
200: * </li>
201: * <li>
202: * charset
203: * </li>
204: * </ul>
205: *
206: *
207: * @param params Set of parameters needed for a jdbc data store.
208: *
209: * @return <code>true</code> if dbtype equals BBOX, and contains keys
210: * for host, user, passwd, and database.
211: */
212: public boolean canProcess(Map params) {
213: Object value;
214:
215: if (params != null) {
216: for (int i = 0; i < arrayParameters.length; i++) {
217: if (!(((value = params.get(arrayParameters[i].key)) != null) && (arrayParameters[i].type
218: .isInstance(value)))) {
219: if (arrayParameters[i].required) {
220: LOGGER
221: .config("BBOXDataStoreFactory: canProcess() Cannot find param "
222: + arrayParameters[i].key
223: + ":"
224: + arrayParameters[i].type
225: + value);
226: return (false);
227: }
228: }
229: }
230: } else {
231: LOGGER
232: .finer("BBOXDataStoreFactory: can Process Cannot find params ");
233: return (false);
234: }
235:
236: if (!(((String) params.get("dbtype")).equalsIgnoreCase("BBOX"))) {
237: return (false);
238: } else {
239: return (true);
240: }
241: }
242:
243: /**
244: * Construct a postgis data store using the params.
245: *
246: * @param params The full set of information needed to construct a live
247: * data source. Should have dbtype equal to BBOX, as well as
248: * host, user, passwd, database, and table.
249: *
250: * @return The created DataSource, this may be null if the required
251: * resource was not found or if insufficent parameters were given.
252: * Note that canProcess() should have returned false if the
253: * problem is to do with insuficent parameters.
254: *
255: * @throws IOException See DataSourceException
256: * @throws DataSourceException Thrown if there were any problems creating
257: * or connecting the datasource.
258: */
259: public DataStore createDataStore(Map params) throws IOException {
260: if (canProcess(params)) {
261: } else {
262: throw new IOException("The parameteres map isn't correct!!");
263: }
264:
265: // String host = (String) HOST.lookUp(params);
266: String user = (String) USER.lookUp(params);
267: String passwd = (String) PASSWD.lookUp(params);
268: // String port = (String) PORT.lookUp(params);
269: // String database = (String) DATABASE.lookUp(params);
270: String schema = (String) SCHEMA.lookUp(params);
271: Charset charSet = (Charset) CHARSET.lookUp(params);
272: String namespace = (String) NAMESPACE.lookUp(params);
273: String driver = (String) DRIVER.lookUp(params);
274: String urlprefix = (String) URLPREFIX.lookUp(params);
275: String minxcolumn = (String) MINXCOLUMN.lookUp(params);
276: String minycolumn = (String) MINYCOLUMN.lookUp(params);
277: String maxxcolumn = (String) MAXXCOLUMN.lookUp(params);
278: String maxycolumn = (String) MAXYCOLUMN.lookUp(params);
279: String geom_name = (String) GEOMNAME.lookUp(params);
280:
281: // Try processing params first so we can get an error message
282: // back to the user
283: //
284: if (!canProcess(params)) {
285: return null;
286: }
287: /*
288: *
289: * JDBCConnectionFactory connFact = new JDBCConnectionFactory( urlprefix, driver );
290:
291: // MySQLConnectionFactory connFact = new MySQLConnectionFactory(host, Integer.parseInt(port), database);
292:
293: connFact.setLogin(user, passwd);
294:
295: if (charSet != null) {
296: connFact.setCharSet(charSet.name());
297: }
298:
299: ConnectionPool pool;
300:
301: try {
302: pool = connFact.getConnectionPool();
303:
304: java.sql.Connection c = pool.getConnection();
305: if( c == null )
306: {
307: throw new SQLException("Pool created but connection null ");
308: }
309: else {
310: c.close();
311: }
312: } catch (SQLException e) {
313: throw new DataSourceException("Could not create connection", e);
314: }
315: */
316: DataSource dataSource = DataSourceUtil.buildDefaultDataSource(
317: urlprefix, driver, user, passwd, null);
318:
319: if (geom_name == null) {
320: geom_name = GEOM_NAME_DEFAULT;
321: }
322: if (namespace != null) {
323: return new BBOXDataStore(dataSource, schema, namespace,
324: minxcolumn, minycolumn, maxxcolumn, maxycolumn,
325: geom_name);
326: } else {
327: return new BBOXDataStore(dataSource);
328: }
329: }
330:
331: /**
332: * The datastore cannot create a new database.
333: *
334: * @param params
335: *
336: *
337: * @throws IOException See UnsupportedOperationException
338: * @throws UnsupportedOperationException Cannot create new database
339: */
340: public DataStore createNewDataStore(Map params) throws IOException {
341: throw new UnsupportedOperationException(
342: "Generic JDBC datastore cannot create a new Database");
343: }
344:
345: /**
346: * Describe the nature of the datasource constructed by this factory.
347: *
348: * @return A human readable description that is suitable for inclusion in a
349: * list of available datasources.
350: */
351: public String getDescription() {
352: return "GeometrylessJDBC - constructs geometry from Bounding Box ";
353: }
354:
355: public String getDisplayName() {
356: return "GeometrylessJDBC - Bounding Box";
357: }
358:
359: // public DataSourceMetadataEnity createMetadata( Map params ) throws IOException {
360: // String host = (String) HOST.lookUp(params);
361: // String user = (String) USER.lookUp(params);
362: // String port = (String) PORT.lookUp(params);
363: // String database = (String) DATABASE.lookUp(params);
364: // return new DataSourceMetadataEnity( host+":"+port, database, "Connection to "+getDisplayName()+" on "+host+" as "+user );
365: // }
366: /**
367: * Test to see if this datastore is available, if it has all the
368: * appropriate libraries to construct a datastore. This datastore just
369: * returns true for now. This method is used for gui apps, so as to not
370: * advertise data store capabilities they don't actually have.
371: *
372: * @return <tt>true</tt> if and only if this factory is available to create
373: * DataStores.
374: */
375: public boolean isAvailable() {
376: /* try {
377: Class.forName(DRIVER);
378: } catch (ClassNotFoundException cnfe) {
379: return false;
380: }
381: */
382: return true;
383: }
384:
385: /**
386: * Describe parameters.
387: *
388: *
389: * @see org.geotools.data.DataStoreFactorySpi#getParametersInfo()
390: */
391: public Param[] getParametersInfo() {
392: return new Param[] { DBTYPE, USER, PASSWD, CHARSET, NAMESPACE,
393: DRIVER, URLPREFIX, MINXCOLUMN, MINYCOLUMN, MAXXCOLUMN,
394: MAXYCOLUMN, GEOMNAME };
395: }
396:
397: /* (non-Javadoc)
398: * @see org.geotools.factory.Factory#getImplementationHints()
399: */
400: public Map getImplementationHints() {
401: return hints;
402: }
403: }
|