sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1728217 - in /sis/branches/JDK8/core: sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/
Date Tue, 02 Feb 2016 21:26:17 GMT
Author: desruisseaux
Date: Tue Feb  2 21:26:16 2016
New Revision: 1728217

URL: http://svn.apache.org/viewvc?rev=1728217&view=rev
Log:
More accurate specification of catalog and schema that contain the EPSG tables.

Modified:
    sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java

Modified: sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java?rev=1728217&r1=1728216&r2=1728217&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/ScriptRunner.java
[UTF-8] Tue Feb  2 21:26:16 2016
@@ -139,7 +139,12 @@ public class ScriptRunner implements Aut
     protected final boolean isEnumTypeSupported;
 
     /**
-     * {@code true} if the database supports schema.
+     * {@code true} if the database supports catalogs.
+     */
+    protected final boolean isCatalogSupported;
+
+    /**
+     * {@code true} if the database supports schemas.
      */
     protected final boolean isSchemaSupported;
 
@@ -231,11 +236,13 @@ public class ScriptRunner implements Aut
         ArgumentChecks.ensureNonNull("encoding", encoding);
         ArgumentChecks.ensurePositive("maxRowsPerInsert", maxRowsPerInsert);
         final DatabaseMetaData metadata = connection.getMetaData();
