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