Author: desruisseaux
Date: Mon Apr 25 20:30:40 2016
New Revision: 1740892

URL: http://svn.apache.org/viewvc?rev=1740892&view=rev
Log:
Merge from the JDK6 branch.

Added:
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/CRSCommand.java
      - copied unchanged from r1740890, 
sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/CRSCommand.java
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
      - copied, changed from r1740890, 
sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java
      - copied unchanged from r1740890, 
sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/TransformCommand.java
Removed:
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/IdentifierRow.java
Modified:
    sis/trunk/   (props changed)
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Command.java
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/CommandRunner.java
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/HelpCommand.java
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/InvalidOptionException.java
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/MetadataCommand.java
    
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Option.java
    
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties
    
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties
    
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options.properties
    
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options_fr.properties
    
sis/trunk/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java
    
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
    
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
    
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
    
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
    
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
    
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/DefaultMathTransformFactory.java
    
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/MathTransforms.java
    
sis/trunk/core/sis-referencing/src/main/resources/org/apache/sis/referencing/factory/sql/EPSG_Finish.sql
    
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/io/wkt/GeodeticObjectParserTest.java
    
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/CRSTest.java
    
sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/referencing/IdentifiedObjectsTest.java
    
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.java
    
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors.properties
    
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Errors_fr.properties
    
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.java
    
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary.properties
    
sis/trunk/core/sis-utility/src/main/java/org/apache/sis/util/resources/Vocabulary_fr.properties

Propchange: sis/trunk/
------------------------------------------------------------------------------
--- svn:mergeinfo (original)
+++ svn:mergeinfo Mon Apr 25 20:30:40 2016
@@ -1,4 +1,4 @@
 /sis/branches/Android:1430670-1480699
-/sis/branches/JDK6:1394364-1740421
-/sis/branches/JDK7:1394913-1740420
-/sis/branches/JDK8:1584960-1740419
+/sis/branches/JDK6:1394364-1740890
+/sis/branches/JDK7:1394913-1740886
+/sis/branches/JDK8:1584960-1740884

Modified: 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Command.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Command.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Command.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Command.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -41,20 +41,23 @@ import org.apache.sis.util.logging.Monol
  * <tr><td>{@code metadata}   </td><td>Show metadata information for the given 
file.</td></tr>
  * <tr><td>{@code crs}        </td><td>Show Coordinate Reference System 
information for the given file or code.</td></tr>
  * <tr><td>{@code identifier} </td><td>Show identifiers for metadata and 
referencing systems in the given file.</td></tr>
+ * <tr><td>{@code transform}  </td><td>Convert or transform coordinates from 
given source CRS to target CRS.</td></tr>
  * </table></blockquote>
  *
- * Each command can accepts an arbitrary amount of the following options:
+ * Each command can accepts some of the following options:
  *
  * <blockquote><table class="compact" summary="Supported command-line 
options.">
- * <tr><td>{@code --format}   </td><td>The output format: {@code xml}, {@code 
wkt}, {@code wkt1} or {@code text}.</td></tr>
- * <tr><td>{@code --locale}   </td><td>The locale to use for the command 
output.</td></tr>
- * <tr><td>{@code --timezone} </td><td>The timezone for the dates to be 
formatted.</td></tr>
- * <tr><td>{@code --encoding} </td><td>The encoding to use for the command 
output.</td></tr>
- * <tr><td>{@code --colors}   </td><td>Whether colorized output shall be 
enabled.</td></tr>
- * <tr><td>{@code --brief}    </td><td>Whether the output should contains only 
brief information.</td></tr>
- * <tr><td>{@code --verbose}  </td><td>Whether the output should contains more 
detailed information.</td></tr>
- * <tr><td>{@code --debug}    </td><td>Prints full stack trace in case of 
failure.</td></tr>
- * <tr><td>{@code --help}     </td><td>Lists the options available for a 
specific command.</td></tr>
+ * <tr><td>{@code --sourceCRS} </td><td>The Coordinate Reference System of 
input data.</td></tr>
+ * <tr><td>{@code --targetCRS} </td><td>The Coordinate Reference System of 
output data.</td></tr>
+ * <tr><td>{@code --format}    </td><td>The output format: {@code xml}, {@code 
wkt}, {@code wkt1} or {@code text}.</td></tr>
+ * <tr><td>{@code --locale}    </td><td>The locale to use for the command 
output.</td></tr>
+ * <tr><td>{@code --timezone}  </td><td>The timezone for the dates to be 
formatted.</td></tr>
+ * <tr><td>{@code --encoding}  </td><td>The encoding to use for the command 
output.</td></tr>
+ * <tr><td>{@code --colors}    </td><td>Whether colorized output shall be 
enabled.</td></tr>
+ * <tr><td>{@code --brief}     </td><td>Whether the output should contains 
only brief information.</td></tr>
+ * <tr><td>{@code --verbose}   </td><td>Whether the output should contains 
more detailed information.</td></tr>
+ * <tr><td>{@code --debug}     </td><td>Prints full stack trace in case of 
failure.</td></tr>
+ * <tr><td>{@code --help}      </td><td>Lists the options available for a 
specific command.</td></tr>
  * </table></blockquote>
  *
  * The {@code --locale}, {@code --timezone} and {@code --encoding} options 
