001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2004-2006, 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: package org.geotools.referencing.factory.epsg;
017:
018: // J2SE dependencies
019: import java.sql.Connection;
020: import java.util.Iterator;
021: import java.util.LinkedHashMap;
022: import java.util.Map;
023:
024: import javax.sql.DataSource;
025:
026: // Geotools dependencies
027: import org.geotools.factory.Hints;
028:
029: /**
030: * An EPSG factory for the database generated by SQL scripts rather than the MS-Access one.
031: * This class overrides {@link #adaptSQL} in order to translate SQL statements from
032: * MS-Access syntax to ANSI syntax. By default, the translated SQL statements use the
033: * table and field names in the Data Description Language (DDL) scripts provided by
034: * EPSG to create the schema for the database. Subclasses can changes this default
035: * behavior by modifying the {@link #map}.
036: * <p>
037: * <strong>References:</strong><ul>
038: * <li>EPSG geodecy parameters database readme at
039: * <A HREF="http://www.ihsenergy.com/epsg/geodetic2.html">www.epsg.org</A>
040: * </li>
041: * </ul>
042: *
043: * @since 2.4
044: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/referencing/src/main/java/org/geotools/referencing/factory/epsg/AnsiDialectEpsgFactory.java $
045: * @version $Id: AnsiDialectEpsgFactory.java 26328 2007-07-24 16:57:19Z desruisseaux $
046: * @author Rueben Schulz
047: * @author Martin Desruisseaux
048: * @author Didier Richard
049: * @author John Grange
050: */
051: public class AnsiDialectEpsgFactory extends FactoryUsingSQL {
052: /**
053: * The default map using ANSI names.
054: */
055: private static final String[] ANSI = { "[Alias]", "epsg_alias",
056: "[Area]", "epsg_area", "[Coordinate Axis]",
057: "epsg_coordinateaxis", "[Coordinate Axis Name]",
058: "epsg_coordinateaxisname", "[Coordinate_Operation]",
059: "epsg_coordoperation", "[Coordinate_Operation Method]",
060: "epsg_coordoperationmethod",
061: "[Coordinate_Operation Parameter]",
062: "epsg_coordoperationparam",
063: "[Coordinate_Operation Parameter Usage]",
064: "epsg_coordoperationparamusage",
065: "[Coordinate_Operation Parameter Value]",
066: "epsg_coordoperationparamvalue",
067: "[Coordinate_Operation Path]", "epsg_coordoperationpath",
068: "[Coordinate Reference System]",
069: "epsg_coordinatereferencesystem", "[Coordinate System]",
070: "epsg_coordinatesystem", "[Datum]", "epsg_datum",
071: "[Ellipsoid]", "epsg_ellipsoid", "[Naming System]",
072: "epsg_namingsystem", "[Prime Meridian]",
073: "epsg_primemeridian", "[Supersession]",
074: "epsg_supersession", "[Unit of Measure]",
075: "epsg_unitofmeasure", "[Version History]",
076: "epsg_versionhistory", "[ORDER]", "coord_axis_order" // a field in epsg_coordinateaxis
077: };
078:
079: /**
080: * Maps the MS-Access names to ANSI names. Keys are MS-Access names including bracket.
081: * Values are ANSI names. Keys and values are case-sensitive. The default content of
082: * this map is:
083: *
084: * <pre><table>
085: * <tr><th align="center">MS-Access name</th> <th align="center">ANSI name</th></tr>
086: * <tr><td>[Alias]</td> <td>epsg_alias</td></tr>
087: * <tr><td>[Area]</td> <td>epsg_area</td></tr>
088: * <tr><td>[Coordinate Axis]</td> <td>epsg_coordinateaxis</td></tr>
089: * <tr><td>[Coordinate Axis Name]</td> <td>epsg_coordinateaxisname</td></tr>
090: * <tr><td>[Coordinate_Operation]</td> <td>epsg_coordoperation</td></tr>
091: * <tr><td>[Coordinate_Operation Method]</td> <td>epsg_coordoperationmethod</td></tr>
092: * <tr><td>[Coordinate_Operation Parameter]</td> <td>epsg_coordoperationparam</td></tr>
093: * <tr><td>[Coordinate_Operation Parameter Usage]</td> <td>epsg_coordoperationparamusage</td></tr>
094: * <tr><td>[Coordinate_Operation Parameter Value]</td> <td>epsg_coordoperationparamvalue</td></tr>
095: * <tr><td>[Coordinate_Operation Path]</td> <td>epsg_coordoperationpath</td></tr>
096: * <tr><td>[Coordinate Reference System]</td> <td>epsg_coordinatereferencesystem</td></tr>
097: * <tr><td>[Coordinate System]</td> <td>epsg_coordinatesystem</td></tr>
098: * <tr><td>[Datum]</td> <td>epsg_datum</td></tr>
099: * <tr><td>[Naming System]</td> <td>epsg_namingsystem</td></tr>
100: * <tr><td>[Ellipsoid]</td> <td>epsg_ellipsoid</td></tr>
101: * <tr><td>[Prime Meridian]</td> <td>epsg_primemeridian</td></tr>
102: * <tr><td>[Supersession]</td> <td>epsg_supersession</td></tr>
103: * <tr><td>[Unit of Measure]</td> <td>epsg_unitofmeasure</td></tr>
104: * <tr><td>[CA.ORDER]</td> <td>coord_axis_order</td></tr>
105: * </table></pre>
106: *
107: * Subclasses can modify this map in their constructor in order to provide a different
108: * mapping.
109: */
110: protected final Map map = new LinkedHashMap();
111:
112: /**
113: * The prefix before any table name. May be replaced by a schema if {@link #setSchema}
114: * is invoked.
115: */
116: private String prefix = "epsg_";
117:
118: /**
119: * Constructs an authority factory using the specified connection.
120: *
121: * @param userHints The underlying factories used for objects creation.
122: * @param connection The connection to the underlying EPSG database.
123: */
124: public AnsiDialectEpsgFactory(final Hints userHints,
125: final Connection connection) {
126: super (userHints, connection);
127: for (int i = 0; i < ANSI.length; i++) {
128: map.put(ANSI[i], ANSI[++i]);
129: }
130: }
131:
132: /**
133: * Replaces the {@code "epsg_"} prefix by the specified schema name. If the removal
134: * of the {@code "epsg_"} prefix is not wanted, append it to the schema name
135: * (e.g. {@code "myschema.epsg_"}). This method should be invoked at construction
136: * time only.
137: *
138: * @param schema The database schema in which the epsg tables are stored.
139: */
140: protected void setSchema(String schema) {
141: schema = schema.trim();
142: final int length = schema.length();
143: if (length == 0) {
144: throw new IllegalArgumentException(schema);
145: }
146: final char separator = schema.charAt(length - 1);
147: if (separator != '.' && separator != '_') {
148: schema += '.';
149: } else if (length == 1) {
150: throw new IllegalArgumentException(schema);
151: }
152: for (final Iterator it = map.entrySet().iterator(); it
153: .hasNext();) {
154: final Map.Entry entry = (Map.Entry) it.next();
155: final String tableName = (String) entry.getValue();
156: /**
157: * Update the map, prepending the schema name to the table name
158: * so long as the value is a table name and not a field. This
159: * algorithm assumes that all old table names start with "epsg_".
160: */
161: if (tableName.startsWith(prefix)) {
162: entry.setValue(schema
163: + tableName.substring(prefix.length()));
164: }
165: }
166: prefix = schema;
167: }
168:
169: /**
170: * Modifies the given SQL string to be suitable for non MS-Access databases.
171: * This replaces table and field names in the SQL with the new names
172: * in the SQL DDL scripts provided with EPSG database.
173: *
174: * @param statement The statement in MS-Access syntax.
175: * @return The SQL statement in ANSI syntax.
176: */
177: protected String adaptSQL(final String statement) {
178: final StringBuffer modified = new StringBuffer(statement);
179: for (final Iterator it = map.entrySet().iterator(); it
180: .hasNext();) {
181: final Map.Entry entry = (Map.Entry) it.next();
182: final String oldName = (String) entry.getKey();
183: final String newName = (String) entry.getValue();
184: /*
185: * Replaces all occurences of 'oldName' by 'newName'.
186: */
187: int start = 0;
188: while ((start = modified.indexOf(oldName, start)) >= 0) {
189: modified.replace(start, start + oldName.length(),
190: newName);
191: start += newName.length();
192: }
193: }
194: return modified.toString();
195: }
196: }
|