/* ***********************************************************************
* This layer is for the reading and display of any spatial data retrieved
* from a MySQL Database (Version 4.1). At this time MySQL 4.1 is available
* only as alfa release, and represents the first version with support for
* the Datatype Geometry. Therefore be careful expecting to much.
* Usefull information can be found in the chapter 9 of the MySQL Reference
* (Spatial Extensions in MySQL)
* http://www.mysql.com/documentation/mysql/bychapter/index.html#GIS_spatial_extensions_in_MySQL
* partially this layer is inspired by Ian Batley's OracleSpatialLayer which
* can be found on the on the Open Map website.Thanks Ian.
* This program is distributed freely and 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.
*
* Copyright 2003 by the Author
*
* Author name: Uwe Baier uwe.baier@gmx.net
* Version 1.0
* ***********************************************************************
*/
package com.bbn.openmap.layer.mysql;
/* Java Core */
import java.awt.geom.Point2D;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import java.util.Vector;
import javax.swing.ImageIcon;
import com.bbn.openmap.layer.OMGraphicHandlerLayer;
import com.bbn.openmap.omGraphics.DrawingAttributes;
import com.bbn.openmap.omGraphics.OMGraphic;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.omGraphics.OMPoly;
import com.bbn.openmap.omGraphics.OMRaster;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.util.Debug;
import com.bbn.openmap.util.PropUtils;
/**
* This layer is for the reading and display of any spatial data retrieved from
* a MySQL Database (Version 4.1). At this time MySQL 4.1 is available only as
* alfa release, and represents the first version with support for the Datatype
* Geometry. Therefore, be careful in expecting too much. Usefull information
* can be found in the chapter 9 of the MySQL Reference (Spatial Extensions in
* MySQL) http://www.mysql.com/documentation/mysql/bychapter/index.html#
* GIS_spatial_extensions_in_MySQL partially this layer is inspired by Ian
* Batley's OracleSpatialLayer which can be found on the on the OpenMap website.
* Thanks Ian.
* <p>
*
* MysqlGeometryLayer uses at this stage a set of Classes which wraps the
* Geometries retrieved from the database. They are thought to be a provisorium
* until a nice MySQL Geometry API is available. Coordinate values are stored as
* values of double precision in arrays as a sequence of Latitude/Longitude
* pairs. This differs from the database where values are stored as X/Y or
* Easting/Northing pairs.
*
* <p>
* Properties to be set:
*
* <pre>
*
* mygeo.prettyName=<Your Layer Name>
* mygeo.dbUrl=<Driver Class> eg. "jdbc:mysql://localhost/openmap?user=me&password=secret"
* mygeo.dbClass=<Driver Class> eg. "com.mysql.jdbc.Driver"
* mygeo.geomTable=<Database Tablename>
* mygeo.geomColumn=<Column name which contains the geometry>
* mygeo.pointSymbol=<Filename and path for image to use for point objects>Default is null
*
* # Optional Properties - use as required
* # NOTE: There are default for each of these
* mygeo.lineColor=<Color for lines> Default is red
* mygeo.lineWidth=<Pixel width of lines> Default is 0
* mygeo.fillColor=<Color of fill> Default is red
*
* </pre>
*
* Copyright 2003 by the Author <br>
* <p>
*
* @author Uwe Baier uwe.baier@gmx.net
* @version 1.0
*/
public class MysqlGeometryLayer extends OMGraphicHandlerLayer {
/**
* The connection String to use for the jdbc query, e.g.
* "jdbc:mysql://localhost/openmap?user=me&password=secret"
*/
protected String dbUrl = null;
/**
* The Property to set for the query: <b>dbUrl </b>.
*/
public static final String dbUrlProperty = "dbUrl";
/**
* ; The driver to use.
*/
protected String dbClass = null;
/**
* The property to use for specifying the driver: <b>dbClass </b>
*/
public static final String dbClassProperty = "dbClass";
/** Table name which contains the geometry to be used. */
protected String geomTable = null;
/**
* Property to specify geomTable in the Database: <b>geomTable </b>.
*/
public static final String geomTableProperty = "geomTable";
/** Column name which contains the geometry to be used. */
protected String geomColumn = null;
/**
* Property to specify geomColumn in the Database: <b>geomColumn </b>
*/
public static final String geomColumnProperty = "geomColumn";
/** The point Symbol set by the Properties */
protected String pointSymbol = "";
/**
* Property to specify GIF or image file(symbol) to use for Points:
* <b>pointSymbol </b>.
*/
public static final String pointSymbolProperty = "pointSymbol";
protected DrawingAttributes drawingAttributes = DrawingAttributes.getDefaultClone();
/**
* The properties and prefix are managed and decoded here.
*
* @param prefix string prefix used in the properties file for this layer.
* @param properties the properties set in the properties file.
*/
public void setProperties(String prefix, Properties properties) {
super.setProperties(prefix, properties);
prefix = PropUtils.getScopedPropertyPrefix(prefix);
dbClass = properties.getProperty(prefix + dbClassProperty);
dbUrl = properties.getProperty(prefix + dbUrlProperty);
geomTable = properties.getProperty(prefix + geomTableProperty);
geomColumn = properties.getProperty(prefix + geomColumnProperty);
pointSymbol = properties.getProperty(prefix + pointSymbolProperty);
if (Debug.debugging("mysql")) {
Debug.output("MysqlGeometryLayer (" + getName() + ") properties:");
Debug.output(" " + dbClass);
Debug.output(" " + dbUrl);
Debug.output(" " + geomTable);
Debug.output(" " + geomColumn);
}
drawingAttributes.setProperties(prefix, properties);
}
public synchronized OMGraphicList prepare() {
Projection proj = getProjection();
if (proj == null) {
Debug.output("MysqlGeometryLayer.prepare: null projection!");
return null;
}
OMGraphicList graphics = new OMGraphicList();
try {
Class.forName(dbClass).newInstance();
Connection conn = DriverManager.getConnection(dbUrl);
Statement stmt = conn.createStatement();
Point2D ul = getProjection().getUpperLeft();
Point2D lr = getProjection().getLowerRight();
String q = "SELECT ID, AsText(" + geomColumn + ") FROM " + geomTable
+ " WHERE MBRIntersects(GEO, GeomFromText('Polygon(( " + ul.getX() + " "
+ ul.getY() + ", " + ul.getX() + " " + lr.getY() + ", " + lr.getX() + " "
+ lr.getY() + ", " + lr.getX() + " " + ul.getY() + ", " + ul.getX() + " "
+ ul.getY() + "))'))";
if (Debug.debugging("mysql")) {
Debug.output("MysqlGeometryLayer query: " + q);
}
ResultSet rs = stmt.executeQuery(q);
graphics.clear();
while (rs.next()) {
String result = rs.getString(2);
if (Debug.debugging("mysql")) {
Debug.output("MysqlGeometryLayer result: " + result);
}
MysqlGeometry mg = MysqlWKTGeometryFactory.createGeometry(result);
OMGraphic omg = createGraphic(mg);
omg.generate(proj);
graphics.add(omg);
}
rs.close();
conn.close();
} catch (SQLException sqlE) {
sqlE.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
return graphics;
}
/**
* Method createPoint. Renders a Point.
*
* @param myPoint
*/
protected OMGraphic createPoint(MysqlPoint myPoint) {
ImageIcon actualPointSymbol = new ImageIcon(pointSymbol);
OMRaster ompoint = new OMRaster((float) myPoint.getNorthings(), (float) myPoint.getEastings(), actualPointSymbol);
drawingAttributes.setTo(ompoint);
return ompoint;
}
/**
* Method createLine. Renders a Linestring Geometry. ToDo: Holes
*
* @param myLine - Database object which will be rendered
*/
protected OMGraphic createLine(MysqlLine myLine) {
OMPoly ompoly = new OMPoly(myLine.getCoordinateArray(), OMGraphic.DECIMAL_DEGREES, OMGraphic.LINETYPE_STRAIGHT);
drawingAttributes.setTo(ompoly);
return ompoly;
}
/**
* Method createPolygon. Renders a polygon geometry
*
* @param myPoly - Database object which will be rendered
*/
protected OMGraphic createPolygon(MysqlPolygon myPoly) {
Vector v = myPoly.getRings();
int size = v.size();
OMGraphic ret = null;
OMPoly ompoly = null;
OMGraphicList subList = null;
if (size > 1) {
subList = new OMGraphicList();
ret = subList;
}
for (int i = 0; i < size; i++) {
ompoly = new OMPoly((double[]) v.elementAt(i), OMGraphic.DECIMAL_DEGREES, OMGraphic.LINETYPE_STRAIGHT);
drawingAttributes.setTo(ompoly);
if (subList != null) {
subList.add(ompoly);
} else {
ret = ompoly;
}
}
return ret;
}
/**
* Method chooses what type of geometry to render.
*
* @param mg Database object which will be rendered
*/
protected OMGraphic createGraphic(MysqlGeometry mg) {
OMGraphic ret = null;
if (mg != null) {
String type = mg.getType();
if (type.equals(MysqlGeometry.POINTTYPE)) {
ret = createPoint((MysqlPoint) mg);
} else if (type.equals(MysqlGeometry.LINESTRINGTYPE)) {
ret = createLine((MysqlLine) mg);
} else if (type.equals(MysqlGeometry.POLYGONTTYPE)) {
ret = createPolygon((MysqlPolygon) mg);
} else if (type.equals(MysqlGeometry.MULTIPOINTTYPE)
|| type.equals(MysqlGeometry.MULTILINESTRINGTYPE)
|| type.equals(MysqlGeometry.MULTIPOLYGONTYPE)
|| type.equals(MysqlGeometry.GEOMETRYCOLLECTIONTYPE)) {
MysqlMulti multi = (MysqlMulti) mg;
OMGraphicList subList = new OMGraphicList();
for (int i = 0; i < multi.countElements(); i++) {
OMGraphic subRet = null;
if (type.equals(MysqlGeometry.MULTIPOINTTYPE)) {
subRet = createPoint((MysqlPoint) multi.getElementByIndex(i));
} else if (type.equals(MysqlGeometry.MULTILINESTRINGTYPE)) {
subRet = createLine((MysqlLine) multi.getElementByIndex(i));
} else if (type.equals(MysqlGeometry.MULTIPOLYGONTYPE)) {
subRet = createPolygon((MysqlPolygon) multi.getElementByIndex(i));
} else if (type.equals(MysqlGeometry.GEOMETRYCOLLECTIONTYPE)) {
subRet = createGraphic((MysqlGeometry) multi.getElementByIndex(i));
}
if (subRet != null) {
subList.add(subRet);
}
}
ret = subList;
} else {
// Other types of geometry
if (Debug.debugging("mysql")) {
Debug.output("MysqlGeometryLayer.createGeometry: Geometry type not supported");
}
}
}
return ret;
}
}