apply to the command output sent
@@ -136,14 +139,9 @@ public final class Command {
             final String arg = args[i];
             if (arg.startsWith(Option.PREFIX)) {
                 final String name = arg.substring(Option.PREFIX.length());
-                final Option option;
-                try {
-                    option = Option.valueOf(name.toUpperCase(Locale.US));
-                } catch (IllegalArgumentException e) {
-                    throw new 
InvalidOptionException(Errors.format(Errors.Keys.UnknownOption_1, name), e, 
name);
-                }
+                final Option option = Option.forLabel(name);
                 if (option.hasValue) {
-                    i++; // Skip the next argument.
+                    i++;                        // Skip the next argument.
                 }
             } else {
                 // Takes the first non-argument option as the command name.
@@ -156,12 +154,13 @@ public final class Command {
             command = new HelpCommand(-1, args);
         } else {
             commandName = commandName.toLowerCase(Locale.US);
-                 if (commandName.equals("help"))       command = new 
HelpCommand    (commandIndex, args);
-            else if (commandName.equals("about"))      command = new 
AboutCommand   (commandIndex, args);
-            else if (commandName.equals("mime-type"))  command = new 
MimeTypeCommand(commandIndex, args);
-            else if (commandName.equals("identifier")) command = new 
MetadataCommand(MetadataCommand.Info.IDENTIFIER, commandIndex, args);
-            else if (commandName.equals("metadata"))   command = new 
MetadataCommand(MetadataCommand.Info.METADATA,   commandIndex, args);
-            else if (commandName.equals("crs"))        command = new 
MetadataCommand(MetadataCommand.Info.CRS,        commandIndex, args);
+                 if (commandName.equals("help"))       command = new 
HelpCommand      (commandIndex, args);
+            else if (commandName.equals("about"))      command = new 
AboutCommand     (commandIndex, args);
+            else if (commandName.equals("mime-type"))  command = new 
MimeTypeCommand  (commandIndex, args);
+            else if (commandName.equals("metadata"))   command = new 
MetadataCommand  (commandIndex, args);
+            else if (commandName.equals("crs"))        command = new 
CRSCommand       (commandIndex, args);
+            else if (commandName.equals("identifier")) command = new 
IdentifierCommand(commandIndex, args);
+            else if (commandName.equals("transform"))  command = new 
TransformCommand (commandIndex, args);
             else throw new InvalidCommandException(Errors.format(
                         Errors.Keys.UnknownCommand_1, commandName), 
commandName);
         }

Modified: 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/CommandRunner.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/CommandRunner.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/CommandRunner.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/CommandRunner.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -149,10 +149,10 @@ abstract class CommandRunner {
      * The argument at index {@code commandIndex} is the name of this command, 
and will be ignored except for
      * the special {@value #TEST} value which is used only at JUnit testing 
time.
      *
-     * @param  commandIndex Index of the {@code args} element containing the 
sub-command name.
-     * @param  arguments    The command-line arguments provided by the user.
-     * @param  validOptions The command-line options allowed by this 
sub-command.
-     * @throws InvalidOptionException If an illegal option has been provided, 
or the option has an illegal value.
+     * @param  commandIndex  index of the {@code args} element containing the 
sub-command name.
+     * @param  arguments     the command-line arguments provided by the user.
+     * @param  validOptions  the command-line options allowed by this 
sub-command.
+     * @throws InvalidOptionException if an illegal option has been provided, 
or the option has an illegal value.
      */
     @SuppressWarnings("UseOfSystemOutOrSystemErr")
     protected CommandRunner(final int commandIndex, final String[] arguments, 
final EnumSet<Option> validOptions)
@@ -170,12 +170,7 @@ abstract class CommandRunner {
             }
             if (arg.startsWith(Option.PREFIX)) {
                 final String name = arg.substring(Option.PREFIX.length());
-                final Option option;
-                try {
-                    option = Option.valueOf(name.toUpperCase(Locale.US));
-                } catch (IllegalArgumentException e) {
-                    throw new 
InvalidOptionException(Errors.format(Errors.Keys.UnknownOption_1, name), e, 
name);
-                }
+                final Option option = Option.forLabel(name);
                 if (!validOptions.contains(option)) {
                     throw new 
InvalidOptionException(Errors.format(Errors.Keys.UnknownOption_1, name), name);
                 }
@@ -197,7 +192,7 @@ abstract class CommandRunner {
         /*
          * Process the --locale, --encoding and --colors options.
          */
-        Option option = null; // In case of IllegalArgumentException.
+        Option option = null;                                           // In 
case of IllegalArgumentException.
         String value  = null;
         final Console console;
         final boolean explicitEncoding;
@@ -219,7 +214,7 @@ abstract class CommandRunner {
             colors = (value != null) ? Option.COLORS.parseBoolean(value) : 
(console != null) && X364.isAnsiSupported();
         } catch (RuntimeException e) {
             @SuppressWarnings("null")                                   // 
'option' has been assigned in 'get' argument.
-            final String name = option.name().toLowerCase(Locale.US);
+            final String name = option.label();
             throw new 
InvalidOptionException(Errors.format(Errors.Keys.IllegalOptionValue_2, name, 
value), name);
         }
         /*
@@ -254,7 +249,7 @@ abstract class CommandRunner {
      *
      * <p>An example of a pair of mutually exclusive options is {@code 
--brief} and {@code --verbose}.</p>
      *
-     * @param  exclusive Pairs of mutually exclusive options.
+     * @param  exclusive  pairs of mutually exclusive options.
      * @return {@code true} if two mutually exclusive options exist.
      */
     final boolean hasContradictoryOptions(final Option... exclusive) {
@@ -262,9 +257,7 @@ abstract class CommandRunner {
             final Option o1 = exclusive[i++];
             final Option o2 = exclusive[i++];
             if (options.containsKey(o1) && options.containsKey(o2)) {
-                
err.println(Errors.format(Errors.Keys.MutuallyExclusiveOptions_2,
-                        o1.name().toLowerCase(Locale.US),
-                        o2.name().toLowerCase(Locale.US)));
+                
err.println(Errors.format(Errors.Keys.MutuallyExclusiveOptions_2, o1.label(), 
o2.label()));
                 return true;
             }
         }
@@ -275,8 +268,8 @@ abstract class CommandRunner {
      * Checks the size of the {@link #files} list. If the list has an 
unexpected size,
      * then this method prints an error message to {@link #err} and returns 
{@code true}.
      *
-     * @param  min Minimal number of files.
-     * @param  max Maximum number of files.
+     * @param  min  minimal number of files.
+     * @param  max  maximum number of files.
      * @return {@code true} if the list size is not in the expected bounds.
      */
     final boolean hasUnexpectedFileCount(final int min, final int max) {
@@ -306,8 +299,8 @@ abstract class CommandRunner {
     /**
      * Prints the <cite>"Can not open …"</cite> error message followed by the 
message in the given exception.
      *
-     * @param fileIndex Index in the {@link #files} list of the file that can 
not be opened.
-     * @param e The exception which occurred.
+     * @param fileIndex  index in the {@link #files} list of the file that can 
not be opened.
+     * @param e          the exception which occurred.
      */
     final void canNotOpen(final int fileIndex, final Exception e) {
         error(Errors.format(Errors.Keys.CanNotOpen_1, files.get(fileIndex)), 
e);
@@ -316,8 +309,8 @@ abstract class CommandRunner {
     /**
      * Prints the given error message followed by the message in the given 
exception.
      *
-     * @param message The message to print before the exception, or {@code 
null}.
-     * @param e The exception which occurred.
+     * @param message  the message to print before the exception, or {@code 
null}.
+     * @param e        the exception which occurred.
      */
     final void error(final String message, final Exception e) {
         out.flush();
@@ -332,7 +325,7 @@ abstract class CommandRunner {
      * Shows the help instructions for a specific command. This method is 
invoked
      * instead of {@link #run()} if the the user provided the {@code --help} 
option.
      *
-     * @param commandName The command name converted to lower cases.
+     * @param commandName  the command name converted to lower cases.
      */
     protected void help(final String commandName) {
         new HelpCommand(this).help(false, new String[] {commandName}, 
validOptions);
@@ -342,7 +335,7 @@ abstract class CommandRunner {
      * Executes the sub-command.
      *
      * @return 0 on success, or an exit code if the command failed for a 
reason other than a Java exception.
-     * @throws Exception If an error occurred while executing the sub-command.
+     * @throws Exception if an error occurred while executing the sub-command.
      */
     public abstract int run() throws Exception;
 }

Modified: 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/HelpCommand.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/HelpCommand.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/HelpCommand.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/HelpCommand.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -17,7 +17,6 @@
 package org.apache.sis.console;
 
 import java.util.EnumSet;
-import java.util.Locale;
 import java.util.ResourceBundle;
 import java.io.IOException;
 import org.apache.sis.io.TableAppender;
@@ -42,7 +41,8 @@ final class HelpCommand extends CommandR
         "mime-type",
         "metadata",
         "crs",
-        "identifier"
+        "identifier",
+        "transform"
     };
 
     /**
@@ -110,7 +110,7 @@ final class HelpCommand extends CommandR
             out.print(vocabulary.getString(Vocabulary.Keys.Options));
             out.println(':');
             for (final Option option : validOptions) {
-                final String name = option.name().toLowerCase(Locale.US);
+                final String name = option.label();
                 table.append("  ").append(Option.PREFIX).append(name);
                 table.nextColumn();
                 table.append(options.getString(name));

Copied: 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
 (from r1740890, 
sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java)
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java?p2=sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java&p1=sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java&r1=1740890&r2=1740892&rev=1740892&view=diff
==============================================================================
--- 
sis/branches/JDK6/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/IdentifierCommand.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -38,6 +38,10 @@ import org.apache.sis.util.ComparisonMod
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.resources.Vocabulary;
 
+// Branch-dependent imports
+import org.apache.sis.metadata.iso.DefaultMetadata;
+import org.apache.sis.metadata.iso.DefaultIdentifier;
+
 
 /**
  * The "identifier" sub-command.
@@ -122,11 +126,11 @@ final class IdentifierCommand extends Me
         }
         if (metadata != null) {
             final List<Row> rows;
-            if (metadata instanceof Metadata) {
+            if (metadata instanceof DefaultMetadata) {
                 rows = new ArrayList<Row>();
-                final Identifier id = ((Metadata) 
metadata).getMetadataIdentifier();
-                if (id != null) {
-                    CharSequence desc = id.getDescription();
+                final Identifier id = ((DefaultMetadata) 
metadata).getMetadataIdentifier();
+                if (id instanceof DefaultIdentifier) {
+                    CharSequence desc = ((DefaultIdentifier) 
id).getDescription();
                     if (desc != null && !files.isEmpty()) desc = files.get(0);
                     rows.add(new Row(State.VALID, 
IdentifiedObjects.toString(id), desc));
                 }

Modified: 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/InvalidOptionException.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/InvalidOptionException.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/InvalidOptionException.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/InvalidOptionException.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -39,8 +39,8 @@ public class InvalidOptionException exte
     /**
      * Constructs an exception with the specified detail message.
      *
-     * @param message The detail message.
-     * @param option The name of the invalid option.
+     * @param message  the detail message.
+     * @param option   the name of the invalid option.
      */
     public InvalidOptionException(final String message, final String option) {
         super(message);
@@ -50,9 +50,9 @@ public class InvalidOptionException exte
     /**
      * Constructs an exception with the specified detail message and cause.
      *
-     * @param message The detail message.
-     * @param cause   The cause of this exception.
-     * @param option  The name of the invalid option.
+     * @param message  the detail message.
+     * @param cause    the cause of this exception.
+     * @param option   the name of the invalid option.
      */
     public InvalidOptionException(final String message, final Throwable cause, 
final String option) {
         super(message, cause);
@@ -62,7 +62,7 @@ public class InvalidOptionException exte
     /**
      * Returns the name of the invalid option.
      *
-     * @return The name of the invalid option.
+     * @return the name of the invalid option.
      */
     public String getOption() {
         return option;

Modified: 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/MetadataCommand.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/MetadataCommand.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/MetadataCommand.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/MetadataCommand.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -16,8 +16,6 @@
  */
 package org.apache.sis.console;
 
-import java.util.List;
-import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.EnumSet;
@@ -28,18 +26,15 @@ import java.io.IOException;
 import javax.xml.bind.Marshaller;
 import javax.xml.bind.JAXBException;
 import org.opengis.metadata.Metadata;
-import org.opengis.metadata.Identifier;
-import org.opengis.util.FactoryException;
 import org.opengis.referencing.ReferenceSystem;
 import org.opengis.referencing.crs.CoordinateReferenceSystem;
+import org.opengis.util.FactoryException;
 import org.apache.sis.io.wkt.WKTFormat;
 import org.apache.sis.io.wkt.Convention;
 import org.apache.sis.io.wkt.Colors;
 import org.apache.sis.metadata.MetadataStandard;
 import org.apache.sis.metadata.ValueExistencePolicy;
-import org.apache.sis.metadata.iso.DefaultIdentifier;
 import org.apache.sis.metadata.iso.DefaultMetadata;
-import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.CRS;
 import org.apache.sis.storage.DataStore;
 import org.apache.sis.storage.DataStores;
@@ -53,15 +48,15 @@ import org.apache.sis.xml.XML;
 
 
 /**
- * The "metadata", "crs" and "identifier" subcommands.
- * CRS are considered as a kind of metadata here.
+ * The "metadata" sub-command. This class is also used as the base class of 
other sub-commands
+ * that perform most of their work on the basis of metadata information.
  *
  * @author  Martin Desruisseaux (Geomatys)
  * @since   0.3
  * @version 0.7
  * @module
  */
-final class MetadataCommand extends CommandRunner {
+class MetadataCommand extends CommandRunner {
     /**
      * The protocol part of the filename to be recognized as a CRS authority.
      * In such case, this class will delegate to {@link CRS#forCode(String)}
@@ -75,98 +70,82 @@ final class MetadataCommand extends Comm
     static final int MAX_AUTHORITY_LENGTH = 5;
 
     /**
-     * The desired information.
-     */
-    static enum Info {
-        METADATA, CRS, IDENTIFIER
-    }
-
-    /**
      * The output format.
      */
-    private static enum Format {
+    static enum Format {
         TEXT, WKT, XML
     }
 
     /**
-     * The sub-command: {@code "metadata"}, {@code "crs"} or {@code 
"identifier"}.
+     * The output format. Default value can be overridden by {@link 
#parseArguments()}.
      */
-    private final Info command;
+    Format outputFormat = Format.TEXT;
 
     /**
-     * The output format.
+     * The WKT convention, or {@code null} if it does not apply.
      */
-    private Format outputFormat;
+    Convention convention;
 
     /**
-     * The WKT convention, or {@code null} if it does not apply.
+     * Sets to {@code true} by {@link #readMetadata()} if the users provided 
an unexpected number of file arguments.
+     * In such case, the {@link #run()} should terminate with exit code {@link 
Command#INVALID_ARGUMENT_EXIT_CODE}.
      */
-    private Convention convention;
+    boolean hasUnexpectedFileCount;
 
     /**
-     * Creates the {@code "metadata"}, {@code "crs"} or {@code "identifier"} 
sub-command.
+     * Creates the {@code "metadata"} sub-command.
      */
-    MetadataCommand(final Info command, final int commandIndex, final 
String... args) throws InvalidOptionException {
+    MetadataCommand(final int commandIndex, final String... args) throws 
InvalidOptionException {
         super(commandIndex, args, EnumSet.of(Option.FORMAT, Option.LOCALE, 
Option.TIMEZONE, Option.ENCODING,
                 Option.COLORS, Option.HELP, Option.DEBUG));
-        this.command = command;
+    }
+
+    /**
+     * Creates a new sub-command with the given command-line arguments.
+     * This constructor is for {@code MetadataCommand} subclasses only.
+     *
+     * @param  commandIndex  index of the {@code args} element containing the 
sub-command name.
+     * @param  arguments     the command-line arguments provided by the user.
+     * @param  validOptions  the command-line options allowed by this 
sub-command.
+     * @throws InvalidOptionException if an illegal option has been provided, 
or the option has an illegal value.
+     */
+    MetadataCommand(final int commandIndex, final String[] args, final 
EnumSet<Option> validOptions)
+            throws InvalidOptionException
+    {
+        super(commandIndex, args, validOptions);
     }
 
     /**
      * Parses the command-line arguments and initializes the {@link 
#outputFormat} and {@link #convention} fields
-     * accordingly. This method verifies the parameter validity.
+     * accordingly.
      */
-    private void parseArguments() throws InvalidOptionException {
+    final void parseArguments() throws InvalidOptionException {
         /*
          * Output format can be either "text" (the default) or "xml".
          * In the case of "crs" sub-command, we accept also WKT variants.
          */
         final String format = options.get(Option.FORMAT);
-        if (format == null || format.equalsIgnoreCase("text")) {
-            if (command == Info.CRS) {
+        if (format != null && !format.equalsIgnoreCase("text")) {
+            if (format.equalsIgnoreCase("wkt") || 
format.equalsIgnoreCase("wkt2")) {
                 outputFormat = Format.WKT;
-                convention = Convention.WKT2_SIMPLIFIED;
+                convention = Convention.WKT2;
+            } else if (format.equalsIgnoreCase("wkt1")) {
+                outputFormat = Format.WKT;
+                convention = Convention.WKT1;
+            } else if (format.equalsIgnoreCase("xml")) {
+                outputFormat = Format.XML;
             } else {
-                outputFormat = Format.TEXT;
-            }
-        } else if (format.equalsIgnoreCase("wkt") || 
format.equalsIgnoreCase("wkt2")) {
-            outputFormat = Format.WKT;
-            convention = Convention.WKT2;
-        } else if (format.equalsIgnoreCase("wkt1")) {
-            outputFormat = Format.WKT;
-            convention = Convention.WKT1;
-        } else if (format.equalsIgnoreCase("xml")) {
-            outputFormat = Format.XML;
-        } else {
-            throw new InvalidOptionException(Errors.format(
-                    Errors.Keys.IllegalOptionValue_2, "format", format), 
format);
-        }
-        final boolean isFormatCompatible;
-        switch (command) {
-            case CRS: {
-                isFormatCompatible = true;
-                break;
-            }
-            case IDENTIFIER: {
-                isFormatCompatible = (outputFormat == Format.TEXT);
-                break;
-            }
-            default: {
-                isFormatCompatible = (convention == null);
-                break;
+                throw new InvalidOptionException(Errors.format(
+                        Errors.Keys.IllegalOptionValue_2, "format", format), 
format);
             }
         }
-        if (!isFormatCompatible) {
-            throw new 
InvalidOptionException(Errors.format(Errors.Keys.IncompatibleFormat_2,
-                    command.name().toLowerCase(locale), format), format);
-        }
     }
 
     /**
-     * If the given argument begins with one of the known authorities ("URN", 
"EPSG", "CRS", "AUTO", <i>etc.</i>),
-     * delegates to {@link CRS#forCode(String)} and wraps in a metadata 
object. Otherwise returns {@code null}.
+     * Returns {@code true} if the given argument begins with one of the known 
authorities
+     * ("URN", "EPSG", "CRS", "AUTO", <i>etc.</i>).
      */
-    private static Metadata fromDatabase(final String code) throws 
FactoryException {
+    static boolean isAuthorityCode(final String code) {
         final char[] authority = new char[MAX_AUTHORITY_LENGTH];
         final int length = code.length();
         int p = 0, i = 0;
@@ -176,9 +155,7 @@ final class MetadataCommand extends Comm
                 if (!AUTHORITIES.contains(new String(authority, 0, p))) {
                     break;
                 }
-                final DefaultMetadata metadata = new DefaultMetadata();
-                
metadata.setReferenceSystemInfo(Collections.singleton(CRS.forCode(code)));
-                return metadata;
+                return true;
             }
             if (!Character.isWhitespace(c)) {
                 if (p >= MAX_AUTHORITY_LENGTH || 
!Character.isLetterOrDigit(c)) {
@@ -187,93 +164,87 @@ final class MetadataCommand extends Comm
                 /*
                  * Casting to char is okay because AUTHORITIES contains only 
ASCII values.
                  * If 'c' was a supplemental Unicode value, then the result of 
the cast
-                 * will not match any AUTHORITIES value anyway.
+                 * would not match any AUTHORITIES value anyway.
                  */
                 authority[p++] = (char) Character.toUpperCase(c);
             }
             i += Character.charCount(c);
         }
-        return null;
+        return false;
     }
 
     /**
-     * Prints metadata or CRS information.
+     * If the given argument begins with one of the known authorities ("URN", 
"EPSG", "CRS", "AUTO", <i>etc.</i>),
+     * delegates to {@link CRS#forCode(String)}. Otherwise reads the metadata 
using a datastore.
      *
-     * @throws DataStoreException if an error occurred while reading the file.
-     * @throws JAXBException if an error occurred while producing the XML 
output.
-     * @throws FactoryException if an error occurred while looking for a CRS 
identifier.
-     * @throws IOException should never happen, since we are appending to a 
print writer.
+     * @return A {@link Metadata} or {@link CoordinateReferenceSystem} 
instance, or {@code null} if none.
      */
-    @Override
-    @SuppressWarnings("UseOfSystemOutOrSystemErr")
-    public int run() throws InvalidOptionException, DataStoreException, 
JAXBException, FactoryException, IOException {
-        parseArguments();
-        /*
-         * Read metadata from the data storage only after we verified that the 
arguments are valid.
-         * The input can be a file given on the command line, or the standard 
input stream.
-         */
-        Metadata metadata;
+    final Object readMetadataOrCRS() throws DataStoreException, 
FactoryException {
         if (useStandardInput()) {
             final DataStore store = DataStores.open(System.in);
             try {
-                metadata = store.getMetadata();
+                return store.getMetadata();
             } finally {
                 store.close();
             }
+        } else if (hasUnexpectedFileCount(1, 1)) {
+            hasUnexpectedFileCount = true;
+            return null;
         } else {
-            if (hasUnexpectedFileCount(1, 1)) {
-                return Command.INVALID_ARGUMENT_EXIT_CODE;
-            }
             final String file = files.get(0);
-            metadata = fromDatabase(file);
-            if (metadata == null) {
+            if (isAuthorityCode(file)) {
+                return CRS.forCode(file);
+            } else {
                 final DataStore store = DataStores.open(file);
                 try {
-                    metadata = store.getMetadata();
+                    return store.getMetadata();
                 } finally {
                     store.close();
                 }
             }
         }
-        if (metadata == null) {
-            return 0;
+    }
+
+    /**
+     * Prints metadata or CRS information.
+     *
+     * @throws DataStoreException if an error occurred while reading the file.
+     * @throws JAXBException if an error occurred while producing the XML 
output.
+     * @throws FactoryException if an error occurred while looking for a CRS 
identifier.
+     * @throws IOException should never happen, since we are appending to a 
print writer.
+     */
+    @Override
+    public int run() throws Exception {
+        parseArguments();
+        if (convention != null) {
+            final String format = outputFormat.name();
+            throw new 
InvalidOptionException(Errors.format(Errors.Keys.IncompatibleFormat_2, 
"metadata", format), format);
         }
         /*
-         * If we are executing the "identifier" sub-command, then show the 
metadata identifier (if any)
-         * and the identifier of all referencing systems found. Otherwise if 
we are executing the "crs"
-         * sub-command, extract only the first CRS. That CRS will be displayed 
after the switch statement.
+         * Read metadata from the data storage only after we verified that the 
arguments are valid.
+         * The input can be a file given on the command line, or the standard 
input stream.
          */
-        Object object = metadata;
-choice: switch (command) {
-            case IDENTIFIER: {
-                final List<IdentifierRow> rows = new 
ArrayList<IdentifierRow>();
-                if (metadata instanceof DefaultMetadata) {
-                    final Identifier id = ((DefaultMetadata) 
metadata).getMetadataIdentifier();
-                    if (id instanceof DefaultIdentifier) {
-                        CharSequence desc = ((DefaultIdentifier) 
id).getDescription();
-                        if (desc != null && !files.isEmpty()) desc = 
files.get(0);
-                        rows.add(new IdentifierRow(IdentifierRow.State.VALID, 
IdentifiedObjects.toString(id), desc));
-                    }
-                }
-                for (final ReferenceSystem rs : 
metadata.getReferenceSystemInfo()) {
-                    rows.add(IdentifierRow.create(rs));
-                }
-                IdentifierRow.print(rows, out, locale, colors);
-                return 0;
-            }
-            case CRS: {
-                for (final ReferenceSystem rs : 
metadata.getReferenceSystemInfo()) {
-                    if (rs instanceof CoordinateReferenceSystem) {
-                        object = rs;
-                        break choice;
-                    }
-                }
-                return 0;
+        Object metadata = readMetadataOrCRS();
+        if (hasUnexpectedFileCount) {
+            return Command.INVALID_ARGUMENT_EXIT_CODE;
+        }
+        if (metadata != null) {
+            if (!(metadata instanceof Metadata)) {
+                final DefaultMetadata md = new DefaultMetadata();
+                
md.setReferenceSystemInfo(Collections.singleton((ReferenceSystem) metadata));
+                metadata = md;
             }
+            format(metadata);
         }
-        /*
-         * Format metadata to the standard output stream.
-         */
+        return 0;
+    }
+
+    /**
+     * Format the given metadata or CRS object to the standard output stream.
+     * The format is determined by {@link #outputFormat} and (in WKT case 
only) {@link #convention}.
+     */
+    @SuppressWarnings("UseOfSystemOutOrSystemErr")
+    final void format(final Object object) throws IOException, JAXBException {
         switch (outputFormat) {
             case TEXT: {
                 final TreeTable tree = 
MetadataStandard.ISO_19115.asTreeTable(object, ValueExistencePolicy.NON_EMPTY);
@@ -313,7 +284,6 @@ choice: switch (command) {
             }
         }
         out.flush();
-        return 0;
     }
 
     /**

Modified: 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Option.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Option.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Option.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/main/java/org/apache/sis/console/Option.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -30,6 +30,16 @@ import org.apache.sis.util.resources.Err
  */
 enum Option {
     /**
+     * The Coordinate Reference System of input data.
+     */
+    SOURCE_CRS(true),
+
+    /**
+     * The Coordinate Reference System of input data.
+     */
+    TARGET_CRS(true),
+
+    /**
      * The output format. Examples: {@code "xml"}, {@code "text"}.
      */
     FORMAT(true),
@@ -95,6 +105,14 @@ enum Option {
     };
 
     /**
+     * The string representation of this option, as used on the command line.
+     * This is usually the lower-case version of {@link #name()}.
+     *
+     * @see #label()
+     */
+    private String label;
+
+    /**
      * Whether this option expects a value.
      */
     final boolean hasValue;
@@ -102,13 +120,43 @@ enum Option {
     /**
      * Creates a new option.
      *
-     * @param hasValue Whether this option expects a value.
+     * @param hasValue  whether this option expects a value.
      */
     private Option(final boolean hasValue) {
         this.hasValue = hasValue;
     }
 
     /**
+     * Special case for which {@code label()} should not be only the 
lower-case of enum name.
+     */
+    static {
+        SOURCE_CRS.label = "sourceCRS";
+        TARGET_CRS.label = "targetCRS";
+    }
+
+    /**
+     * Return the string representation as used on the command line.
+     */
+    String label() {
+        if (label == null) {
+            label = name().toLowerCase(Locale.US);
+        }
+        return label;
+    }
+
+    /**
+     * Returns the option for the given string.
+     */
+    static Option forLabel(final String label) throws InvalidOptionException {
+        for (final Option option : values()) {
+            if (label.equalsIgnoreCase(option.name().replace("_", ""))) {
+                return option;
+            }
+        }
+        throw new 
InvalidOptionException(Errors.format(Errors.Keys.UnknownOption_1, label), 
label);
+    }
+
+    /**
      * Parses the given value as a boolean.
      *
      * @param  value The value to parse.

Modified: 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties
 [ISO-8859-1] (original)
+++ 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands.properties
 [ISO-8859-1] Mon Apr 25 20:30:40 2016
@@ -8,3 +8,4 @@ mime-type=Show MIME type for the given f
 metadata=Show metadata information for the given file.
 crs=Show Coordinate Reference System (CRS) information for the given file.
 identifier=Show identifiers for metadata and referencing systems in the given 
file.
+transform=Convert or transform coordinates from given source CRS to target CRS.

Modified: 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties
 [ISO-8859-1] (original)
+++ 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Commands_fr.properties
 [ISO-8859-1] Mon Apr 25 20:30:40 2016
@@ -8,3 +8,4 @@ mime-type=Affiche le type MIME du fichie
 metadata=Affiche les méta-données du fichier spécifié.
 crs=Affiche le système de référence des coordonnées du fichier spécifié.
 identifier=Affiche les identifiants des méta-données et des systèmes de 
références du fichier spécifié.
+transform=Transforme des coordonnées du système de référence source vers le 
système destination donné.

Modified: 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options.properties
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options.properties?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options.properties
 [ISO-8859-1] (original)
+++ 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options.properties
 [ISO-8859-1] Mon Apr 25 20:30:40 2016
@@ -1,4 +1,6 @@
 # Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.
+sourceCRS=The Coordinate Reference System of input data.
+targetCRS=The Coordinate Reference System of output data.
 format=The output format: xml, wkt, wkt1 or text.
 locale=The locale to use for the command output.
 timezone=The timezone for the dates to be formatted.

Modified: 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options_fr.properties
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options_fr.properties?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options_fr.properties
 [ISO-8859-1] (original)
+++ 
sis/trunk/application/sis-console/src/main/resources/org/apache/sis/console/Options_fr.properties
 [ISO-8859-1] Mon Apr 25 20:30:40 2016
@@ -1,4 +1,6 @@
 # Licensed to the Apache Software Foundation (ASF) under one or more 
contributor license agreements.
+sourceCRS=Le système de référence des coordonnées source.
+targetCRS=Le système de référence des coordonnées destination.
 format=Le format de sortie: xml, wkt, wkt1 ou text.
 locale=Les paramètres régionaux à utiliser pour la sortie de la commande.
 timezone=Le fuseau horaire des dates à écrire.

Modified: 
sis/trunk/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java
 [UTF-8] (original)
+++ 
sis/trunk/application/sis-console/src/test/java/org/apache/sis/console/MetadataCommandTest.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -59,7 +59,7 @@ public final strictfp class MetadataComm
     public void testNetCDF() throws Exception {
         final URL url = MetadataCommandTest.class.getResource("NCEP-SST.nc");
         assertNotNull("NCEP-SST.nc", url);
-        final MetadataCommand test = new 
MetadataCommand(MetadataCommand.Info.METADATA, 0, CommandRunner.TEST, 
url.toString());
+        final MetadataCommand test = new MetadataCommand(0, 
CommandRunner.TEST, url.toString());
         test.run();
         verifyNetCDF("Metadata", test.outputBuffer.toString());
     }
@@ -86,8 +86,7 @@ public final strictfp class MetadataComm
     @DependsOnMethod("testNetCDF")
     public void testFormatXML() throws Exception {
         final URL url = MetadataCommandTest.class.getResource("NCEP-SST.nc");
-        final MetadataCommand test = new 
MetadataCommand(MetadataCommand.Info.METADATA,
-                0, CommandRunner.TEST, url.toString(), "--format", "XML");
+        final MetadataCommand test = new MetadataCommand(0, 
CommandRunner.TEST, url.toString(), "--format", "XML");
         test.run();
         verifyNetCDF("<?xml", test.outputBuffer.toString());
     }

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/sql/Initializer.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -431,6 +431,8 @@ public abstract class Initializer {
      * @return {@code true} if the exception indicates a successful shutdown.
      */
     static boolean isSuccessfulShutdown(final SQLException e) {
-        return e.getErrorCode() == 45000 && "08006".equals(e.getSQLState());
+        final String state = e.getSQLState();
+        return "08006".equals(state) ||     // Database 'SpatialMetadata' 
shutdown.
+               "XJ004".equals(state);       // Database 'SpatialMetadata' not 
found (may happen if we failed to open it in the first place).
     }
 }

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/AbstractParser.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -83,13 +83,6 @@ abstract class AbstractParser implements
     static final int MANDATORY = 2;
 
     /**
-     * The logger to use for reporting warnings when this parser is used 
through the {@link #createFromWKT(String)}.
-     * This happen most often when the user invoke the {@link 
org.apache.sis.referencing.CRS#fromWKT(String)}
-     * convenience method.
-     */
-    private static final Logger LOGGER = Logging.getLogger(Loggers.WKT);
-
-    /**
      * The locale for error messages (not for number parsing), or {@code null} 
for the system default.
      */
     final Locale errorLocale;
@@ -196,6 +189,14 @@ abstract class AbstractParser implements
     abstract String getPublicFacade();
 
     /**
+     * Returns the name of the method invoked from {@link #getPublicFacade()}.
+     * This information is used for logging purpose only.
+     */
+    String getFacadeMethod() {
+        return "createFromWKT";
+    }
+
+    /**
      * Creates the object from a string. This method is for implementation of 
{@code createFromWKT(String)}
      * method is SIS factories only.
      *
@@ -220,16 +221,24 @@ abstract class AbstractParser implements
         }
         final Warnings warnings = getAndClearWarnings(value);
         if (warnings != null) {
-            final LogRecord record = new LogRecord(Level.WARNING, 
warnings.toString());
-            record.setSourceClassName(getPublicFacade());
-            record.setSourceMethodName("createFromWKT");
-            record.setLoggerName(LOGGER.getName());
-            LOGGER.log(record);
+            log(new LogRecord(Level.WARNING, warnings.toString()));
         }
         return value;
     }
 
     /**
+     * Logs the given record. This is used only when we can not use the {@link 
#warning warning methods},
+     * or when the information is not worth to report as a warning.
+     */
+    final void log(final LogRecord record) {
+        Logger logger = Logging.getLogger(Loggers.WKT);
+        record.setSourceClassName(getPublicFacade());
+        record.setSourceMethodName(getFacadeMethod());
+        record.setLoggerName(logger.getName());
+        logger.log(record);
+    }
+
+    /**
      * Returns the index after the end of the fragment name starting at the 
given index.
      * Current implementation assumes that the fragment name is a Unicode 
identifier.
      */
@@ -323,7 +332,7 @@ abstract class AbstractParser implements
     /**
      * Parses the given unit symbol.
      */
-    final Unit<?> parseUnit(final String text) throws ParseException {
+    final Unit<?> parseUnit(final String text) throws ParseException, 
IllegalArgumentException {
         if (unitFormat == null) {
             if (symbols.getLocale() == Locale.ROOT) {
                 return Units.valueOf(text);             // Most common case, 
avoid the convolved code below.

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java 
[UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/Formatter.java 
[UTF-8] Mon Apr 25 20:30:40 2016
@@ -696,7 +696,8 @@ public class Formatter implements Locali
             info = ((GeneralParameterValue) object).getDescriptor();
         }
         if (info != null) {
-            appendComplement(info, (stackDepth != 0) ? 
enclosingElements.get(stackDepth - 1) : null);
+            appendComplement(info, (stackDepth >= 1) ? 
enclosingElements.get(stackDepth - 1) : null,
+                                   (stackDepth >= 2) ? 
enclosingElements.get(stackDepth - 2) : null);
         }
         buffer.appendCodePoint(symbols.getClosingBracket(0));
         indent(-1);
@@ -711,9 +712,10 @@ public class Formatter implements Locali
      * and have a special treatment: they are written by {@link 
#append(FormattableObject)}
      * after the {@code formatTo(Formatter)} method returned.
      *
-     * <p>The {@code ID[<name>,<code>,…]} element is written only for the root 
element, unless the convention are
-     * INTERNAL. If formatted, the ID element will be on the same line than 
the enclosing one if no line separator
-     * were requested (e.g. SPHEROID["Clarke 1866", …, ID["EPSG", 7008]]), or 
on a new line otherwise. Example:</p>
+     * <p>The {@code ID[<name>,<code>,…]} element is normally written only for 
the root element
+     * (unless the convention is {@code INTERNAL}), but there is various 
exceptions to this rule.
+     * If formatted, the {@code ID} element will be by default on the same 
line than the enclosing
+     * element (e.g. {@code SPHEROID["Clarke 1866", …, ID["EPSG", 7008]]}). 
Other example:</p>
      *
      * {@preformat text
      *   PROJCS["NAD27 / Idaho Central",
@@ -734,7 +736,7 @@ public class Formatter implements Locali
      * A {@code <remark>} can be included within the descriptions of source 
and target CRS embedded within
      * a coordinate transformation as well as within the coordinate 
transformation itself.</blockquote>
      */
-    private void appendComplement(final IdentifiedObject object, final 
FormattableObject parent) {
+    private void appendComplement(final IdentifiedObject object, final 
FormattableObject parent, final FormattableObject gp) {
         isComplement = true;
         final boolean showIDs;      // Whether to format ID[…] elements.
         final boolean filterID;     // Whether we shall limit to a single 
ID[…] element.
@@ -757,6 +759,9 @@ public class Formatter implements Locali
              */
             if (parent == null || parent instanceof CompoundCRS) {
                 showIDs = true;
+            } else if (gp instanceof CoordinateOperation && !(parent 
instanceof IdentifiedObject)) {
+                // "SourceCRS[…]" and "TargetCRS[…]" sub-elements in 
CoordinateOperation.
+                showIDs = true;
             } else if (convention == Convention.WKT2_SIMPLIFIED) {
                 showIDs = false;
             } else {
@@ -773,7 +778,7 @@ public class Formatter implements Locali
                     showRemarks = showOthers;
                 } else if (object instanceof ReferenceSystem) {
                     showOthers  = (parent == null);
-                    showRemarks = (parent == null) || (getEnclosingElement(2) 
instanceof CoordinateOperation);
+                    showRemarks = (parent == null) || (gp instanceof 
CoordinateOperation);
                 } else {
                     showOthers  = false;    // Mandated by ISO 19162.
                     showRemarks = false;

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/GeodeticObjectParser.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -26,6 +26,8 @@ import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.Date;
+import java.util.logging.Level;
+import java.util.logging.LogRecord;
 import java.text.DateFormat;
 import java.text.NumberFormat;
 import java.text.ParsePosition;
@@ -38,6 +40,7 @@ import javax.measure.quantity.Angle;
 import javax.measure.quantity.Length;
 import javax.measure.quantity.Quantity;
 import javax.measure.quantity.Duration;
+import javax.measure.converter.ConversionException;
 
 import org.opengis.util.Factory;
 import org.opengis.metadata.Identifier;
@@ -71,6 +74,7 @@ import org.apache.sis.internal.metadata.
 import org.apache.sis.internal.metadata.TransformationAccuracy;
 import org.apache.sis.internal.util.LocalizedParseException;
 import org.apache.sis.internal.system.DefaultFactories;
+import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.util.CharSequences;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.util.iso.DefaultNameSpace;
@@ -92,7 +96,7 @@ import static java.util.Collections.sing
  * @version 0.7
  * @module
  */
-final class GeodeticObjectParser extends MathTransformParser implements 
Comparator<CoordinateSystemAxis> {
+class GeodeticObjectParser extends MathTransformParser implements 
Comparator<CoordinateSystemAxis> {
     /**
      * The names of the 7 parameters in a {@code TOWGS84[…]} element.
      * Those names are derived from the <cite>Well Known Text</cite> (WKT) 
version 1 specification.
@@ -277,7 +281,7 @@ final class GeodeticObjectParser extends
      * @throws ParseException if the string can not be parsed.
      */
     @Override
-    public Object parseObject(final String text, final ParsePosition position) 
throws ParseException {
+    public final Object parseObject(final String text, final ParsePosition 
position) throws ParseException {
         final Object object;
         try {
             object = super.parseObject(text, position);
@@ -321,7 +325,7 @@ final class GeodeticObjectParser extends
      * @throws ParseException if the element can not be parsed.
      */
     @Override
-    Object parseObject(final Element element) throws ParseException {
+    final Object parseObject(final Element element) throws ParseException {
         Object value = parseCoordinateReferenceSystem(element, false);
         if (value != null) {
             return value;
@@ -617,7 +621,7 @@ final class GeodeticObjectParser extends
      * @return The {@code "UNIT"} element as an {@link Unit} object, or {@code 
null} if none.
      * @throws ParseException if the {@code "UNIT"} can not be parsed.
      *
-     * @todo Authority code is currently ignored. We may consider to create a 
subclass of
+     * @todo Authority code is currently discarded after parsing. We may 
consider to create a subclass of
      *       {@link Unit} which implements {@link IdentifiedObject} in a 
future version.
      */
     @SuppressWarnings("unchecked")
@@ -630,16 +634,48 @@ final class GeodeticObjectParser extends
         }
         final String name   = element.pullString("name");
         final double factor = element.pullDouble("factor");
-        final Unit<?> unit  = parseUnitID(element);
+        Unit<Q> unit   = Units.multiply(baseUnit, factor);
+        Unit<?> verify = parseUnitID(element);
         element.close(ignoredElements);
-        if (unit != null) {
-            if (baseUnit.toSI().equals(unit.toSI())) {
-                return (Unit<Q>) unit;
+        /*
+         * Consider the following element: UNIT[“km”, 1000, ID[“EPSG”, “9036”]]
+         *
+         *  - if the authority code (“9036”) refers to a unit incompatible 
with 'baseUnit' (“metre”), log a warning.
+         *  - otherwise: 1) unconditionally replace the parsed unit (“km”) by 
the unit referenced by the authority code.
+         *               2) if the new unit is not equivalent to the old one 
(i.e. different scale factor), log a warning.
+         */
+        if (verify != null) {
+            if (!baseUnit.toSI().equals(verify.toSI())) {
+                warning(parent, element, 
Errors.formatInternational(Errors.Keys.InconsistentUnitsForCS_1, verify), null);
+            } else if (Math.abs(unit.getConverterTo(unit = (Unit<Q>) 
verify).convert(1) - 1) > Numerics.COMPARISON_THRESHOLD) {
+                warning(parent, element, 
Errors.formatInternational(Errors.Keys.UnexpectedScaleFactorForUnit_2, verify, 
factor), null);
             } else {
-                warning(parent, element, 
Errors.formatInternational(Errors.Keys.IllegalUnitFor_2, keyword, unit), null);
+                verify = null;                                          // 
Means to perform additional verifications.
+            }
+        }
+        /*
+         * Above block verified the ID[“EPSG”, “9036”] authority code. Now 
verify the unit parsed from the “km” symbol.
+         * This is only a verification; we will not replace the unit by the 
parsed one (i.e. authority code or scale
+         * factor have precedence over the unit symbol).
+         */
+        if (verify == null) {
+            try {
+                verify = parseUnit(name);
+            } catch (IllegalArgumentException e) {
+                log(new LogRecord(Level.FINE, e.toString()));
+            } catch (ParseException e) {
+                log(new LogRecord(Level.FINE, e.toString()));
+            }
+            if (verify != null) try {
+                if (Math.abs(verify.getConverterToAny(unit).convert(1) - 1) > 
Numerics.COMPARISON_THRESHOLD) {
+                    warning(parent, element, 
Errors.formatInternational(Errors.Keys.UnexpectedScaleFactorForUnit_2, verify, 
factor), null);
+                }
+            } catch (ConversionException e) {
+                throw (ParseException) new LocalizedParseException(errorLocale,
+                        Errors.Keys.InconsistentUnitsForCS_1, new Object[] 
{verify}, element.offset).initCause(e);
             }
         }
-        return Units.multiply(baseUnit, factor);
+        return unit;
     }
 
     /**
@@ -1091,7 +1127,7 @@ final class GeodeticObjectParser extends
      *          0 if undetermined (no axis order change).
      */
     @Override
-    public int compare(final CoordinateSystemAxis o1, final 
CoordinateSystemAxis o2) {
+    public final int compare(final CoordinateSystemAxis o1, final 
CoordinateSystemAxis o2) {
         final Integer n1 = axisOrder.get(o1);
         final Integer n2 = axisOrder.get(o2);
         if (n1 != null) {

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/MathTransformParser.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -245,7 +245,12 @@ class MathTransformParser extends Abstra
             return Units.multiply(BASE_UNITS[index], factor);
         }
         // If we can not infer the base type, we have to rely on the name.
-        return parseUnit(name);
+        try {
+            return parseUnit(name);
+        } catch (IllegalArgumentException e) {
+            throw (ParseException) new LocalizedParseException(errorLocale,
+                    Errors.Keys.UnknownUnit_1, new Object[] {name}, 
element.offset).initCause(e);
+        }
     }
 
     /**

Modified: 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java 
[UTF-8] (original)
+++ 
sis/trunk/core/sis-metadata/src/main/java/org/apache/sis/io/wkt/WKTFormat.java 
[UTF-8] Mon Apr 25 20:30:40 2016
@@ -708,7 +708,7 @@ public class WKTFormat extends CompoundF
     private AbstractParser parser() {
         AbstractParser parser = this.parser;
         if (parser == null) {
-            this.parser = parser = new GeodeticObjectParser(symbols, 
fragments(),
+            this.parser = parser = new Parser(symbols, fragments(),
                     (NumberFormat) getFormat(Number.class),
                     (DateFormat)   getFormat(Date.class),
                     (UnitFormat)   getFormat(Unit.class),
@@ -721,6 +721,23 @@ public class WKTFormat extends CompoundF
     }
 
     /**
+     * The parser created by {@link #parser()}, identical to {@link 
GeodeticObjectParser} except for
+     * the source of logging messages which is the enclosing {@code WKTParser} 
instead than a factory.
+     */
+    private static final class Parser extends GeodeticObjectParser {
+        Parser(final Symbols symbols, final Map<String,Element> fragments,
+                final NumberFormat numberFormat, final DateFormat dateFormat, 
final UnitFormat unitFormat,
+                final Convention convention, final Transliterator 
transliterator, final Locale errorLocale,
+                final Map<Class<?>,Factory> factories)
+        {
+            super(symbols, fragments, numberFormat, dateFormat, unitFormat, 
convention, transliterator, errorLocale, factories);
+        }
+
+        @Override String getPublicFacade() {return WKTFormat.class.getName();}
+        @Override String getFacadeMethod() {return "parse";}
+    }
+
+    /**
      * Formats the specified object as a Well Know Text. The formatter accepts 
at least the following types:
      * {@link FormattableObject}, {@link IdentifiedObject},
      * {@link org.opengis.referencing.operation.MathTransform},

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/IdentifiedObjects.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -43,6 +43,7 @@ import org.apache.sis.internal.metadata.
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.referencing.factory.IdentifiedObjectFinder;
 import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
+import org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException;
 
 import static org.apache.sis.internal.util.Citations.iterator;
 import static org.apache.sis.internal.util.Citations.identifierMatches;
@@ -515,14 +516,17 @@ public final class IdentifiedObjects ext
      * @param  authority The authority of the objects to search (typically 
{@code "EPSG"} or {@code "OGC"}),
      *         or {@code null} for searching among the objects created by all 
authorities.
      * @return A finder to use for looking up unidentified objects.
-     * @throws FactoryException if the finder can not be created.
+     * @throws NoSuchAuthorityFactoryException if the given authority is not 
found.
+     * @throws FactoryException if the finder can not be created for another 
reason.
      *
      * @see #lookupEPSG(IdentifiedObject)
      * @see #lookupURN(IdentifiedObject, Citation)
      * @see 
org.apache.sis.referencing.factory.GeodeticAuthorityFactory#newIdentifiedObjectFinder()
      * @see IdentifiedObjectFinder#find(IdentifiedObject)
      */
-    public static IdentifiedObjectFinder newFinder(final String authority) 
throws FactoryException {
+    public static IdentifiedObjectFinder newFinder(final String authority)
+            throws NoSuchAuthorityFactoryException, FactoryException
+    {
         final GeodeticAuthorityFactory factory;
         if (authority == null) {
             factory = AuthorityFactories.ALL;

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/GeodeticObjectFactory.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -42,6 +42,7 @@ import org.opengis.referencing.cs.*;
 import org.opengis.referencing.crs.*;
 import org.opengis.referencing.datum.*;
 import org.opengis.referencing.operation.*;
+import org.opengis.parameter.ParameterNotFoundException;
 import org.apache.sis.referencing.cs.*;
 import org.apache.sis.referencing.crs.*;
 import org.apache.sis.referencing.datum.*;
@@ -1639,7 +1640,25 @@ public class GeodeticObjectFactory exten
         } catch (Exception e) { // (ReflectiveOperationException) on JDK7 
branch.
             throw new FactoryException(e);
         }
-        final Object object = p.createFromWKT(text);
+        final Object object;
+        try {
+            object = p.createFromWKT(text);
+        } catch (FactoryException e) {
+            /*
+             * In the case of map projection, the parsing may fail because a 
projection parameter is not known to SIS.
+             * If this happen, replace the generic exception thrown be the 
parser (which is FactoryException) by a
+             * more specific one. Note that InvalidGeodeticParameterException 
is defined only in this sis-referencing
+             * module, so we could not throw it from the sis-metadata module 
that contain the parser.
+             */
+            Throwable cause = e.getCause();
+            while (cause != null) {
+                if (cause instanceof ParameterNotFoundException) {
+                    throw new 
InvalidGeodeticParameterException(e.getMessage(), cause);     // More accurate 
exception.
+                }
+                cause = cause.getCause();
+            }
+            throw e;
+        }
         parser.set(p);
         if (object instanceof CoordinateReferenceSystem) {
             return (CoordinateReferenceSystem) object;

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/IdentifiedObjectFinder.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -17,7 +17,6 @@
 package org.apache.sis.referencing.factory;
 
 import java.util.Set;
-import java.util.Iterator;
 import java.util.Collections;
 import java.util.LinkedHashSet;
 import org.opengis.util.GenericName;
@@ -338,11 +337,16 @@ public class IdentifiedObjectFinder {
 
     /**
      * Lookups only one object which is approximatively equal to the specified 
object.
-     * If the set returned by {@link #find(IdentifiedObject)} contains exactly 
one element,
-     * then that element is returned. Otherwise this method returns {@code 
null}.
+     * This method invokes {@link #find(IdentifiedObject)}, then examine the 
returned {@code Set} as below:
      *
-     * <p>This method returns {@code null} if there is more than one element
-     * because in such case we consider that there is an ambiguity.</p>
+     * <ul>
+     *   <li>If the set is empty, then this method returns {@code null}.</li>
+     *   <li>If the set contains exactly one element, then this method returns 
that element.</li>
+     *   <li>If the set contains more than one element, but only one element 
has the same axis order
+     *       than {@code object} and all other elements have different axis 
order,
+     *       then this method returns the single element having the same axis 
order.</li>
+     *   <li>Otherwise this method considers that there is ambiguity and 
returns {@code null}.</li>
+     * </ul>
      *
      * @param  object The object looked up.
      * @return The identified object, or {@code null} if none or ambiguous.
@@ -353,18 +357,25 @@ public class IdentifiedObjectFinder {
          * Do not invoke Set.size() because it may be a costly operation if 
the subclass
          * implements a mechanism that create IdentifiedObject instances only 
on demand.
          */
+        IdentifiedObject result = null;
+        boolean sameAxisOrder = false;
+        boolean ambiguous = false;
         try {
-            final Iterator<IdentifiedObject> it = find(object).iterator();
-            if (it.hasNext()) {
-                final IdentifiedObject candidate = it.next();
-                if (!it.hasNext()) {
-                    return candidate;
+            for (final IdentifiedObject candidate : find(object)) {
+                final boolean so = !ignoreAxes || 
Utilities.deepEquals(candidate, object, COMPARISON_MODE);
+                if (result != null) {
+                    ambiguous = true;
+                    if (sameAxisOrder && so) {
+                        return null;            // Found two matches even when 
taking in account axis order.
+                    }
                 }
+                result = candidate;
+                sameAxisOrder = so;
             }
         } catch (BackingStoreException e) {
             throw e.unwrapOrRethrow(FactoryException.class);
         }
-        return null;
+        return (sameAxisOrder || !ambiguous) ? result : null;
     }
 
     /**

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/factory/sql/EPSGDataAccess.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -1435,13 +1435,14 @@ addURIs:    for (int i=0; ; i++) {
                                  * may be recreated every time a deprecated 
ProjectedCRS is created, we temporarily
                                  * shutdown the loggings in order to avoid the 
same warning to be logged many time.
                                  */
+                                final boolean old = quiet;
                                 try {
                                     quiet = true;
                                     replaceDeprecatedCS = true;
                                     baseCRS = 
createCoordinateReferenceSystem(geoCode);         // Do not cache that CRS.
                                 } finally {
                                     replaceDeprecatedCS = false;
-                                    quiet = false;
+                                    quiet = old;
                                 }
                                 /*
                                  * The crsFactory method calls will indirectly 
create a parameterized MathTransform.

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/AbstractCoordinateOperation.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -929,6 +929,7 @@ check:      for (int isTarget=0; ; isTar
                     return type;
                 }
             });
+            formatter.newLine();
         }
     }
 

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationFinder.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -581,8 +581,9 @@ public class CoordinateOperationFinder e
         if (!(interpolationCS instanceof EllipsoidalCS)) {
             final EllipsoidalCS cs = 
CommonCRS.WGS84.geographic3D().getCoordinateSystem();
             if (!equalsIgnoreMetadata(interpolationCS, cs)) {
-                step1 = createOperation(sourceCRS, factorySIS.getCRSFactory()
-                        .createGeographicCRS(derivedFrom(sourceCRS), 
sourceCRS.getDatum(), cs));
+                final GeographicCRS stepCRS = factorySIS.getCRSFactory()
+                        .createGeographicCRS(derivedFrom(sourceCRS), 
sourceCRS.getDatum(), cs);
+                step1 = createOperation(sourceCRS, 
toAuthorityDefinition(GeographicCRS.class, stepCRS));
                 interpolationCRS = step1.getTargetCRS();
                 interpolationCS  = interpolationCRS.getCoordinateSystem();
             }
@@ -611,12 +612,13 @@ public class CoordinateOperationFinder e
             heightCS  = heightCRS.getCoordinateSystem();
             isEllipsoidalHeight = equalsIgnoreMetadata(heightCS.getAxis(0), 
expectedAxis);
             if (!isEllipsoidalHeight) {
-                heightCS = 
factorySIS.getCSFactory().createVerticalCS(derivedFrom(heightCS), expectedAxis);
+                heightCS = toAuthorityDefinition(VerticalCS.class, 
factorySIS.getCSFactory()
+                        .createVerticalCS(derivedFrom(heightCS), 
expectedAxis));
             }
         }
         if (!isEllipsoidalHeight) {                     // 'false' if we need 
to change datum, unit or axis direction.
-            heightCRS = factorySIS.getCRSFactory()
-                    .createVerticalCRS(derivedFrom(heightCRS), 
CommonCRS.Vertical.ELLIPSOIDAL.datum(), heightCS);
+            heightCRS = toAuthorityDefinition(VerticalCRS.class, 
factorySIS.getCRSFactory()
+                    .createVerticalCRS(derivedFrom(heightCRS), 
CommonCRS.Vertical.ELLIPSOIDAL.datum(), heightCS));
         }
         if (heightCRS != targetCRS) {
             step3     = createOperation(heightCRS, targetCRS);  // May need 
interpolationCRS for performing datum change.
@@ -787,7 +789,8 @@ public class CoordinateOperationFinder e
             if (stepComponents.length == 1) {
                 stepSourceCRS = stepComponents[0];    // Slight optimization 
of the next block (in the 'else' case).
             } else {
-                stepSourceCRS = 
factorySIS.getCRSFactory().createCompoundCRS(derivedFrom(sourceCRS), 
stepComponents);
+                stepSourceCRS = 
toAuthorityDefinition(CoordinateReferenceSystem.class,
+                        
factorySIS.getCRSFactory().createCompoundCRS(derivedFrom(sourceCRS), 
stepComponents));
             }
             operation = createFromAffineTransform(AXIS_CHANGES, sourceCRS, 
stepSourceCRS, select);
         }
@@ -818,8 +821,8 @@ public class CoordinateOperationFinder e
             } else if (stepComponents.length == 1) {
                 stepTargetCRS = target;                 // Slight optimization 
of the next block.
             } else {
-                stepTargetCRS = 
ReferencingServices.getInstance().createCompoundCRS(
-                        factorySIS.getCRSFactory(), factorySIS.getCSFactory(), 
derivedFrom(target), stepComponents);
+                stepTargetCRS = 
toAuthorityDefinition(CoordinateReferenceSystem.class, 
ReferencingServices.getInstance()
+                        .createCompoundCRS(factorySIS.getCRSFactory(), 
factorySIS.getCSFactory(), derivedFrom(target), stepComponents));
             }
             int delta = source.getCoordinateSystem().getDimension();
             final int startAtDimension = endAtDimension;

Modified: 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
URL: 
http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java?rev=1740892&r1=1740891&r2=1740892&view=diff
==============================================================================
--- 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
 [UTF-8] (original)
+++ 
sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/CoordinateOperationRegistry.java
 [UTF-8] Mon Apr 25 20:30:40 2016
@@ -55,6 +55,7 @@ import org.apache.sis.referencing.factor
 import org.apache.sis.referencing.factory.GeodeticAuthorityFactory;
 import org.apache.sis.referencing.factory.MissingFactoryResourceException;
 import org.apache.sis.referencing.factory.InvalidGeodeticParameterException;
+import org.apache.sis.referencing.factory.NoSuchAuthorityFactoryException;
 import org.apache.sis.metadata.iso.extent.Extents;
 import org.apache.sis.internal.referencing.CoordinateOperations;
 import org.apache.sis.internal.referencing.PositionalAccuracyConstant;
@@ -151,7 +152,8 @@ class CoordinateOperationRegistry {
     }
 
     /**
-     * The object to use for finding authority codes.
+     * The object to use for finding authority codes, or {@code null} if none.
+     * An instance is fetched at construction time from the {@link #registry} 
if possible.
      */
     private final IdentifiedObjectFinder codeFinder;
 
@@ -213,17 +215,21 @@ class CoordinateOperationRegistry {
         this.factory  = factory;
         factorySIS    = (factory instanceof DefaultCoordinateOperationFactory)
                         ? (DefaultCoordinateOperationFactory) factory : 
CoordinateOperations.factory();
+        IdentifiedObjectFinder codeFinder = null;
         if (registry != null) {
             if (registry instanceof GeodeticAuthorityFactory) {
                 codeFinder = ((GeodeticAuthorityFactory) 
registry).newIdentifiedObjectFinder();
-            } else {
+            } else try {
                 codeFinder = 
IdentifiedObjects.newFinder(Citations.getIdentifier(registry.getAuthority(), 
false));
+            } catch (NoSuchAuthorityFactoryException e) {
+                
Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
+                        CoordinateOperationRegistry.class, "<init>", e);
+            }
+            if (codeFinder != null) {
+                codeFinder.setIgnoringAxes(true);
             }
-            
codeFinder.setSearchDomain(IdentifiedObjectFinder.Domain.ALL_DATASET);
-            codeFinder.setIgnoringAxes(true);
-        } else {
-            codeFinder = null;
         }
+        this.codeFinder = codeFinder;
         if (context != null) {
             areaOfInterest  = context.getAreaOfInterest();
             desiredAccuracy = context.getDesiredAccuracy();
@@ -232,12 +238,36 @@ class CoordinateOperationRegistry {
     }
 
     /**
+     * If the authority defines an object equal, ignoring metadata, to the 
given object, returns that authority object.
+     * Otherwise returns the given object unchanged. We do not invoke this 
method for user-supplied CRS, but only for
+     * CRS or other objects created by {@code CoordinateOperationRegistry} as 
intermediate step.
+     */
+    final <T extends IdentifiedObject> T toAuthorityDefinition(final Class<T> 
type, final T object) throws FactoryException {
+        if (codeFinder != null) {
+            codeFinder.setIgnoringAxes(false);
+            final IdentifiedObject candidate = 
codeFinder.findSingleton(object);
+            codeFinder.setIgnoringAxes(true);
+            if (Utilities.equalsIgnoreMetadata(object, candidate)) {
+                return type.cast(candidate);
+            }
+        }
+        return object;
+    }
+
+    /**
      * Finds the authority code for the given coordinate reference system.
      * This method does not trust the code given by the user in its CRS - we 
verify it.
+     * This method may return a code even if the axis order does not match;
+     * it will be caller's responsibility to make necessary adjustments.
      */
     private String findCode(final CoordinateReferenceSystem crs) throws 
FactoryException {
-        final Identifier identifier = 
IdentifiedObjects.getIdentifier(codeFinder.findSingleton(crs), null);
-        return (identifier != null) ? identifier.getCode() : null;
+        if (codeFinder != null) {
+            final Identifier identifier = 
IdentifiedObjects.getIdentifier(codeFinder.findSingleton(crs), null);
+            if (identifier != null) {
+                return identifier.getCode();
+            }
+        }
+        return null;
     }
 
     /**
@@ -410,7 +440,7 @@ class CoordinateOperationRegistry {
                 } catch (NoninvertibleTransformException exception) {
                     // It may be a normal failure - the operation is not 
required to be invertible.
                     
Logging.recoverableException(Logging.getLogger(Loggers.COORDINATE_OPERATION),
-                            CoordinateOperationRegistry.class, "search", 
exception);
+                            CoordinateOperationRegistry.class, 
"createOperation", exception);
                     continue;
                 }
             } catch (MissingFactoryResourceException e) {
@@ -872,10 +902,11 @@ class CoordinateOperationRegistry {
                 return candidate;               // Keep the existing instance 
since it may contain useful metadata.
             }
         }
-        return ReferencingServices.getInstance().createCompoundCRS(
-                factorySIS.getCRSFactory(),
-                factorySIS.getCSFactory(),
-                derivedFrom(crs), crs, CommonCRS.Vertical.ELLIPSOIDAL.crs());
+        return toAuthorityDefinition(CoordinateReferenceSystem.class,
+                ReferencingServices.getInstance().createCompoundCRS(
+                        factorySIS.getCRSFactory(),
+                        factorySIS.getCSFactory(),
+                        derivedFrom(crs), crs, 
CommonCRS.Vertical.ELLIPSOIDAL.crs()));
     }
 
     /**



Reply via email to