sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1720139 - in /sis/branches/JDK8/core: sis-referencing/src/main/java/org/apache/sis/referencing/factory/ sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/ sis-utility/src/main/java/org/apache/sis/util/resources/
Date Tue, 15 Dec 2015 12:16:07 GMT
Author: desruisseaux
Date: Tue Dec 15 12:16:07 2015
New Revision: 1720139

URL: http://svn.apache.org/viewvc?rev=1720139&view=rev
Log:
Revisit the policy about AuthorityCodes disposal of JDBC resources.
Port more EPSGFactory methods.

Added:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/FactoryDataException.java
  (with props)
Modified:
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CloseableReference.java
    sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGFactory.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties

Added: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/FactoryDataException.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/FactoryDataException.java?rev=1720139&view=auto
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/FactoryDataException.java
(added)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/FactoryDataException.java
[UTF-8] Tue Dec 15 12:16:07 2015
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sis.referencing.factory;
+
+import org.opengis.util.FactoryException;
+
+
+/**
+ * Thrown when a factory contains invalid data.
+ *
+ * <div class="note"><b>Example:</b>
+ * an EPSG database record containing a null value in a column where nulls should not have
been allowed.</div>
+ *
+ * @author  Martin Desruisseaux (Geomatys)
+ * @since   0.7
+ * @version 0.7
+ * @module
+ */
+public class FactoryDataException extends FactoryException {
+    /**
+     * Serial number for inter-operability with different versions.
+     */
+    private static final long serialVersionUID = -6296443455120500463L;
+
+    /**
+     * Construct an exception with no detail message.
+     */
+    public FactoryDataException() {
+    }
+
+    /**
+     * Construct an exception with the specified detail message.
+     *
+     * @param  message The detail message. The detail message is saved
+     *         for later retrieval by the {@link #getMessage()} method.
+     */
+    public FactoryDataException(String message) {
+        super(message);
+    }
+
+    /**
+     * Construct an exception with the specified detail message and cause.
+     *
+     * @param  message The detail message. The detail message is saved
+     *         for later retrieval by the {@link #getMessage()} method.
+     * @param  cause The cause for this exception. The cause is saved
+     *         for later retrieval by the {@link #getCause()} method.
+     */
+    public FactoryDataException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/FactoryDataException.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/FactoryDataException.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain;charset=UTF-8

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java?rev=1720139&r1=1720138&r2=1720139&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/AuthorityCodes.java
[UTF-8] Tue Dec 15 12:16:07 2015
@@ -41,12 +41,20 @@ import org.apache.sis.util.logging.Loggi
  * <p>Serialization of this class stores a copy of all authority codes.
  * The serialization does not preserve any connection to the database.</p>
  *
+ * <p>This method does not implement {@link AutoCloseable} because the same instance
may be shared by many users,
+ * since {@link EPSGFactory#getAuthorityCodes(Class)} caches {@code AuthorityCodes} instances.
Furthermore we can
+ * not rely on the users closing {@code AuthorityCodes} themselves because this is not part
of the usual contract
+ * for Java collection classes (we could document that recommendation in method Javadoc,
but not every developers
+ * read Javadoc). Relying on the garbage collector for disposing this resource is far from
ideal, but alternatives
+ * are not very convincing either (load the same codes many time, have the risk that users
do not dispose resources,
+ * have the risk to return to user an already closed {@code AuthorityCodes} instance).</p>
+ *
  * @author  Martin Desruisseaux (IRD, Geomatys)
  * @since   0.7
  * @version 0.7
  * @module
  */
-final class AuthorityCodes extends AbstractMap<String,String> implements Serializable,
AutoCloseable {
+final class AuthorityCodes extends AbstractMap<String,String> implements Serializable
{
     /**
      * For compatibility with different versions.
      */
@@ -176,7 +184,8 @@ final class AuthorityCodes extends Abstr
 
     /**
      * Creates a weak reference to this map. That reference will also be in charge of closing
the JDBC statements
-     * if they were not closed.
+     * when the garbage collector determined that this {@code AuthorityCodes} instance is
no longer in use.
+     * See class Javadoc for more information.
      */
     final Reference<AuthorityCodes> createReference() {
         return new CloseableReference<>(this, factory, statements);
@@ -272,7 +281,9 @@ final class AuthorityCodes extends Abstr
     }
 
     /**
-     * Returns the description associated to the given authority code, or {@code null} if
none.
+     * Returns the object name associated to the given authority code, or {@code null} if
none.
+     * If there is no name for the {@linkplain #type} of object being queried, then this
method
+     * returns the code itself.
      *
      * @param  code  The code for which to get the description. May be a string or an integer.
      * @return The description for the given code, or {@code null} if none.
@@ -343,7 +354,7 @@ final class AuthorityCodes extends Abstr
 
             /**
              * Returns pseudo-value at the current iterator position. We do not query the
real value because it
-             * is costly and useless in the context where this method is used. This is because
the users should
+             * is costly and useless in the context where this method is used. It should
be okay since the users
              * never see the map directly, but only the key set.
              */
             @Override protected String getValue() {
@@ -367,25 +378,7 @@ final class AuthorityCodes extends Abstr
         return new LinkedHashMap<>(this);
     }
 
-    /**
-     * Closes the JDBC statement used by the {@code AuthorityCodes}. Note that if this method
is never invoked,
-     * {@link CloseableReference} will perform the same work after the garbage collector
detected that this map
-     * is not referenced anymore.
+    /*
+     * No close() or finalize() method - see class Javadoc for an explanation why.
      */
-    @Override
-    public void close() throws SQLException {
-        SQLException exception = null;
-        synchronized (factory) {
-            if (results != null) try {
-                results.close();
-            } catch (SQLException e) {
-                exception = e;
-            }
-            results = null;
-            exception = CloseableReference.close(statements, exception);
-        }
-        if (exception != null) {
-            throw exception;
-        }
-    }
 }

Modified: sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CloseableReference.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CloseableReference.java?rev=1720139&r1=1720138&r2=1720139&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CloseableReference.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/CloseableReference.java
[UTF-8] Tue Dec 15 12:16:07 2015
@@ -61,9 +61,21 @@ final class CloseableReference<T> extend
      */
     @Override
     public void dispose() {
-        SQLException exception;
+        SQLException exception = null;
         synchronized (factory) {
-            exception = close(statements, null);
+            for (int i=statements.length; --i >= 0;) {
+                final Statement s = statements[i];
+                statements[i] = null;
+                if (s != null) try {
+                    s.close();
+                } catch (SQLException e) {
+                    if (exception == null) {
+                        exception = e;
+                    } else {
+                        exception.addSuppressed(e);
+                    }
+                }
+            }
         }
         if (exception != null) {
             /*
@@ -75,25 +87,4 @@ final class CloseableReference<T> extend
             Logging.unexpectedException(Logging.getLogger(Loggers.CRS_FACTORY), AuthorityCodes.class,
"close", exception);
         }
     }
-
-    /**
-     * Implementation of {@link #dispose()} as a static method for sharing with {@link AuthorityCodes#close()}.
-     * It is caller's responsibility to invoke this method from a synchronization lock on
the factory.
-     */
-    static SQLException close(final Statement[] statements, SQLException exception) {
-        for (int i=statements.length; --i >= 0;) {
-            final Statement s = statements[i];
-            statements[i] = null;
-            if (s != null) try {
-                s.close();
-            } catch (SQLException e) {
-                if (exception == null) {
-                    exception = e;
-                } else {
-                    exception.addSuppressed(e);
-                }
-            }
-        }
-        return exception;
-    }
 }

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=1720139&r1=1720138&r2=1720139&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 Dec 15 12:16:07 2015
@@ -31,6 +31,7 @@ import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
 import java.sql.Statement;
 import java.sql.SQLException;
 import java.lang.ref.Reference;
@@ -58,10 +59,12 @@ import org.opengis.metadata.citation.OnL
 import org.opengis.metadata.quality.PositionalAccuracy;
 import org.opengis.referencing.NoSuchAuthorityCodeException;
 import org.apache.sis.internal.system.Loggers;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.metadata.iso.DefaultIdentifier;
 import org.apache.sis.metadata.iso.citation.DefaultCitation;
 import org.apache.sis.metadata.iso.citation.DefaultOnlineResource;
 import org.apache.sis.referencing.datum.BursaWolfParameters;
+import org.apache.sis.referencing.factory.FactoryDataException;
 import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
 import org.apache.sis.referencing.factory.ConcurrentAuthorityFactory;
 import org.apache.sis.util.iso.SimpleInternationalString;
@@ -70,6 +73,7 @@ import org.apache.sis.util.resources.Mes
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.logging.Logging;
 import org.apache.sis.util.ArgumentChecks;
+import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.Disposable;
 import org.apache.sis.util.Version;
 import org.apache.sis.measure.Units;
@@ -80,20 +84,28 @@ import org.apache.sis.measure.Units;
  * The EPSG database is freely available at <a href="http://www.epsg.org">http://www.epsg.org</a>.
  * Current version of this class requires EPSG database version 6.6 or above.
  *
- * <p>This factory accepts names as well as numerical identifiers.
- * For example <cite>"NTF (Paris) / France I"</cite> and {@code "27581"} both
fetch the same object.
+ * <p>EPSG codes are numerical identifiers. For example code 3395 stands for <cite>"WGS
84 / World Mercator"</cite>.
+ * Coordinate Reference Objects are normally created from their numerical codes, but this
factory accepts also names.
+ * For example {@code createProjectedCRS("3395")} and {@code createProjectedCRS("WGS 84 /
World Mercator")} both fetch
+ * the same object.
  * 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 instance.
  * If such an ambiguity is found, an exception will be thrown.
  * This behavior can be changed by overriding the {@link #isPrimaryKey(String)} method.</p>
  *
- * <p>This factory does not cache the result of {@code createFoo(String)} methods.
- * Asking for the same object twice will cause the EPSG database to be queried again.
- * For caching, this factory should be wrapped in {@link ConcurrentAuthorityFactory}.</p>
+ * <div class="section">Life cycle and caching</div>
+ * {@code EPSGFactory} instances should be short-lived since they may hold a significant
amount of JDBC resources.
+ * It is recommended to have those instances created on the fly by {@link ConcurrentAuthorityFactory}
and disposed
+ * after a relatively short {@linkplain ConcurrentAuthorityFactory#getTimeout timeout}.
+ * In addition {@code ConcurrentAuthorityFactory} caches the most recently created objects,
which reduce greatly
+ * the amount of {@code EPSGFactory} instantiations (and consequently the amount of database
accesses)
+ * in the common case where only a few EPSG codes are used by an application.
+ * {@code EPSGFactory.createFoo(String)} methods do not cache by themselves and query the
database on every invocation.
  *
- * <p>Because the primary distribution format for the EPSG database is MS-Access, this
class uses
+ * <div class="section">SQL dialects</div>
+ * Because the primary distribution format for the EPSG database is MS-Access, this class
uses
  * SQL statements formatted for the MS-Access syntax. For usage with an other database software,
- * a dialect-specific subclass must be used.</p>
+ * a dialect-specific subclass must be used.
  *
  * @author  Yann Cézard (IRD)
  * @author  Martin Desruisseaux (IRD, Geomatys)
@@ -139,7 +151,7 @@ public abstract class EPSGFactory extend
         if (target != unit) try {
             value = unit.getConverterToAny(target).convert(value);
         } catch (ConversionException e) {
-            throw new FactoryException(Errors.format(Errors.Keys.IncompatibleUnit_1, unit),
e);
+            throw new FactoryDataException(Errors.format(Errors.Keys.IncompatibleUnit_1,
unit), e);
         }
         switch (code) {
             case 8605: parameters.tX = value; break;
@@ -149,7 +161,7 @@ public abstract class EPSGFactory extend
             case 8609: parameters.rY = value; break;
             case 8610: parameters.rZ = value; break;
             case 8611: parameters.dS = value; break;
-            default: throw new FactoryException(Errors.format(Errors.Keys.UnexpectedParameter_1,
code));
+            default: throw new FactoryDataException(Errors.format(Errors.Keys.UnexpectedParameter_1,
code));
         }
     }
     // Datum shift operation methods
@@ -416,7 +428,7 @@ public abstract class EPSGFactory extend
     public synchronized Citation getAuthority() {
         if (authority == null) {
             final DefaultCitation c = new DefaultCitation("EPSG Geodetic Parameter Dataset");
-            c.setIdentifiers(Collections.singleton(new DefaultIdentifier("EPSG")));
+            c.setIdentifiers(Collections.singleton(new DefaultIdentifier(Constants.EPSG)));
             try {
                 /*
                  * Get the most recent version number from the history table. We get the
date in local timezone
@@ -458,8 +470,8 @@ addURIs:        for (int i=0; ; i++) {
                         case 2: {
                             url = metadata.getURL();
                             function = OnLineFunction.valueOf("CONNECTION");
-                            description = Messages.formatInternational(Messages.Keys.DataBase_4,
"EPSG", version,
-                                    metadata.getDatabaseProductName(),
+                            description = Messages.formatInternational(Messages.Keys.DataBase_4,
+                                    Constants.EPSG, version, metadata.getDatabaseProductName(),
                                     Version.valueOf(metadata.getDatabaseMajorVersion(),
                                                     metadata.getDatabaseMinorVersion()));
                             break;
@@ -569,11 +581,6 @@ addURIs:        for (int i=0; ; i++) {
                         result = new LinkedHashMap<>(result);
                     }
                     result.putAll(codes);
-                    try {
-                        codes.close();
-                    } catch (SQLException e) {  // Not a fatal exception for this method
since we got the data.
-                        unexpectedException("getAuthorityCodes", e);
-                    }
                 }
             }
         }
@@ -582,10 +589,10 @@ addURIs:        for (int i=0; ; i++) {
 
     /**
      * Gets a description of the object corresponding to a code.
+     * This method returns the object name in a lightweight manner, without creating the
full {@link IdentifiedObject}.
      *
      * @param  code Value allocated by authority.
-     * @return A description of the object, or {@code null} if the object corresponding to
the specified {@code code}
-     *         has no description.
+     * @return The object name, or {@code null} if the object corresponding to the specified
{@code code} has no name.
      * @throws NoSuchAuthorityCodeException if the specified {@code code} was not found.
      * @throws FactoryException if the query failed for some other reason.
      */
@@ -601,6 +608,174 @@ addURIs:        for (int i=0; ; i++) {
         throw noSuchAuthorityCode(IdentifiedObject.class, code);
     }
 
+    /**
+     * Returns a prepared statement for the specified name. Most {@link PreparedStatement}
creations are performed
+     * through this method, except {@link #toPrimaryKey} and {@link #createObject(String)}.
+     *
+     * @param  key  A key uniquely identifying the caller (e.g. {@code "Ellipsoid"} for {@link
#createEllipsoid(String)}).
+     * @param  sql  The SQL statement to use if for creating the {@link PreparedStatement}
object.
+     *              Will be used only if no prepared statement was already created for the
specified key.
+     * @return The prepared statement.
+     * @throws SQLException if the prepared statement can not be created.
+     */
+    private PreparedStatement prepareStatement(final String key, final String sql) throws
SQLException {
+        assert Thread.holdsLock(this);
+        PreparedStatement stmt = statements.get(key);
+        if (stmt == null) {
+            stmt = connection.prepareStatement(adaptSQL(sql));
+            statements.put(key, stmt);
+        }
+        // Partial check that the statement is for the right SQL query.
+        assert stmt.getParameterMetaData().getParameterCount() == CharSequences.count(sql,
'?');
+        return stmt;
+    }
+
+    /**
+     * Makes sure that the last result was non-null.
+     * Used for {@code getString(…)}, {@code getDouble(…)} and {@code getInt(…)} methods
only.
+     */
+    private static void ensureNonNull(final ResultSet result, final int columnIndex, final
Object code)
+            throws SQLException, FactoryDataException
+    {
+        if (result.wasNull()) {
+            final ResultSetMetaData metadata = result.getMetaData();
+            final String column = metadata.getColumnName(columnIndex);
+            final String table  = metadata.getTableName (columnIndex);
+            result.close();
+            throw new FactoryDataException(Errors.format(Errors.Keys.NullValueInTable_3,
table, column, code));
+        }
+    }
+
+    /**
+     * Same as {@link #getString(ResultSet, int, Object)},
+     * but reports the fault on an alternative column if the value is null.
+     */
+    private static String getString(final ResultSet result, final int columnIndex,
+                                    final String    code,   final int columnFault)
+            throws SQLException, FactoryDataException
+    {
+        final String str = result.getString(columnIndex);
+        if (result.wasNull()) {
+            final ResultSetMetaData metadata = result.getMetaData();
+            final String column = metadata.getColumnName(columnFault);
+            final String table  = metadata.getTableName (columnFault);
+            result.close();
+            throw new FactoryDataException(Errors.format(Errors.Keys.NullValueInTable_3,
table, column, code));
+        }
+        return str.trim();
+    }
+
+    /**
+     * Gets the string from the specified {@link ResultSet}.
+     * The string is required to be non-null. A null string will throw an exception.
+     *
+     * @param  result       The result set to fetch value from.
+     * @param  columnIndex  The column index (1-based).
+     * @param  code         The identifier of the record where the string was found.
+     * @return The string at the specified column.
+     * @throws SQLException if an error occurred while querying the database.
+     * @throws FactoryDataException if a null value was found.
+     */
+    private static String getString(final ResultSet result, final int columnIndex, final
Object code)
+            throws SQLException, FactoryDataException
+    {
+        final String value = result.getString(columnIndex);
+        ensureNonNull(result, columnIndex, code);
+        return value.trim();
+    }
+
+    /**
+     * Gets the value from the specified {@link ResultSet}.
+     * The value is required to be non-null. A null value (i.e. blank) will throw an exception.
+     *
+     * @param  result       The result set to fetch value from.
+     * @param  columnIndex  The column index (1-based).
+     * @param  code         The identifier of the record where the string was found.
+     * @return The double at the specified column.
+     * @throws SQLException if an error occurred while querying the database.
+     * @throws FactoryDataException if a null value was found.
+     */
+    private static double getDouble(final ResultSet result, final int columnIndex, final
Object code)
+            throws SQLException, FactoryDataException
+    {
+        final double value = result.getDouble(columnIndex);
+        ensureNonNull(result, columnIndex, code);
+        return value;
+    }
+
+    /**
+     * Gets the value from the specified {@link ResultSet}.
+     * The value is required to be non-null. A null value (i.e. blank) will throw an exception.
+     *
+     * @param  result       The result set to fetch value from.
+     * @param  columnIndex  The column index (1-based).
+     * @param  code         The identifier of the record where the string was found.
+     * @return The integer at the specified column.
+     * @throws SQLException if an error occurred while querying the database.
+     * @throws FactoryDataException if a null value was found.
+     */
+    private static int getInt(final ResultSet result, final int columnIndex, final Object
code)
+            throws SQLException, FactoryDataException
+    {
+        final int value = result.getInt(columnIndex);
+        ensureNonNull(result, columnIndex, code);
+        return value;
+    }
+
+    /**
+     * Sets the value of the primary key to search for, and executes the given prepared statement.
+     * The primary key should be the value returned by {@link #toPrimaryKey}.
+     * Its values is assigned to the parameter #1.
+     *
+     * @param  stmt  The prepared statement in which to set the primary key.
+     * @param  primaryKey  The primary key.
+     * @throws NoSuchIdentifierException if the primary key has not been found.
+     * @throws SQLException if an error occurred while querying the database.
+     */
+    private static ResultSet executeQuery(final PreparedStatement stmt, final String primaryKey)
+            throws NoSuchIdentifierException, SQLException
+    {
+        final int n;
+        try {
+            n = Integer.parseInt(primaryKey);
+        } catch (NumberFormatException e) {
+            final NoSuchIdentifierException ne = new NoSuchIdentifierException(Errors.format(
+                    Errors.Keys.IllegalIdentifierForCodespace_2, Constants.EPSG, primaryKey),
primaryKey);
+            ne.initCause(e);
+            throw ne;
+        }
+        stmt.setInt(1, n);
+        return stmt.executeQuery();
+    }
+
+    /**
+     * Sets the value of the primary keys to search for, and executes the given prepared
statement.
+     * The primary keys should be the values returned by {@link #toPrimaryKey}.
+     * Their values are assigned to parameters #1 and 2.
+     *
+     * @param  stmt The prepared statement in which to set the primary key.
+     * @param  primaryKey The primary key.
+     * @throws SQLException If an error occurred.
+     */
+    private static ResultSet executeQuery(final PreparedStatement stmt, final String pk1,
final String pk2)
+            throws NoSuchIdentifierException, SQLException
+    {
+        final int n1, n2;
+        String key = pk1;
+        try {
+            n1 = Integer.parseInt(      pk1);
+            n2 = Integer.parseInt(key = pk2);
+        } catch (NumberFormatException e) {
+            final NoSuchIdentifierException ne = new NoSuchIdentifierException(Errors.format(
+                    Errors.Keys.IllegalIdentifierForCodespace_2, Constants.EPSG, key), key);
+            ne.initCause(e);
+            throw ne;
+        }
+        stmt.setInt(1, n1);
+        stmt.setInt(2, n2);
+        return stmt.executeQuery();
+    }
+
     final boolean isProjection(final int code) throws NoSuchIdentifierException, SQLException
{
         return false;
     }

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java?rev=1720139&r1=1720138&r2=1720139&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
[UTF-8] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
[UTF-8] Tue Dec 15 12:16:07 2015
@@ -373,6 +373,11 @@ public final class Errors extends Indexe
         public static final short IllegalFormatPatternForClass_2 = 35;
 
         /**
+         * “{1}” is not a valid identifier for the “{0}” code space.
+         */
+        public static final short IllegalIdentifierForCodespace_2 = 208;
+
+        /**
          * The “{0}” language is not recognized.
          */
         public static final short IllegalLanguageCode_1 = 36;
@@ -826,6 +831,11 @@ public final class Errors extends Indexe
         public static final short NullMapValue = 97;
 
         /**
+         * Unexpected null value in record “{2}” for the column “{1}” in table “{0}”.
+         */
+        public static final short NullValueInTable_3 = 207;
+
+        /**
          * Array length is {0}, while we expected an even length.
          */
         public static final short OddArrayLength_1 = 98;

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties?rev=1720139&r1=1720138&r2=1720139&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
[ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
[ISO-8859-1] Tue Dec 15 12:16:07 2015
@@ -84,6 +84,7 @@ IllegalClass_2                    = Clas
 IllegalCoordinateSystem_1         = Coordinate system can not be \u201c{0}\u201d.
 IllegalCRSType_1                  = Coordinate reference system can not be of type \u2018{0}\u2019.
 IllegalFormatPatternForClass_2    = The \u201c{1}\u201d pattern can not be applied to formating
of objects of type \u2018{0}\u2019.
+IllegalIdentifierForCodespace_2   = \u201c{1}\u201d is not a valid identifier for the \u201c{0}\u201d
code space.
 IllegalLanguageCode_1             = The \u201c{0}\u201d language is not recognized.
 IllegalMemberType_2               = Member \u201c{0}\u201d can not be associated to type
\u201c{1}\u201d.
 IllegalOperationDimension_3       = Dimensions of \u201c{0}\u201d operation can not be ({1}
\u2192 {2}).
@@ -176,6 +177,7 @@ NullCollectionElement_1           = \u20
 # Use the OGC/ISO "Dictionary" word instead of "Map" for avoiding confusion with geographic
map.
 NullMapKey                        = Null key is not allowed in this dictionary.
 NullMapValue                      = Null values are not allowed in this dictionary.
+NullValueInTable_3                = Unexpected null value in record \u201c{2}\u201d for the
column \u201c{1}\u201d in table \u201c{0}\u201d.
 OddArrayLength_1                  = Array length is {0}, while we expected an even length.
 PropertyAlreadyExists_2           = Property \u201c{1}\u201d already exists in \u201c{0}\u201d.
 ParameterNotFound_2               = No parameter named \u201c{1}\u201d has been found in
\u201c{0}\u201d.

Modified: sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
URL: http://svn.apache.org/viewvc/sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties?rev=1720139&r1=1720138&r2=1720139&view=diff
==============================================================================
--- sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
[ISO-8859-1] (original)
+++ sis/branches/JDK8/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
[ISO-8859-1] Tue Dec 15 12:16:07 2015
@@ -81,6 +81,7 @@ IllegalCharacterForFormat_3       = Le c
 IllegalCoordinateSystem_1         = Le syst\u00e8me de coordonn\u00e9es ne peut pas \u00eatre
\u00ab\u202f{0}\u202f\u00bb.
 IllegalCRSType_1                  = Le syst\u00e8me de r\u00e9f\u00e9rence des coordonn\u00e9es
ne peut pas \u00eatre de type \u2018{0}\u2019.
 IllegalFormatPatternForClass_2    = Le mod\u00e8le \u00ab\u202f{1}\u202f\u00bb ne peut pas
\u00eatre appliqu\u00e9 au formatage d\u2019objets de type \u2018{0}\u2019.
+IllegalIdentifierForCodespace_2   = \u00ab\u202f{1}\u202f\u00bb n\u2019est pas un identifiant
valide pour l\u2019espace de codes \u00ab\u202f{0}\u202f\u00bb.
 IllegalLanguageCode_1             = Le code de langue \u00ab\u202f{0}\u202f\u00bb n\u2019est
pas reconnu.
 IllegalMemberType_2               = Le membre \u00ab\u202f{0}\u202f\u00bb ne peut pas \u00eatre
associ\u00e9 au type \u00ab\u202f{1}\u202f\u00bb.
 IllegalOperationDimension_3       = Les dimensions de l\u2019op\u00e9ration \u00ab\u202f{0}\u202f\u00bb
ne peuvent pas \u00eatre ({1} \u2192 {2}).
@@ -172,6 +173,7 @@ NullArgument_1                    = L\u2
 NullCollectionElement_1           = La collection \u2018{0}\u2019 n\u2019accepte pas les
valeurs nulles.
 NullMapKey                        = La cl\u00e9 nulle n\u2019est pas autoris\u00e9e dans
ce dictionnaire.
 NullMapValue                      = Les valeurs nulles ne sont pas autoris\u00e9es dans ce
dictionnaire.
+NullValueInTable_3                = Dans la table \u00ab\u202f{0}\u202f\u00bb, la colonne
\u00ab\u202f{1}\u202f\u00bb de l\u2019enregistrement \u00ab\u202f{2}\u202f\u00bb ne devrait
pas contenir de valeur nulle.
 OddArrayLength_1                  = La longueur du tableau est {0}, alors qu\u2019on attendait
une longueur paire.
 PropertyAlreadyExists_2           = La propri\u00e9t\u00e9 \u00ab\u202f{1}\u202f\u00bb existe
d\u00e9j\u00e0 dans \u00ab\u202f{0}\u202f\u00bb.
 ParameterNotFound_2               = Aucun param\u00e8tre nomm\u00e9 \u00ab\u202f{1}\u202f\u00bb
n\u2019a \u00e9t\u00e9 trouv\u00e9 dans \u00ab\u202f{0}\u202f\u00bb.



Mime
View raw message