/*
* GeoTools - The Open Source Java GIS Toolkit
* http://geotools.org
*
* (C) 2002-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.geometryless;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Map;
import java.util.logging.Logger;
import javax.sql.DataSource;
import org.geotools.data.DataSourceException;
import org.geotools.data.FeatureReader;
import org.geotools.data.FeatureWriter;
import org.geotools.data.Transaction;
import org.geotools.data.geometryless.attributeio.PointXYAttributeIO;
import org.geotools.data.geometryless.filter.SQLEncoderLocationsXY;
import org.geotools.data.jdbc.JDBCFeatureWriter;
import org.geotools.data.jdbc.QueryData;
import org.geotools.data.jdbc.SQLBuilder;
import org.geotools.data.jdbc.attributeio.AttributeIO;
import org.geotools.data.sql.BypassSqlFeatureTypeHandler;
import org.geotools.data.sql.BypassSqlSQLBuilder;
import org.geotools.feature.AttributeTypeBuilder;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.filter.Filter;
import com.vividsolutions.jts.geom.Point;
/**
* An implementation of the GeoTools Data Store API for a generic non-spatial
* database platform.
*
* This specialisation uses X,Y (lat/lon) database colums to hold point
* geometries
*
* the constructor is used to pass metadata from datastore to SQLEncoder class
*
* <br>
* Please see {@link org.geotools.data.jdbc.JDBCDataStore class JDBCDataStore}
* and {@link org.geotools.data.DataStore interface DataStore} for DataStore
* usage details.
*
* @author Rob Atkinson rob@socialchange.net.au
* @source $URL:
* http://svn.geotools.org/geotools/trunk/gt/modules/unsupported/geometryless/src/main/java/org/geotools/data/geometryless/LocationsXYDataStore.java $
*/
public class LocationsXYDataStore extends org.geotools.data.geometryless.JDBCDataStore {
/** The logger for the mysql module. */
private static final Logger LOGGER = org.geotools.util.logging.Logging.getLogger("org.geotools.data.geometryless");
private String XCoordColumnName = null;
private String YCoordColumnName = null;
private String geomName = null;
public LocationsXYDataStore(DataSource connectionPool) throws IOException {
super(connectionPool);
}
/**
* Constructor for LocationsXYDataStore where the database schema name is
* provided.
*
* @param connectionPool
* a {@link org.geotools.data.jdbc.ConnectionPool ConnectionPool}
* @param databaseSchemaName
* the database schema. Can be null. See the comments for the
* parameter schemaPattern in
* {@link java.sql.DatabaseMetaData#getTables(String, String, String, String[]) DatabaseMetaData.getTables},
* because databaseSchemaName behaves in the same way.
* @throws IOException
* if the database cannot be properly accessed
*/
public LocationsXYDataStore(DataSource connectionPool, String databaseSchemaName,
String namespace, String x, String y, String geomName) throws IOException {
// databaseSchemaName can be null
super(connectionPool, databaseSchemaName, namespace);
this.XCoordColumnName = x;
this.YCoordColumnName = y;
this.geomName = geomName;
}
/**
* Utility method for getting a FeatureWriter for modifying existing
* features, using no feature filtering and auto-committing. Not used for
* adding new features.
*
* @param typeName
* the feature type name (the table name)
* @return a FeatureWriter for modifying existing features
* @throws IOException
* if the database cannot be properly accessed
*/
public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriter(String typeName) throws IOException {
return getFeatureWriter(typeName, Filter.INCLUDE, Transaction.AUTO_COMMIT);
}
/**
* Utility method for getting a FeatureWriter for adding new features, using
* auto-committing. Not used for modifying existing features.
*
* @param typeName
* the feature type name (the table name)
* @return a FeatureWriter for adding new features
* @throws IOException
* if the database cannot be properly accessed
*/
public FeatureWriter<SimpleFeatureType, SimpleFeature> getFeatureWriterAppend(String typeName) throws IOException {
return getFeatureWriterAppend(typeName, Transaction.AUTO_COMMIT);
}
/**
* Constructs an AttributeType from a row in a ResultSet. The ResultSet
* contains the information retrieved by a call to getColumns() on the
* DatabaseMetaData object. This information can be used to construct an
* Attribute Type.
*
* <p>
* This simply returns the constructed geometry when the column is the first
* (X)
* </p>
*
* <p>
* Note: Overriding methods must never move the current row pointer in the
* result set.
* </p>
*
* @param rs
* The ResultSet containing the result of a
* DatabaseMetaData.getColumns call.
*
* @return The AttributeType built from the ResultSet.
*
* @throws SQLException
* If an error occurs processing the ResultSet.
* @throws DataSourceException
* Provided for overriding classes to wrap exceptions caused by
* other operations they may perform to determine additional
* types. This will only be thrown by the default implementation
* if a type is present that is not present in the
* TYPE_MAPPINGS.
*/
protected AttributeDescriptor buildAttributeType(ResultSet rs) throws IOException {
final int COLUMN_NAME = 4;
final int DATA_TYPE = 5;
final int TYPE_NAME = 6;
try {
int dataType = rs.getInt(DATA_TYPE);
String colName = rs.getString(COLUMN_NAME);
LOGGER.fine("dataType: " + dataType + " " + rs.getString(TYPE_NAME) + " " + colName);
Class type = (Class) TYPE_MAPPINGS.get(new Integer(dataType));
// This should be improved - first should probably check for
// presence of both the x and y columns, only create the geometry
// if both are found, instead of just ignoring the y - right now
// the y could just not exist. And then if either do not exist
// an exception should be thrown.
// Also, currently the name of the geometry is hard coded -
// do we want it to be user configurable? ch
if (colName.equals(XCoordColumnName)) {
// do type checking here, during config, not during reading.
if (Number.class.isAssignableFrom(type)) {
return new AttributeTypeBuilder().binding(Point.class).buildDescriptor(geomName);
} else {
String excMesg = "Specified X column of " + colName + " of type: " + type
+ ", can not be used as x point";
throw new DataSourceException(excMesg);
}
} else if (colName.equals(YCoordColumnName)) {
if (Number.class.isAssignableFrom(type)) {
return null;
} else {
String excMesg = "Specified X column of " + colName + " of type: " + type
+ ", can not be used as x point";
throw new DataSourceException(excMesg);
}
} else {
return super.buildAttributeType(rs);
}
} catch (SQLException e) {
throw new IOException("SQL exception occurred: " + e.getMessage());
}
}
// public SQLBuilder getSqlBuilder(String typeName) throws IOException {
//
// SQLEncoderLocationsXY encoder = new
// SQLEncoderLocationsXY(XCoordColumnName,YCoordColumnName);
// encoder.setFIDMapper(getFIDMapper(typeName));
// return new LocationsXYSQLBuilder(encoder, XCoordColumnName,
// YCoordColumnName);
// }
public SQLBuilder getSqlBuilder(String typeName) throws IOException {
String xCol = XCoordColumnName;
String yCol = YCoordColumnName;
BypassSqlFeatureTypeHandler ftHanlder = (BypassSqlFeatureTypeHandler) super.typeHandler;
if (ftHanlder.isView(typeName)) {
String sqlQeury = ftHanlder.getQuery(typeName);
Map aliases = BypassSqlSQLBuilder.parseAliases(sqlQeury);
xCol = (String) aliases.get(xCol);
yCol = (String) aliases.get(yCol);
}
SQLEncoderLocationsXY encoder = new SQLEncoderLocationsXY(xCol, yCol);
encoder.setFeatureType(ftHanlder.getSchema(typeName));
encoder.setFIDMapper(getFIDMapper(typeName));
return new LocationsXYSQLBuilder(encoder, geomName, XCoordColumnName, YCoordColumnName,
ftHanlder);
}
/**
* @see org.geotools.data.jdbc.JDBCDataStore#getGeometryAttributeIO(org.geotools.feature.AttributeType)
*/
protected AttributeIO getGeometryAttributeIO(AttributeDescriptor type, QueryData queryData) {
return new PointXYAttributeIO();
}
protected JDBCFeatureWriter createFeatureWriter(FeatureReader <SimpleFeatureType, SimpleFeature> reader, QueryData queryData)
throws IOException {
LOGGER.fine("returning jdbc feature writer");
return new GeometrylessFeatureWriter(reader, queryData);
}
}