-        this.encoding          = encoding;
-        this.dialect           = Dialect.guess(metadata);
-        this.identifierQuote   = metadata.getIdentifierQuoteString();
-        this.isSchemaSupported = metadata.supportsSchemasInTableDefinitions() &&
-                                 metadata.supportsSchemasInDataManipulation();
+        this.encoding           = encoding;
+        this.dialect            = Dialect.guess(metadata);
+        this.identifierQuote    = metadata.getIdentifierQuoteString();
+        this.isSchemaSupported  = metadata.supportsSchemasInTableDefinitions() &&
+                                  metadata.supportsSchemasInDataManipulation();
+        this.isCatalogSupported = metadata.supportsCatalogsInTableDefinitions() &&
+                                  metadata.supportsCatalogsInDataManipulation();
         switch (dialect) {
             default: {
                 isEnumTypeSupported      = false;

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java?rev=1728217&r1=1728216&r2=1728217&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
[UTF-8] Tue Feb  2 21:26:16 2016
@@ -128,7 +128,7 @@ import static org.apache.sis.internal.re
  *
  * <div class="section">Life cycle and caching</div>
  * {@code EPSGDataAccess} instances should be short-lived since they may hold a significant
amount of JDBC resources.
- * Those instances are created on the fly by {@link EPSGFactory} and closed after a relatively
short
+ * {@code EPSGDataAccess} instances are created on the fly by {@link EPSGFactory} and closed
after a relatively short
  * {@linkplain EPSGFactory#getTimeout timeout}.
  * In addition {@code EPSGFactory} caches the most recently created objects, which reduce
greatly
  * the amount of {@code EPSGDataAccess} instantiations (and consequently the amount of database
accesses)
@@ -297,21 +297,21 @@ public class EPSGDataAccess extends Geod
      * by the {@link EPSGFactory#newDataAccess(Connection, SQLTranslator)} method of a corresponding
custom
      * {@code EPSGFactory} subclass.</div>
      *
-     * @param parent      The {@code EPSGFactory} which is creating this Data Access Object
(DAO).
+     * @param owner       The {@code EPSGFactory} which is creating this Data Access Object
(DAO).
      * @param connection  The connection to the underlying EPSG database.
      * @param translator  The translator from the SQL statements using MS-Access dialect
      *                    to SQL statements using the dialect of the actual database.
      *
      * @see EPSGFactory#newDataAccess(Connection, SQLTranslator)
      */
-    protected EPSGDataAccess(final EPSGFactory parent, final Connection connection, final
SQLTranslator translator) {
+    protected EPSGDataAccess(final EPSGFactory owner, final Connection connection, final
SQLTranslator translator) {
         ArgumentChecks.ensureNonNull("connection", connection);
         ArgumentChecks.ensureNonNull("translator", translator);
-        this.owner     = parent;
+        this.owner      = owner;
         this.connection = connection;
         this.translator = translator;
-        this.namespace  = parent.nameFactory.createNameSpace(
-                          parent.nameFactory.createLocalName(null, Constants.IOGP), null);
+        this.namespace  = owner.nameFactory.createNameSpace(
+                          owner.nameFactory.createLocalName(null, Constants.IOGP), null);
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java?rev=1728217&r1=1728216&r2=1728217&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
[UTF-8] Tue Feb  2 21:26:16 2016
@@ -55,14 +55,19 @@ import java.nio.file.Path;
  * when first needed using the {@link DataSource} specified at construction time. The geodetic
objects are cached
  * for reuse and the idle connections are closed after a timeout.
  *
- * <div class="section">EPSG dataset creation</div>
- * This class tries to automatically detect in which database schema are located the EPSG
tables
- * (see {@link SQLTranslator} for information on the search process). If the tables are not
found,
+ * <p>If no data source has been specified to the constructor, then {@code EPSGFactory}
searches for a
+ * default data source in JNDI, or in the directory given by the {@code SIS_DATA} environment
variable,
+ * or in the directory given by the {@code "derby​.system​.home"} property, in that order.
+ * See the {@linkplain org.apache.sis.referencing.factory.sql package documentation} for
more information.</p>
+ *
+ * <div class="section">EPSG dataset installation</div>
+ * This class tries to automatically detect the schema that contains the EPSG tables
+ * (see {@link SQLTranslator} for examples of tables to look for). If the tables are not
found,
  * then the {@link #install(Connection)} method will be invoked for creating the EPSG schema.
  * The {@code install(…)} method can perform its work only if the definition files are
reachable
  * on the classpath, or if the directory containing the files have been specified.
  *
- * <div class="section">Note for subclasses</div>
+ * <div class="section">Data Access Object (DAO)</div>
  * If there is no cached object for a given code, then {@code EPSGFactory} creates an {@link
EPSGDataAccess} instance
  * for performing the actual creation work. Developers who need to customize the geodetic
object creation can override
  * the {@link #newDataAccess(Connection, SQLTranslator)} method in order to return their
own {@link EPSGDataAccess}
@@ -72,6 +77,9 @@ import java.nio.file.Path;
  * @since   0.7
  * @version 0.7
  * @module
+ *
+ * @see EPSGDataAccess
+ * @see SQLTranslator
  */
 public class EPSGFactory extends ConcurrentAuthorityFactory<EPSGDataAccess> implements
CRSAuthorityFactory,
         CSAuthorityFactory, DatumAuthorityFactory, CoordinateOperationAuthorityFactory, Localized
@@ -124,7 +132,22 @@ public class EPSGFactory extends Concurr
     protected final MathTransformFactory mtFactory;
 
     /**
-     * The database schema where the EPSG tables are located, or {@code null} if no schema.
+     * The name of the catalog that contains the EPSG tables, or {@code null} or an empty
string.
+     * <ul>
+     *   <li>The {@code ""} value retrieves the EPSG schema without a catalog.</li>
+     *   <li>The {@code null} value means that the catalog name should not be used
to narrow the search.</li>
+     * </ul>
+     */
+    private final String catalog;
+
+    /**
+     * The name of the schema that contains the EPSG tables, or {@code null} or an empty
string.
+     * <ul>
+     *   <li>The {@code ""} value retrieves the EPSG tables without a schema.
+     *       In such case, table names are prefixed by {@value SQLTranslator#TABLE_PREFIX}.</li>
+     *   <li>The {@code null} value means that the schema name should not be used to
narrow the search.
+     *       In such case, {@link SQLTranslator} will tries to automatically detect the schema.</li>
+     * </ul>
      */
     private final String schema;
 
@@ -170,31 +193,35 @@ public class EPSGFactory extends Concurr
      *  </tr><tr>
      *   <td>{@code datumFactory}</td>
      *   <td>{@link DatumAuthorityFactory}</td>
-     *   <td>The factory to use for creating {@link Datum} instances.</td>
+     *   <td>The factory to use for creating {@link org.opengis.referencing.datum.Datum}
instances.</td>
      *  </tr><tr>
      *   <td>{@code csFactory}</td>
      *   <td>{@link CSAuthorityFactory}</td>
-     *   <td>The factory to use for creating {@link CoordinateSystem} instances.</td>
+     *   <td>The factory to use for creating {@link org.opengis.referencing.cs.CoordinateSystem}
instances.</td>
      *  </tr><tr>
      *   <td>{@code crsFactory}</td>
      *   <td>{@link CRSAuthorityFactory}</td>
-     *   <td>The factory to use for creating {@link CoordinateReferenceSystem} instances.</td>
+     *   <td>The factory to use for creating {@link org.opengis.referencing.crs.CoordinateReferenceSystem}
instances.</td>
      *  </tr><tr>
      *   <td>{@code copFactory}</td>
      *   <td>{@link CoordinateOperationAuthorityFactory}</td>
-     *   <td>The factory to use for creating {@link CoordinateOperation} instances.</td>
+     *   <td>The factory to use for creating {@link org.opengis.referencing.operation.CoordinateOperation}
instances.</td>
      *  </tr><tr>
      *   <td>{@code mtFactory}</td>
      *   <td>{@link MathTransformFactory}</td>
-     *   <td>The factory to use for creating {@link MathTransform} instances.</td>
+     *   <td>The factory to use for creating {@link org.opengis.referencing.operation.MathTransform}
instances.</td>
+     *  </tr><tr>
+     *   <td>{@code catalog}</td>
+     *   <td>{@link String}</td>
+     *   <td>The database catalog that contains the EPSG schema (see {@linkplain #install
install}).</td>
      *  </tr><tr>
      *   <td>{@code schema}</td>
      *   <td>{@link String}</td>
-     *   <td>The database schema where the EPSG tables are located (see {@linkplain
#install install}).</td>
+     *   <td>The database schema that contains the EPSG tables (see {@linkplain #install
install}).</td>
      *  </tr><tr>
      *   <td>{@code scriptDirectory}</td>
      *   <td>{@link java.nio.file.Path}, {@link java.io.File} or {@link java.net.URL}</td>
-     *   <td>The directory where the EPSG definition files are located (see {@linkplain
#install install}).</td>
+     *   <td>The directory that contains the EPSG definition files (see {@linkplain
#install install}).</td>
      *  </tr><tr>
      *   <td>{@code locale}</td>
      *   <td>{@link Locale}</td>
@@ -202,6 +229,16 @@ public class EPSGFactory extends Concurr
      *  </tr>
      * </table>
      *
+     * <p>Default values</p>
+     * <ul>
+     *   <li>If no {@code dataSource} is specified, this constructor defaults to the
search algorithm described
+     *       in the {@linkplain org.apache.sis.referencing.factory.sql package documentation}.</li>
+     *   <li>If no {@code catalog} or {@code schema} is specified, {@link SQLTranslator}
will try to auto-detect
+     *       the schema that contains the EPSG tables.</li>
+     *   <li>If no {@code locale} is specified, this constructor defaults to the
+     *       {@linkplain Locale#getDefault(Locale.Category) display locale}.</li>
+     * </ul>
+     *
      * @param  properties The data source, authority factories and other configuration properties,
      *                    or {@code null} for the default values.
      * @throws ClassCastException if a property value is not of the expected class.
@@ -214,17 +251,14 @@ public class EPSGFactory extends Concurr
             properties = Collections.emptyMap();
         }
         DataSource ds   = (DataSource) properties.get("dataSource");
-        Locale locale   = ObjectConverters.convert(properties.get("locale"), Locale.class);
-        String schema   = ObjectConverters.convert(properties.get("schema"), String.class);
+        Locale locale   = ObjectConverters.convert(properties.get("locale"),  Locale.class);
+        schema          = ObjectConverters.convert(properties.get("schema"),  String.class);
+        catalog         = ObjectConverters.convert(properties.get("catalog"), String.class);
         scriptDirectory = ObjectConverters.convert(properties.get("scriptDirectory"), Path.class);
         if (locale == null) {
             locale = Locale.getDefault(Locale.Category.DISPLAY);
         }
-        if (schema == null && !properties.containsKey("schema")) {
-            schema = Constants.EPSG;
-        }
         this.locale = locale;
-        this.schema = schema;
         if (ds == null) try {
             ds = Initializer.getDataSource();
             if (ds == null) {
@@ -281,12 +315,22 @@ public class EPSGFactory extends Concurr
      * {@linkplain #EPSGFactory(Map) construction time}:</p>
      *
      * <ul class="verbose">
+     *   <li><b>{@code catalog}:</b><br>
+     *     a {@link String} giving the name of the database catalog where to create the EPSG
schema.
+     *     If non-null, that catalog shall exist prior this method call (this method does
not create any catalog).
+     *     If no catalog is specified or if the catalog is an empty string,
+     *     then the EPSG schema will be created without catalog.
+     *     If the database does not {@linkplain DatabaseMetaData#supportsCatalogsInTableDefinitions()
support
+     *     catalogs in table definitions} or in {@linkplain DatabaseMetaData#supportsCatalogsInDataManipulation()
+     *     data manipulation}, then this property is ignored.</li>
+     *
      *   <li><b>{@code schema}:</b><br>
-     *     a {@link String} giving the name of the database schema where to create the tables.
-     *     That schema shall not exist prior this method call as it will be created by this
{@code install(…)} method.
-     *     If no schema is specified or if the schema is null, then the tables will be created
without schema.
+     *     a {@link String} giving the name of the database schema where to create the EPSG
tables.
+     *     That schema shall <strong>not</strong> exist prior this method call;
+     *     the schema will be created by this {@code install(…)} method.
+     *     If no schema is specified or if the schema an empty string, then the tables will
be created without schema.
      *     If the database does not {@linkplain DatabaseMetaData#supportsSchemasInTableDefinitions()
support
-     *     schema in table definitions} or in {@linkplain DatabaseMetaData#supportsSchemasInDataManipulation()
+     *     schemas in table definitions} or in {@linkplain DatabaseMetaData#supportsSchemasInDataManipulation()
      *     data manipulation}, then this property is ignored.</li>
      *
      *   <li><b>{@code scriptDirectory}:</b><br>
@@ -367,11 +411,11 @@ public class EPSGFactory extends Concurr
                 synchronized (this) {
                     tr = translator;
                     if (tr == null) {
-                        tr = new SQLTranslator(connection.getMetaData());
+                        tr = new SQLTranslator(connection.getMetaData(), catalog, schema);
                         try {
-                            if (!tr.isSchemaFound()) {
+                            if (!tr.isTableFound()) {
                                 install(connection);
-                                tr.setSchemaFound(connection.getMetaData());   // Set only
on success.
+                                tr.setup(connection.getMetaData());   // Set only on success.
                             }
                         } finally {
                             translator = tr;        // Set only after installation in order
to block other threads.
@@ -379,7 +423,7 @@ public class EPSGFactory extends Concurr
                     }
                 }
             }
-            if (tr.isSchemaFound()) {
+            if (tr.isTableFound()) {
                 return newDataAccess(connection, tr);
             }
             connection.close();
@@ -391,7 +435,7 @@ public class EPSGFactory extends Concurr
             }
             throw new UnavailableFactoryException(e.getLocalizedMessage(), e);
         }
-        throw new UnavailableFactoryException(SQLTranslator.schemaNotFound(locale));
+        throw new UnavailableFactoryException(SQLTranslator.tableNotFound(locale));
     }
 
     /**

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java?rev=1728217&r1=1728216&r2=1728217&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/SQLTranslator.java
[UTF-8] Tue Feb  2 21:26:16 2016
@@ -18,7 +18,6 @@ package org.apache.sis.referencing.facto
 
 import java.util.Map;
 import java.util.HashMap;
-import java.util.Collections;
 import java.util.Locale;
 import java.sql.DatabaseMetaData;
 import java.sql.ResultSet;
@@ -56,7 +55,7 @@ import java.util.function.Function;
  *   <li>{@code SELECT * FROM "Coordinate Reference System"}</li>
  *   <li>{@code SELECT * FROM epsg_coordinatereferencesystem} (in the default schema)</li>
  *   <li>{@code SELECT * FROM epsg.coordinatereferencesystem} (in the {@code "epsg"}
schema)</li>
- *   <li>{@code SELECT * FROM "EPSG"."Coordinate Reference System"}</li>
+ *   <li>{@code SELECT * FROM epsg."Coordinate Reference System"}</li>
  * </ul></div>
  *
  * In addition to the MS-Access format, EPSG also provides the dataset as <cite>Data
Description Language</cite> (DDL)
@@ -87,8 +86,8 @@ import java.util.function.Function;
  *   <tr><td>Column</td> <td>{@code ORDER}</td>           
                     <td>{@code coord_axis_order}</td></tr>
  * </table>
  *
- * This class auto-detects the schema where the EPSG database seems to be located and whether
the table names
- * are the ones used by EPSG in the MS-Access version or the PostgreSQL, MySQL or Oracle
version of the database.
+ * By default this class auto-detects the schema that contains the EPSG tables and whether
the table names are
+ * the ones used by EPSG in the MS-Access version or the PostgreSQL, MySQL or Oracle version
of the database.
  * Consequently it is legal to use the MS-Access table names, which are more readable, in
a PostgreSQL database.
  *
  * <div class="section">Thread safety</div>
@@ -128,11 +127,32 @@ public class SQLTranslator implements Fu
     static final String TABLE_PREFIX = "epsg_";
 
     /**
-     * The name of the schema where the tables are located, or {@code null} if none.
-     * In the later case, table names are prefixed by {@value #TABLE_PREFIX}.
+     * The name of the catalog that contains the EPSG tables, or {@code null} or an empty
string.
+     * <ul>
+     *   <li>The {@code ""} value retrieves the EPSG schema without a catalog.</li>
+     *   <li>The {@code null} value means that the catalog name should not be used
to narrow the search.</li>
+     * </ul>
      *
      * <p><b>Consider this field as final.</b> This field is non-final
only for construction convenience,
      * or for updating after the {@link EPSGInstaller} class created the database.</p>
+     *
+     * @see #getCatalog()
+     */
+    private String catalog;
+
+    /**
+     * The name of the schema that contains the EPSG tables, or {@code null} or an empty
string.
+     * <ul>
+     *   <li>The {@code ""} value retrieves the EPSG tables without a schema.
+     *       In such case, table names are prefixed by {@value #TABLE_PREFIX}.</li>
+     *   <li>The {@code null} value means that the schema name should not be used to
narrow the search.
+     *       In such case, {@code SQLTranslator} will tries to automatically detect the schema.</li>
+     * </ul>
+     *
+     * <p><b>Consider this field as final.</b> This field is non-final
only for construction convenience,
+     * or for updating after the {@link EPSGInstaller} class created the database.</p>
+     *
+     * @see #getSchema()
      */
     private String schema;
 
@@ -162,106 +182,141 @@ public class SQLTranslator implements Fu
     private final String quote;
 
     /**
-     * {@code true} if the tables exist. If {@code false}, then {@link EPSGInstaller} needs
to be run.
+     * {@code true} if one of the {@link #SENTINEL} tables exist.
+     * If {@code false}, then {@link EPSGInstaller} needs to be run.
+     *
+     * @see #isTableFound()
      */
-    private boolean isSchemaFound;
+    private boolean isTableFound;
 
     /**
-     * Creates a new adapter for the database described by the given metadata.
-     * This constructor:
+     * Creates a new SQL translator for the database described by the given metadata.
+     * This constructor detects automatically the dialect: the characters to use for quoting
identifiers, and whether
+     * the table names are the ones used in the MS-Access database or in the Data Definition
Language (DDL) scripts.
      *
-     * <ul>
-     *   <li>gets the characters to use for quoting identifiers,</li>
-     *   <li>finds the schema where are located the EPSG tables,</li>
-     *   <li>detects if the table names are the ones used in MS-Access database or
in the DDL scripts.</li>
-     * </ul>
+     * <p>If the given catalog or schema name is non-null, then the {@linkplain DatabaseMetaData#getTables
+     * search for EPSG tables} will be restricted to the catalog or schema of that name.
+     * An empty string ({@code ""}) means to search for tables without catalog or schema.
+     * A {@code null} value means that the catalog or schema should not be used to narrow
the search.</p>
      *
-     * <div class="note"><b>API design note:</b>
-     * this constructor is for sub-classing only. Otherwise, instances of {@code SQLTranslator}
should not need to be
-     * created explicitely since instantiations are performed automatically by {@link EPSGFactory}
when first needed.</div>
-     *
-     * @param  md Information about the database.
+     * @param  md      Information about the database.
+     * @param  catalog The catalog where to look for EPSG schema, or {@code null} if any.
+     * @param  schema  The schema where to look for EPSG tables, or {@code null} if any.
      * @throws SQLException if an error occurred while querying the database metadata.
      */
-    protected SQLTranslator(final DatabaseMetaData md) throws SQLException {
+    public SQLTranslator(final DatabaseMetaData md, final String catalog, final String schema)
throws SQLException {
         ArgumentChecks.ensureNonNull("md", md);
-        quote = md.getIdentifierQuoteString();
-        findSchema(md);
-        /*
-         * Initialize the 'accessToAnsi' map. This map translates the table and column names
used in the SQL
-         * statements into the names used by the database. Two conventions are understood:
the names used in
-         * the MS-Access database or the names used in the SQL scripts. Both of them are
distributed by EPSG.
-         */
-        if (quoteTableNames) {
-            /*
-             * MS-Access database uses a column named "ORDER" in the "Coordinate Axis" table.
-             * This column has been renamed "coord_axis_order" in DLL scripts.
-             * We need to check which name our current database uses.
-             */
-            try (ResultSet result = md.getColumns(null, schema, "Coordinate Axis", "ORDER"))
{
-                if (result.next()) {
-                    accessToAnsi = Collections.emptyMap();
-                } else {
-                    accessToAnsi = Collections.singletonMap("ORDER", "coord_axis_order");
-                }
-            }
-        } else {
-            accessToAnsi = new HashMap<>(4);
-            accessToAnsi.put("ORDER",                "coord_axis_order");     // A column,
not a table.
-            accessToAnsi.put("Coordinate_Operation", "coordoperation");
-            accessToAnsi.put("Parameter",            "param");
-        }
-    };
+        quote = md.getIdentifierQuoteString().trim();
+        accessToAnsi = new HashMap<>(4);
+        this.catalog = catalog;
+        this.schema  = schema;
+        setup(md);
+    }
 
     /**
-     * Finds the schema where the EPSG tables seem to be located. If there is more than one
schema containing the
-     * tables, give precedence to the schema named "EPSG" if one is found. If there is no
schema named "EPSG",
-     * take an arbitrary schema. It may be null if the tables are not located in a schema.
+     * Sets the value of all non-final fields. This method performs two steps:
+     *
+     * <ol class="verbose">
+     *   <li>Finds the schema that seems to contain the EPSG tables. If there is more
than one schema containing the
+     *       tables, gives precedence to the schema named "EPSG" if one is found. If there
is no schema named "EPSG",
+     *       takes an arbitrary schema. It may be the empty string if the tables are not
contained in a schema.</li>
+     *
+     *   <li>Fills the {@link #accessToAnsi} map. That map translates the table and
column names used in the SQL
+     *       statements into the names used by the database. Two conventions are understood:
the names used in
+     *       the MS-Access database or the names used in the SQL scripts. Both of them are
distributed by EPSG.</li>
+     * </ol>
      */
-    private void findSchema(final DatabaseMetaData md) throws SQLException {
+    final void setup(final DatabaseMetaData md) throws SQLException {
         final boolean toUpperCase = md.storesUpperCaseIdentifiers();
         for (int i = SENTINEL.length; --i >= 0;) {
             String table = SENTINEL[i];
             if (toUpperCase && i != MIXED_CASE) {
                 table = table.toUpperCase(Locale.US);
             }
-            try (ResultSet result = md.getTables(null, null, table, null)) {
+            try (ResultSet result = md.getTables(catalog, schema, table, null)) {
                 if (result.next()) {
-                    isSchemaFound = true;
+                    isTableFound    = true;
                     quoteTableNames = (i == MIXED_CASE);
                     do {
-                        schema = result.getString("TABLE_SCHEM");
+                        catalog = result.getString("TABLE_CAT");
+                        schema  = result.getString("TABLE_SCHEM");
                     } while (!Constants.EPSG.equalsIgnoreCase(schema) && result.next());
+                    if (schema == null) schema = "";
                     break;
                 }
             }
         }
+        /*
+         * At this point the catalog and schema have been found or confirmed, or are still
null
+         * if we did not found them. Now fill the 'accessToAnsi' map.
+         */
+        boolean translateColumns = true;
+        accessToAnsi.clear();
+        if (quoteTableNames) {
+            /*
+             * MS-Access database uses a column named "ORDER" in the "Coordinate Axis" table.
+             * This column has been renamed "coord_axis_order" in DLL scripts.
+             * We need to check which name our current database uses.
+             */
+            try (ResultSet result = md.getColumns(catalog, schema, "Coordinate Axis", "ORDER"))
{
+                translateColumns = !result.next();
+            }
+        } else {
+            accessToAnsi.put("Coordinate_Operation", "coordoperation");
+            accessToAnsi.put("Parameter", "param");
+        }
+        if (translateColumns) {
+            accessToAnsi.put("ORDER", "coord_axis_order");
+        }
+    };
+
+    /**
+     * Returns the catalog that contains the EPSG schema. This is the catalog specified at
construction time
+     * if it was non-null, or the catalog discovered by the constructor otherwise.
+     * Note that this method may still return {@code null} if the EPSG tables were not found
or if the database
+     * does not {@linkplain DatabaseMetaData#supportsCatalogsInDataManipulation() supports
catalogs}.
+     *
+     * @return The catalog that contains the EPSG schema, or {@code null}.
+     */
+    public String getCatalog() {
+        return catalog;
     }
 
     /**
-     * Returns {@code true} if the constructor has found the EPSG schema.
+     * Returns the schema that contains the EPSG tables. This is the schema specified at
construction time
+     * if it was non-null, or the schema discovered by the constructor otherwise.
+     * Note that this method may still return {@code null} if the EPSG tables were not found
or if the database
+     * does not {@linkplain DatabaseMetaData#supportsSchemasInDataManipulation() supports
schemas}.
+     *
+     * @return The schema that contains the EPSG tables, or {@code null}.
      */
-    final boolean isSchemaFound() {
-        return isSchemaFound;
+    public String getSchema() {
+        return schema;
     }
 
     /**
-     * Declares that the EPSG schema should exists now.
-     * This method is invoked after {@link EPSGInstaller} execution.
+     * Returns whether the EPSG tables have been found.
+     * If {@code false}, then {@link EPSGInstaller} needs to be run.
      */
-    final void setSchemaFound(final DatabaseMetaData md) throws SQLException {
-        findSchema(md);
-        isSchemaFound = true;
+    final boolean isTableFound() {
+        return isTableFound;
     }
 
     /**
-     * Returns the error message for the exception to throw if the EPSG schema is not found
and we can not create it.
+     * Returns the error message for the exception to throw if the EPSG tables are not found
and we can not create them.
      */
-    static String schemaNotFound(final Locale locale) {
+    static String tableNotFound(final Locale locale) {
         return Errors.getResources(locale).getString(Errors.Keys.TableNotFound_1, SENTINEL[MIXED_CASE]);
     }
 
     /**
+     * If the given string is empty, returns {@code null} instead.
+     */
+    private static String nonEmpty(final String s) {
+        return (s != null && !s.isEmpty()) ? s : null;
+    }
+
+    /**
      * Adapts the given SQL statement from the original MS-Access dialect to the dialect
of the target database.
      * Table and column names may also be replaced.
      *
@@ -270,7 +325,9 @@ public class SQLTranslator implements Fu
      */
     @Override
     public String apply(final String sql) {
-        if (schema == null && accessToAnsi.isEmpty() && quote.trim().isEmpty())
{
+        final String catalog = nonEmpty(this.catalog);
+        final String schema  = nonEmpty(this.schema);
+        if (quote.isEmpty() && accessToAnsi.isEmpty() && schema == null &&
catalog == null) {
             return sql;
         }
         final StringBuilder ansi = new StringBuilder(sql.length() + 16);
@@ -295,6 +352,9 @@ public class SQLTranslator implements Fu
             if (CharSequences.isUpperCase(name)) {
                 ansi.append(accessToAnsi.getOrDefault(name, name));
             } else {
+                if (catalog != null) {
+                    ansi.append(quote).append(catalog).append(quote).append('.');
+                }
                 if (schema != null) {
                     ansi.append(quote).append(schema).append(quote).append('.');
                 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java?rev=1728217&r1=1728216&r2=1728217&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/package-info.java
[UTF-8] Tue Feb  2 21:26:16 2016
@@ -17,10 +17,12 @@
 
 /**
  * Factories for geodetic objects defined in a SQL database.
- * Every classes in this package require a connection to a database, which may be on Apache
Derby (a.k.a. JavaDB),
- * PostgreSQL or MS-Access. The connection is obtained by the first of the following data
sources which is found:
+ * The main class in this package is {@link org.apache.sis.referencing.factory.sql.EPSGFactory},
+ * which requires a {@link javax.sql.DataSource} providing connections to an EPSG database.
+ * By default Apache SIS used Apache Derby (a.k.a. JavaDB), but the database can also be
PostgreSQL or MS-Access.
+ * The connection is obtained by the first of the following data sources which is found:
  *
- * <ol>
+ * <ol class="verbose">
  *   <li>If a {@linkplain javax.naming.InitialContext JNDI context} exists,
  *       the {@link javax.sql.DataSource} registered under the {@code "java:comp/env/jdbc/SpatialMetadata"}
name.</li>
  *   <li>If the {@code SIS_DATA} {@linkplain System#getenv(String) environment variable}
is defined,
@@ -39,11 +41,17 @@
  * EPSG codes are numerical identifiers.
  * For example {@code "EPSG::4326"} is the EPSG identifier for the <cite>"WGS 84"</cite>
geographic CRS.
  * As an extension, the Apache SIS implementation accepts names as well as numeric identifiers.
- * For example {@code createProjectedCRS("NTF (Paris) / Lambert zone II")} and {@code createProjectedCRS("27572")}
- * both fetch the same object. However names may be ambiguous since the same name may be
used for more than one object.
+ * For example the two following method calls fetch the same object:
+ *
+ * <ul>
+ *   <li>{@code createProjectedCRS("NTF (Paris) / Lambert zone II")}</li>
+ *   <li>{@code createProjectedCRS("27572")}</li>
+ * </ul>
+ *
+ * However names may be ambiguous since the same name may be used for more than one object.
  * This is the case of <cite>"WGS 84"</cite> for example. If such an ambiguity
is found, an exception will be thrown.
  *
- * <p>When an error is discovered in a Coordinate Reference System definition, the
EPSG group does not apply the
+ * <p>When an error is discovered in a Coordinate Reference System (CRS) definition,
the EPSG group does not apply the
  * correction directly on the erroneous object (unless the correction is very minor).
  * Instead, the erroneous object is deprecated and a new one is created.
  * Apache SIS handles deprecated objects as below:</p>
@@ -51,8 +59,7 @@
  * <ul>
  *   <li>Deprecated objects are not listed in the collection returned by the
  *       {@link org.apache.sis.referencing.factory.sql.EPSGDataAccess#getAuthorityCodes getAuthorityCodes(…)}
method.</li>
- *   <li>However if the code of a deprecated object is given directly to {@code getAuthorityCodes(…).contains(…)},
- *       {@code getDescriptionText(…)} or any {@code createFoo(…)} method, it will be
recognized.</li>
+ *   <li>All method expecting an EPSG code in argument accept also the codes of deprecated
objects.</li>
  *   <li>If a deprecated object is created by a call to {@code createFoo(…)}, a warning
will be logged
  *       with a message proposing a replacement.</li>
  * </ul>



Mime
View raw message