/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2004-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.referencing.factory.epsg; // J2SE dependencies import java.sql.Connection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.Map; import javax.sql.DataSource; // Geotools dependencies import org.geotools.factory.Hints; import org.opengis.referencing.FactoryException; /** * An EPSG factory for the database generated by SQL scripts rather than the MS-Access one. * This class overrides {@link #adaptSQL} in order to translate SQL statements from * MS-Access syntax to ANSI syntax. By default, the translated SQL statements use the * table and field names in the Data Description Language (DDL) scripts provided by * EPSG to create the schema for the database. Subclasses can changes this default * behavior by modifying the {@link #map}. * <p> * <strong>References:</strong><ul> * <li>EPSG geodecy parameters database readme at * <A HREF="http://www.ihsenergy.com/epsg/geodetic2.html">www.epsg.org</A> * </li> * </ul> * * @since 2.4 * * @source $URL$ * @version $Id$ * @author Rueben Schulz * @author Martin Desruisseaux * @author Didier Richard * @author John Grange */ public class AnsiDialectEpsgFactory extends AbstractEpsgFactory { /** * The default map using ANSI names. */ private static final String[] ANSI = { "[Alias]", "epsg_alias", "[Area]", "epsg_area", "[Coordinate Axis]", "epsg_coordinateaxis", "[Coordinate Axis Name]", "epsg_coordinateaxisname", "[Coordinate_Operation]", "epsg_coordoperation", "[Coordinate_Operation Method]", "epsg_coordoperationmethod", "[Coordinate_Operation Parameter]", "epsg_coordoperationparam", "[Coordinate_Operation Parameter Usage]", "epsg_coordoperationparamusage", "[Coordinate_Operation Parameter Value]", "epsg_coordoperationparamvalue", "[Coordinate_Operation Path]", "epsg_coordoperationpath", "[Coordinate Reference System]", "epsg_coordinatereferencesystem", "[Coordinate System]", "epsg_coordinatesystem", "[Datum]", "epsg_datum", "[Ellipsoid]", "epsg_ellipsoid", "[Naming System]", "epsg_namingsystem", "[Prime Meridian]", "epsg_primemeridian", "[Supersession]", "epsg_supersession", "[Unit of Measure]", "epsg_unitofmeasure", "[Version History]", "epsg_versionhistory", "[ORDER]", "coord_axis_order" // a field in epsg_coordinateaxis }; /** * Maps the MS-Access names to ANSI names. Keys are MS-Access names including bracket. * Values are ANSI names. Keys and values are case-sensitive. The default content of * this map is: * * <pre><table> * <tr><th align="center">MS-Access name</th> <th align="center">ANSI name</th></tr> * <tr><td>[Alias]</td> <td>epsg_alias</td></tr> * <tr><td>[Area]</td> <td>epsg_area</td></tr> * <tr><td>[Coordinate Axis]</td> <td>epsg_coordinateaxis</td></tr> * <tr><td>[Coordinate Axis Name]</td> <td>epsg_coordinateaxisname</td></tr> * <tr><td>[Coordinate_Operation]</td> <td>epsg_coordoperation</td></tr> * <tr><td>[Coordinate_Operation Method]</td> <td>epsg_coordoperationmethod</td></tr> * <tr><td>[Coordinate_Operation Parameter]</td> <td>epsg_coordoperationparam</td></tr> * <tr><td>[Coordinate_Operation Parameter Usage]</td> <td>epsg_coordoperationparamusage</td></tr> * <tr><td>[Coordinate_Operation Parameter Value]</td> <td>epsg_coordoperationparamvalue</td></tr> * <tr><td>[Coordinate_Operation Path]</td> <td>epsg_coordoperationpath</td></tr> * <tr><td>[Coordinate Reference System]</td> <td>epsg_coordinatereferencesystem</td></tr> * <tr><td>[Coordinate System]</td> <td>epsg_coordinatesystem</td></tr> * <tr><td>[Datum]</td> <td>epsg_datum</td></tr> * <tr><td>[Naming System]</td> <td>epsg_namingsystem</td></tr> * <tr><td>[Ellipsoid]</td> <td>epsg_ellipsoid</td></tr> * <tr><td>[Prime Meridian]</td> <td>epsg_primemeridian</td></tr> * <tr><td>[Supersession]</td> <td>epsg_supersession</td></tr> * <tr><td>[Unit of Measure]</td> <td>epsg_unitofmeasure</td></tr> * <tr><td>[CA.ORDER]</td> <td>coord_axis_order</td></tr> * </table></pre> * * Subclasses can modify this map in their constructor in order to provide a different * mapping. */ protected final Map map = new LinkedHashMap(); /** * The prefix before any table name. May be replaced by a schema if {@link #setSchema} * is invoked. */ private String prefix = "epsg_"; /** * Constructs an authority factory, the hints should describe the data source it use. * * @param userHints The underlying factories used for objects creation. * @throws FactoryException */ public AnsiDialectEpsgFactory(final Hints userHints) throws FactoryException { super(userHints ); for (int i=0; i<ANSI.length; i++) { map.put(ANSI[i], ANSI[++i]); } } /** * Constructs an authority factory using the specified connection. * * @param userHints The underlying factories used for objects creation. * @param connection The connection to the underlying EPSG database. * @throws FactoryException */ public AnsiDialectEpsgFactory( Hints hints, Connection connection ) { super(hints, connection ); for (int i=0; i<ANSI.length; i++) { map.put(ANSI[i], ANSI[++i]); } } /** * Constructs an authority factory using the specified connection. * * @param userHints The underlying factories used for objects creation. * @param dataSource Used to create a connection to the underlying EPSG database * @throws FactoryException */ public AnsiDialectEpsgFactory( Hints hints, DataSource dataSource ) { super(hints, dataSource); for (int i=0; i<ANSI.length; i++) { map.put(ANSI[i], ANSI[++i]); } } /** * Replaces the {@code "epsg_"} prefix by the specified schema name. If the removal * of the {@code "epsg_"} prefix is not wanted, append it to the schema name * (e.g. {@code "myschema.epsg_"}). This method should be invoked at construction * time only. * * @param schema The database schema in which the epsg tables are stored. */ protected void setSchema(String schema) { schema = schema.trim(); final int length = schema.length(); if (length == 0) { throw new IllegalArgumentException(schema); } final char separator = schema.charAt(length-1); if (separator!='.' && separator!='_') { schema += '.'; } else if (length == 1) { throw new IllegalArgumentException(schema); } for (final Iterator it=map.entrySet().iterator(); it.hasNext();) { final Map.Entry entry = (Map.Entry) it.next(); final String tableName = (String) entry.getValue(); /** * Update the map, prepending the schema name to the table name * so long as the value is a table name and not a field. This * algorithm assumes that all old table names start with "epsg_". */ if (tableName.startsWith(prefix)) { entry.setValue(schema + tableName.substring(prefix.length())); } } prefix = schema; } /** * Modifies the given SQL string to be suitable for non MS-Access databases. * This replaces table and field names in the SQL with the new names * in the SQL DDL scripts provided with EPSG database. * * @param statement The statement in MS-Access syntax. * @return The SQL statement in ANSI syntax. */ protected String adaptSQL(final String statement) { final StringBuilder modified = new StringBuilder(statement); for (final Iterator it=map.entrySet().iterator(); it.hasNext();) { final Map.Entry entry = (Map.Entry) it.next(); final String oldName = (String) entry.getKey(); final String newName = (String) entry.getValue(); /* * Replaces all occurences of 'oldName' by 'newName'. */ int start = 0; while ((start=modified.indexOf(oldName, start)) >= 0) { modified.replace(start, start+oldName.length(), newName); start += newName.length(); } } return modified.toString(); } }