sis-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From desruisse...@apache.org
Subject svn commit: r1672288 [2/3] - in /sis/trunk: ./ core/sis-metadata/src/main/java/org/apache/sis/internal/metadata/ core/sis-metadata/src/main/java/org/apache/sis/io/wkt/ core/sis-metadata/src/main/java/org/apache/sis/metadata/iso/ core/sis-metadata/src/m...
Date Thu, 09 Apr 2015 10:52:54 GMT
Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParameters.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParameters.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParameters.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParameters.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -19,12 +19,10 @@ package org.apache.sis.parameter;
 import java.util.Map;
 import java.util.HashMap;
 import java.io.ObjectStreamException;
-import org.opengis.util.GenericName;
 import org.opengis.parameter.ParameterDescriptor;
 import org.apache.sis.referencing.NamedIdentifier;
 import org.apache.sis.internal.util.Constants;
 import org.apache.sis.internal.referencing.provider.Affine;
-import org.apache.sis.internal.referencing.provider.EPSGName;
 import org.apache.sis.metadata.iso.citation.Citations;
 
 
@@ -147,13 +145,13 @@ class MatrixParameters extends TensorPar
      * This method creates:
      *
      * <ul>
-     *   <li>The OGC name (e.g. {@code "elt_1_2"}) as primary name</li>
-     *   <li>The EPSG name (e.g. {@code "B2"}) as an alias</li>
+     *   <li>The OGC name (e.g. {@code "elt_1_2"}) as primary name.</li>
+     *   <li>The alpha-numeric name (e.g. {@code "B2"}) as an alias.</li>
      * </ul>
      *
-     * This method does <strong>not</strong> create the EPSG identifiers (e.g. EPSG:8641) because the primary name
-     * created by this method is not the EPSG name. However the {@link MatrixParametersAlphaNum} subclass uses the
-     * EPSG name as the primary name. Consequently that subclass will create the EPSG identifier.
+     * This method does <strong>not</strong> assign the alpha-numeric names to the EPSG authority in order to avoid
+     * confusion when formatting the parameters as Well Known Text (WKT). However {@link MatrixParametersAlphaNum}
+     * subclass will assign some names to the EPSG authority, as well as their identifier (e.g. EPSG:8641).
      */
     @Override
     protected ParameterDescriptor<Double> createElementDescriptor(final int[] indices) throws IllegalArgumentException {
@@ -162,13 +160,8 @@ class MatrixParameters extends TensorPar
                 new NamedIdentifier(Citations.OGC, Constants.OGC, indicesToName(indices), null, null));
         final String c = indicesToAlias(indices);
         if (c != null) {
-            final GenericName alias;
-            if (isEPSG(indices)) {
-                alias = EPSGName.create(c);
-            } else {
-                alias = new NamedIdentifier(Citations.SIS, Constants.SIS, c, null, null);
-            }
-            properties.put(ParameterDescriptor.ALIAS_KEY, alias);
+            properties.put(ParameterDescriptor.ALIAS_KEY,
+                    new NamedIdentifier(Citations.SIS, Constants.SIS, c, null, null));
         }
         return new DefaultParameterDescriptor<Double>(properties, 0, 1, Double.class, null, null, getDefaultValue(indices));
     }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParametersAlphaNum.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParametersAlphaNum.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParametersAlphaNum.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/MatrixParametersAlphaNum.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -95,7 +95,7 @@ final class MatrixParametersAlphaNum ext
             throw new AssertionError();
         }
         final ParameterDescriptor<Double> wkt = WKT1.getElementDescriptor(indices);   // Really 'WKT1', not 'super'.
-        final GenericName name = first(wkt.getAlias());
+        GenericName name = first(wkt.getAlias());
         if (name == null) {
             /*
              * Outside the range of names (e.g. more than 26 rows or more than 10 columns).
@@ -104,15 +104,16 @@ final class MatrixParametersAlphaNum ext
             return wkt;
         }
         final Map<String,Object> properties = new HashMap<String,Object>(6);
-        properties.put(ParameterDescriptor.NAME_KEY, first(wkt.getAlias()));
-        properties.put(ParameterDescriptor.ALIAS_KEY, wkt.getName());
         /*
          * Declare the EPSG identifier only for A0, A1, A2, B0, B1 and B2.
          */
         if (isEPSG(indices)) {
+            name = EPSGName.create(name.tip().toString()); // Put the name in EPSG namespace.
             final int code = (indices[0] == 0 ? Constants.A0 : Constants.B0) + indices[1];
             properties.put(ParameterDescriptor.IDENTIFIERS_KEY, EPSGName.identifier(code));
         }
+        properties.put(ParameterDescriptor.NAME_KEY, name);
+        properties.put(ParameterDescriptor.ALIAS_KEY, wkt.getName());
         return new DefaultParameterDescriptor<Double>(properties, 0, 1, Double.class, null, null, wkt.getDefaultValue());
     }
 

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterBuilder.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -70,7 +70,7 @@ import static org.apache.sis.util.Argume
  *
  * {@preformat java
  *   ParameterBuilder builder = new ParameterBuilder();
- *   builder.setCodeSpace(Citations.OGP, "EPSG")                    // The default namespace to be used below.
+ *   builder.setCodeSpace(Citations.EPSG, "EPSG")                   // The default namespace to be used below.
  *          .setRequired(true);                                     // All parameters will be considered mandatory.
  *
  *   // Constructs the list of parameters.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/ParameterTableRow.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -39,6 +39,7 @@ import org.opengis.referencing.Reference
 import org.apache.sis.io.wkt.Colors;
 import org.apache.sis.io.wkt.ElementKind;
 import org.apache.sis.util.Characters;
+import org.apache.sis.util.Deprecable;
 import org.apache.sis.measure.Range;
 import org.apache.sis.measure.RangeFormat;
 import org.apache.sis.internal.metadata.NameToIdentifier;
@@ -149,20 +150,22 @@ final class ParameterTableRow {
             final Collection<GenericName> aliases = object.getAlias();
             if (aliases != null) { // Paranoiac check.
                 for (GenericName alias : aliases) {
-                    String codespace = NameToIdentifier.getCodeSpace(alias, locale);
-                    if (codespace != null) {
-                        alias = alias.tip();
-                    } else {
-                        final NameSpace scope = alias.scope();
-                        if (scope != null && !scope.isGlobal()) {
-                            codespace = NameToIdentifier.toString(scope.name().tip(), locale);
+                    if (!isDeprecated(alias)) {
+                        String codespace = NameToIdentifier.getCodeSpace(alias, locale);
+                        if (codespace != null) {
+                            alias = alias.tip();
+                        } else {
+                            final NameSpace scope = alias.scope();
+                            if (scope != null && !scope.isGlobal()) {
+                                codespace = NameToIdentifier.toString(scope.name().tip(), locale);
+                            }
                         }
-                    }
-                    if (preferredCodespaces == null || preferredCodespaces.contains(codespace)) {
-                        addIdentifier(codespace, NameToIdentifier.toString(alias, locale));
-                        name = null;
-                        if (isBrief) {
-                            break;
+                        if (preferredCodespaces == null || preferredCodespaces.contains(codespace)) {
+                            addIdentifier(codespace, NameToIdentifier.toString(alias, locale));
+                            name = null;
+                            if (isBrief) {
+                                break;
+                            }
                         }
                     }
                 }
@@ -182,9 +185,11 @@ final class ParameterTableRow {
             final Collection<? extends ReferenceIdentifier> ids = object.getIdentifiers();
             if (ids != null) { // Paranoiac check.
                 for (final ReferenceIdentifier id : ids) {
-                    final String codespace = id.getCodeSpace();
-                    if (preferredCodespaces == null || preferredCodespaces.contains(codespace)) {
-                        addIdentifier(codespace, id); // No .getCode() here.
+                    if (!isDeprecated(id)) {
+                        final String codespace = id.getCodeSpace();
+                        if (preferredCodespaces == null || preferredCodespaces.contains(codespace)) {
+                            addIdentifier(codespace, id); // No .getCode() here.
+                        }
                     }
                 }
             }
@@ -201,6 +206,13 @@ final class ParameterTableRow {
     }
 
     /**
+     * Returns {@code true} if the given name or identifier is deprecated.
+     */
+    private static boolean isDeprecated(final Object object) {
+        return (object instanceof Deprecable) && ((Deprecable) object).isDeprecated();
+    }
+
+    /**
      * Helper method for the constructor only, adding an identifier for the given code space.
      * As a side effect, this method remembers the length of the widest code space.
      */

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/Parameters.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -343,23 +343,32 @@ public abstract class Parameters impleme
          * was created from an EPSG database, then we want to use the EPSG names instead than the OGC names.
          */
         final String name = getName(parameter);
-        if (parameter.getMinimumOccurs() == 0) {
-            /*
-             * The parameter is optional. We do not want to invoke 'parameter(name)' because we do not want
-             * to create a new parameter if the user did not supplied one.  We search the parameter ourself
-             * (so we don't create any) and return null if we do not find any.
-             *
-             * If we find a parameter,  we can return it directly only if this object is an instance of a known
-             * implementation (currently DefaultParameterValueGroup only), otherwise we do not know if the user
-             * overrode the 'parameter' method  (we do not use Class.getMethod(...).getDeclaringClass() because
-             * it is presumed not worth the cost).  In case of doubt, we delegate to 'parameter(name)'.
-             */
-            final ParameterValue<?> value = parameterIfExist(name);
-            if (value == null || getClass() == DefaultParameterValueGroup.class) {
-                return value;
-            }
+        /*
+         * We do not want to invoke 'parameter(name)' because we do not want to create a new parameter
+         * if the user did not supplied one.  We search the parameter ourself (so we don't create any)
+         * and return null if we do not find any.
+         *
+         * If we find a parameter, we can return it directly only if this object is an instance of a known
+         * implementation (currently DefaultParameterValueGroup and MapProjectionParameters), otherwise we
+         * do not know if the user overrode the 'parameter' method in a way incompatible with this method.
+         * We do not use Class.getMethod(…).getDeclaringClass() because it is presumed not worth the cost.
+         * In case of doubt, we delegate to 'parameter(name)'.
+         */
+        final ParameterValue<?> value = parameterIfExist(name);
+        if (value == null || isKnownImplementation()) {
+            return value;
+        } else {
+            return parameter(name);
         }
-        return parameter(name);
+    }
+
+    /**
+     * Returns {@code true} if this class is an implementation of an instance which is known to not override
+     * {@link #parameter(String)} in a way incompatible with {@link #parameterIfExist(String)}.
+     * The {@link DefaultParameterValueGroup} class needs to override this method.
+     */
+    boolean isKnownImplementation() {
+        return false;
     }
 
     /**

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/parameter/TensorValues.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -35,7 +35,6 @@ import org.apache.sis.referencing.operat
 import org.apache.sis.internal.referencing.WKTUtilities;
 import org.apache.sis.internal.util.Numerics;
 import org.apache.sis.internal.util.UnmodifiableArrayList;
-import org.apache.sis.io.wkt.ElementKind;
 import org.apache.sis.io.wkt.Formatter;
 import org.apache.sis.util.Utilities;
 import org.apache.sis.util.Classes;
@@ -465,8 +464,7 @@ final class TensorValues<E> extends Abst
      */
     @Override
     protected String formatTo(final Formatter formatter) {
-        WKTUtilities.appendName(this, formatter, ElementKind.PARAMETER);
-        WKTUtilities.append(this, formatter);
+        WKTUtilities.appendParamMT(this, formatter);
         return "ParameterGroup";
     }
 }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/Builder.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -32,6 +32,7 @@ import org.opengis.referencing.Reference
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.internal.system.DefaultFactories;
 import org.apache.sis.internal.util.Citations;
+import org.apache.sis.util.Deprecable;
 import org.apache.sis.util.resources.Errors;
 
 import static org.apache.sis.util.ArgumentChecks.ensureNonNull;
@@ -112,7 +113,7 @@ import org.apache.sis.internal.jdk8.JDK8
  * If we choose EPSG as our primary naming authority, then those three names can be declared as below:
  *
  * {@preformat java
- *   builder.setCodespace (Citations.OGP, "EPSG")
+ *   builder.setCodespace (Citations.EPSG, "EPSG")
  *          .addName("Mercator (variant A)")
  *          .addName("Mercator (1SP)")
  *          .addName(Citations.OGC, "Mercator_1SP")
@@ -265,6 +266,64 @@ public abstract class Builder<B extends
     }
 
     /**
+     * Returns the name factory to use for creating namespaces and local names.
+     * The factory will be fetched when first needed, and while not change anymore
+     * for the rest of this {@code Builder} lifetime.
+     */
+    private NameFactory factory() {
+        if (nameFactory == null) {
+            nameFactory = DefaultFactories.forBuildin(NameFactory.class);
+        }
+        return nameFactory;
+    }
+
+    /**
+     * Creates or returns an existing name for the given string in the current namespace.
+     * The namespace may be cleared at anytime by a call to {@link #setCodeSpace(Citation, String)}.
+     */
+    private GenericName createName(final CharSequence name) {
+        final NameFactory factory = factory();
+        if (namespace == null) {
+            final String codespace = getCodeSpace();
+            if (codespace != null) {
+                namespace = factory.createNameSpace(factory.createLocalName(null, codespace), null);
+            }
+        }
+        return factory.createLocalName(namespace, name);
+    }
+
+    /**
+     * Creates or returns an existing name for the given string in the given namespace.
+     */
+    private GenericName createName(final Citation authority, final CharSequence name) {
+        if (authority == getAuthority()) {
+            return createName(name);
+        } else {
+            return new NamedIdentifier(authority, name);
+        }
+    }
+
+    /**
+     * Creates an identifier from a string for the given authority.
+     */
+    private ReferenceIdentifier createIdentifier(final Citation authority, final String identifier) {
+        if (authority == getAuthority()) {
+            return new ImmutableIdentifier(authority, getCodeSpace(), identifier, getVersion(), null);
+        } else {
+            // Do not use the version information since it applies to the default authority rather than the given one.
+            return new ImmutableIdentifier(authority, Citations.getUnicodeIdentifier(authority), identifier);
+        }
+    }
+
+    /**
+     * Converts the given name into an identifier. Note that {@link NamedIdentifier}
+     * implements both {@link GenericName} and {@link Identifier} interfaces.
+     */
+    private static ReferenceIdentifier toIdentifier(final GenericName name) {
+        return (name instanceof ReferenceIdentifier) ? (ReferenceIdentifier) name : new NamedIdentifier(name);
+    }
+
+    /**
      * Sets the property value for the given key, if a change is still possible. The check for change permission
      * is needed for all keys defined in the {@link Identifier} interface. This check is not needed for other keys,
      * so callers do not need to invoke this method for other keys.
@@ -289,30 +348,6 @@ public abstract class Builder<B extends
     }
 
     /**
-     * Returns the name factory to use for creating namespaces and local names.
-     */
-    private NameFactory factory() {
-        if (nameFactory == null) {
-            nameFactory = DefaultFactories.forBuildin(NameFactory.class);
-        }
-        return nameFactory;
-    }
-
-    /**
-     * Returns the namespace, creating it when first needed.
-     */
-    private NameSpace namespace() {
-        if (namespace == null) {
-            final String codespace = getCodeSpace();
-            if (codespace != null) {
-                final NameFactory factory = factory();
-                namespace = factory.createNameSpace(factory.createLocalName(null, codespace), null);
-            }
-        }
-        return namespace;
-    }
-
-    /**
      * Returns the value of the first argument given by the last call to {@link #setCodeSpace(Citation, String)},
      * or {@code null} if none. The default value is {@code null}.
      *
@@ -341,7 +376,7 @@ public abstract class Builder<B extends
      * The code space is often the authority's abbreviation, but not necessarily.
      *
      * <div class="note"><b>Example:</b> Coordinate Reference System (CRS) objects identified by codes from the
-     * EPSG database are maintained by the {@linkplain org.apache.sis.metadata.iso.citation.Citations#OGP OGP}
+     * EPSG database are maintained by the <cite>International Association of Oil &amp; Gas producers</cite> (IOGP)
      * authority, but the code space is {@code "EPSG"} for historical reasons.</div>
      *
      * This method is typically invoked only once, since a compound object often uses the same code space
@@ -427,7 +462,7 @@ public abstract class Builder<B extends
         ensureNonNull("name", name);
         if (JDK8.putIfAbsent(properties, IdentifiedObject.NAME_KEY, name.toString()) != null) {
             // A primary name is already present. Add the given name as an alias instead.
-            aliases.add(name instanceof GenericName ? (GenericName) name : factory().createLocalName(namespace(), name));
+            aliases.add(createName(name));
         }
         return self();
     }
@@ -441,7 +476,7 @@ public abstract class Builder<B extends
      * by OGC and GeoTIFF. Those alternative names can be defined as below:
      *
      * {@preformat java
-     *   builder.setCodespace(Citations.OGP, "EPSG")           // Sets the default namespace to "EPSG".
+     *   builder.setCodespace(Citations.EPSG, "EPSG")          // Sets the default namespace to "EPSG".
      *          .addName("Longitude of natural origin")        // Primary name in builder default namespace.
      *          .addName(Citations.OGC, "central_meridian")    // First alias in "OGC" namespace.
      *          .addName(Citations.GEOTIFF, "NatOriginLong");  // Second alias in "GeoTIFF" namespace.
@@ -516,7 +551,7 @@ public abstract class Builder<B extends
     public B addName(final GenericName name) {
         ensureNonNull("name", name);
         if (properties.get(IdentifiedObject.NAME_KEY) == null) {
-            properties.put(IdentifiedObject.NAME_KEY, (name instanceof Identifier) ? name : new NamedIdentifier(name));
+            properties.put(IdentifiedObject.NAME_KEY, toIdentifier(name));
         } else {
             aliases.add(name);
         }
@@ -581,8 +616,7 @@ public abstract class Builder<B extends
      */
     public B addIdentifier(final Citation authority, final String identifier) {
         ensureNonNull("identifier", identifier);
-        // Do not use the version information since it applies to the default authority rather than the given one.
-        identifiers.add(new ImmutableIdentifier(authority, Citations.getUnicodeIdentifier(authority), identifier));
+        identifiers.add(createIdentifier(authority, identifier));
         return self();
     }
 
@@ -628,6 +662,130 @@ public abstract class Builder<B extends
         return self();
     }
 
+    /**
+     * Returns {@code true} if the given name or identifier is deprecated.
+     */
+    private static boolean isDeprecated(final Object object) {
+        return (object instanceof Deprecable) && ((Deprecable) object).isDeprecated();
+    }
+
+    /**
+     * Adds all non-deprecated names and identifiers from the given object.
+     * Other properties like description and remarks are ignored.
+     *
+     * <p>This is a convenience method for using an existing object as a template, before to modify
+     * some names by calls to {@link #rename(Citation, CharSequence[])}.</p>
+     *
+     * @param  object The object from which to copy the references to names and identifiers.
+     * @return {@code this}, for method call chaining.
+     *
+     * @since 0.6
+     */
+    public B addNamesAndIdentifiers(final IdentifiedObject object) {
+        ensureNonNull("object", object);
+        for (final ReferenceIdentifier id : object.getIdentifiers()) {
+            if (!isDeprecated(id)) {
+                addIdentifier(id);
+            }
+        }
+        ReferenceIdentifier id = object.getName();
+        if (!isDeprecated(id)) {
+            addName(id);
+        }
+        for (final GenericName alias : object.getAlias()) {
+            if (!isDeprecated(alias)) {
+                addName(alias);
+            }
+        }
+        return self();
+    }
+
+    /**
+     * Replaces the names associated to the given authority by the given new names.
+     * More specifically:
+     *
+     * <ul>
+     *   <li>The first occurrence of a name associated to {@code authority} will be replaced by a new name
+     *       with the same authority and the local part defined by {@code replacements[0]}.</li>
+     *   <li>The second occurrence of a name associated to {@code authority} will be replaced by a new name
+     *       with the same authority and the local part defined by {@code replacements[1]}.</li>
+     *   <li><i>etc.</i> until one of the following conditions is meet:
+     *     <ul>
+     *       <li>There is no more name associated to the given authority in this {@code Builder}, in which case
+     *           new names are inserted for all remaining elements in the {@code replacements} array.</li>
+     *       <li>There is no more elements in the {@code replacements} array, in which case all remaining
+     *           names associated to the given authority in this {@code Builder} are removed.</li>
+     *     </ul>
+     *   </li>
+     * </ul>
+     *
+     * @param  authority The authority of the names to replaces.
+     * @param  replacements The new local parts for the names to replace,
+     *         or {@code null} for removing all identifiers associated to the given authority.
+     * @return {@code this}, for method call chaining.
+     *
+     * @since 0.6
+     */
+    public B rename(final Citation authority, final CharSequence... replacements) {
+        ensureNonNull("authority", authority);
+        final int length = (replacements != null) ? replacements.length : 0;
+        /*
+         * IdentifiedObjects store the "primary name" separately from aliases. Consequently we will start
+         * the iteration at index -1 where i=-1 is used as a sentinel value meaning "primary name" before
+         * to iterate over the aliases. Note that the type is not the same:
+         *
+         *   - Primary:   Identifier or String
+         *   - Aliases:   Identifier or GenericName
+         */
+        int next = 0;
+        int insertAt = aliases.size();
+        for (int i = -1; i < aliases.size(); i++) {
+            final Object name = (i < 0) ? properties.get(IdentifiedObject.NAME_KEY) : aliases.get(i);
+            if (name != null) {  // Actually only the primary name can be null.
+                final boolean isIdentifier = (name instanceof Identifier);
+                if (authority.equals(isIdentifier ? ((Identifier) name).getAuthority() : getAuthority())) {
+                    /*
+                     * Found a name associated to the given authority. Process to the replacement if we still
+                     * have some elements to take in the 'replacements' array, otherwise remove the name.
+                     */
+                    if (next < length) {
+                        final CharSequence code = replacements[next++];
+                        if (!code.toString().equals(isIdentifier ? ((Identifier) name).getCode() : name.toString())) {
+                            if (i < 0) {
+                                properties.put(IdentifiedObject.NAME_KEY, (authority != getAuthority())
+                                        ? new NamedIdentifier(authority, code) : code.toString());
+                            } else {
+                                aliases.set(i, createName(authority, code));
+                            }
+                            insertAt = i + 1;
+                        }
+                    } else {
+                        if (i < 0) {
+                            properties.remove(IdentifiedObject.NAME_KEY);
+                        } else {
+                            aliases.remove(i--);
+                        }
+                    }
+                }
+            }
+        }
+        /*
+         * If there is any remaining elements in the 'replacements' array, insert them right after the last
+         * element of the given authority that we found (so we keep together the names of the same authority).
+         */
+        while (next < length) {
+            aliases.add(insertAt++, createName(authority, replacements[next++]));
+        }
+        /*
+         * If the primary name has been removed as a result of this method execution,
+         * take the first alias as the new primary name.
+         */
+        if (properties.get(IdentifiedObject.NAME_KEY) == null && !aliases.isEmpty()) {
+            properties.put(IdentifiedObject.NAME_KEY, toIdentifier(aliases.remove(0)));
+        }
+        return self();
+    }
+
     /**
      * Sets the parameter description as a {@code String} or {@code InternationalString} instance.
      * Calls to this method overwrite any previous value.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/NamedIdentifier.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -75,9 +75,10 @@ import org.apache.sis.internal.jdk7.Obje
  * </ul>
  *
  * <div class="note"><b>Example:</b>
- * If the identifier attributes are {@code authority} = {@link Citations#OGP}, {@code codeSpace} = {@code "EPSG"}
- * and {@code code} = {@code "4326"}, then the name attributes will be {@code scope} = {@code "OGP"},
- * {@code head} = {@code "EPSG"}, {@code tip} = {@code "4326"} and {@link #toString()} = {@code "EPSG:4326"}.
+ * If the identifier attributes are {@code authority} = {@code new DefaultCitation("IOGP")},
+ * {@code codeSpace} = {@code "EPSG"} and {@code code} = {@code "4326"}, then the name attributes will be
+ * {@code scope} = {@code "IOGP"}, {@code head} = {@code "EPSG"}, {@code tip} = {@code "4326"} and
+ * {@link #toString()} = {@code "EPSG:4326"}.
  * Note that the scope does not appear in the string representation of names.</div>
  *
  *

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/crs/DefaultGeographicCRS.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -266,7 +266,7 @@ public class DefaultGeographicCRS extend
      *      Area["World"],
      *      BBox[-90.00, -180.00, 90.00, 180.00],
      *      Scope["Used by GPS satellite navigation system."]
-     *      Id["EPSG", 4326, Citation["OGP"], URI["urn:ogc:def:crs:EPSG::4326"]]]
+     *      Id["EPSG", 4326, Citation["IOGP"], URI["urn:ogc:def:crs:EPSG::4326"]]]
      * }
      *
      * <p>Same coordinate reference system using WKT 1.</p>

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/datum/DefaultGeodeticDatum.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -518,7 +518,7 @@ public class DefaultGeodeticDatum extend
      * {@preformat wkt
      *      Datum["World Geodetic System 1984",
      *        Ellipsoid["WGS84", 6378137.0, 298.257223563, LengthUnit["metre", 1]],
-     *      Id["EPSG", 6326, Citation["OGP"], URI["urn:ogc:def:datum:EPSG::6326"]]]
+     *      Id["EPSG", 6326, Citation["IOGP"], URI["urn:ogc:def:datum:EPSG::6326"]]]
      * }
      *
      * <p>Same datum using WKT 1.</p>

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/Mercator.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -17,30 +17,31 @@
 package org.apache.sis.referencing.operation.projection;
 
 import org.opengis.util.FactoryException;
-import org.opengis.parameter.ParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.operation.Matrix;
 import org.opengis.referencing.operation.MathTransform;
 import org.opengis.referencing.operation.MathTransformFactory;
 import org.opengis.referencing.operation.OperationMethod;
 import org.opengis.referencing.operation.TransformException;
+import org.apache.sis.internal.referencing.provider.AbstractMercator;
+import org.apache.sis.internal.referencing.provider.Mercator1SP;
 import org.apache.sis.internal.referencing.provider.Mercator2SP;
-import org.apache.sis.internal.referencing.provider.PseudoMercator;
+import org.apache.sis.internal.referencing.provider.MercatorSpherical;
+import org.apache.sis.internal.referencing.provider.RegionalMercator;
 import org.apache.sis.internal.referencing.provider.MillerCylindrical;
-import org.apache.sis.internal.referencing.Formulas;
+import org.apache.sis.internal.referencing.provider.PseudoMercator;
 import org.apache.sis.internal.util.DoubleDouble;
 import org.apache.sis.referencing.operation.matrix.MatrixSIS;
 import org.apache.sis.referencing.operation.matrix.Matrix2;
-import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.parameter.Parameters;
-import org.apache.sis.util.resources.Errors;
+import org.apache.sis.util.Workaround;
 
 import static java.lang.Math.*;
 import static java.lang.Double.*;
 
 
 /**
- * <cite>Mercator Cylindrical</cite> projection (EPSG codes 9804, 9805, 1026, 1024, <span class="deprecated">9841</span>).
+ * <cite>Mercator Cylindrical</cite> projection (EPSG codes 9804, 9805, 1026, 1024, 1044, <span class="deprecated">9841</span>).
  * See the <a href="http://mathworld.wolfram.com/MercatorProjection.html">Mercator projection on MathWorld</a> for an overview.
  *
  * <div class="section">Description</div>
@@ -80,19 +81,28 @@ public class Mercator extends Normalized
     private static final long serialVersionUID = 2564172914329253286L;
 
     /**
-     * Same parameter than {@link Mercator2SP#STANDARD_PARALLEL}, but declared as optional
-     * for allowing this class to process <cite>"Mercator (variant A)"</cite> parameters.
-     */
-    private static final ParameterDescriptor<Double> STANDARD_PARALLEL = makeOptional(Mercator2SP.STANDARD_PARALLEL);
-
-    /**
-     * Codes for special kinds of Mercator projection.
+     * Codes for special kinds of Mercator projection. We do not provide such codes in public API because
+     * they duplicate the functionality of {@link OperationMethod} instances. We use them only for convenience.
+     *
+     * <p><b>CONVENTION:</b> Spherical cases must be odd, all other cases must be even. This allow us to perform
+     * quick checks for all spherical cases using {@code if ((type & SPHERICAL) != 0)}.</p>
      */
-    static final byte PSEUDO = 1, MILLER = 2;
+    static final byte SPHERICAL = 1, PSEUDO = 3,    // Must be odd and SPHERICAL must be 1.
+                      REGIONAL  = 2, MILLER = 4;    // Must be even.
 
     /**
-     * 0 if this projection is a standard Mercator, {@link #PSEUDO} if this projection is the "Pseudo Mercator" case.
+     * The type of Mercator projection. Possible values are:
+     * <ul>
+     *   <li>0                  if this projection is a Mercator variant A or B.</li>
+     *   <li>{@link #REGIONAL}  if this projection is the "Mercator (variant C)" case.</li>
+     *   <li>{@link #SPHERICAL} if this projection is the "Mercator (Spherical)" case.</li>
+     *   <li>{@link #PSEUDO}    if this projection is the "Pseudo Mercator" case.</li>
+     *   <li>{@link #MILLER}    if this projection is the "Miller Cylindrical" case.</li>
+     * </ul>
+     *
      * Other cases may be added in the future.
+     *
+     * @see #getType(ParameterDescriptorGroup)
      */
     final byte type;
 
@@ -103,6 +113,8 @@ public class Mercator extends Normalized
      * <ul>
      *   <li><cite>"Mercator (variant A)"</cite>, also known as <cite>"Mercator (1SP)"</cite>.</li>
      *   <li><cite>"Mercator (variant B)"</cite>, also known as <cite>"Mercator (2SP)"</cite>.</li>
+     *   <li><cite>"Mercator (variant C)"</cite>.</li>
+     *   <li><cite>"Mercator (Spherical)"</cite>.</li>
      *   <li><cite>"Popular Visualisation Pseudo Mercator"</cite>.</li>
      *   <li><cite>"Miller Cylindrical"</cite>.</li>
      * </ul>
@@ -111,34 +123,60 @@ public class Mercator extends Normalized
      * @param parameters The parameter values of the projection to create.
      */
     public Mercator(final OperationMethod method, final Parameters parameters) {
-        super(method, parameters, Mercator2SP.FALSE_EASTING, Mercator2SP.FALSE_NORTHING);
-        double φ1 = toRadians(getAndStore(parameters, STANDARD_PARALLEL));
-        double φ0 = parameters.doubleValue(Mercator2SP.LATITUDE_OF_ORIGIN);
-        double λ0 = getAndStore(parameters, Mercator2SP.CENTRAL_MERIDIAN);
-        double k0 = getAndStore(parameters, Mercator2SP.SCALE_FACTOR);
+        this(method, parameters, getType(parameters.getDescriptor()));
+    }
+
+    /**
+     * Work around for RFE #4093999 in Sun's bug database
+     * ("Relax constraint on placement of this()/super() call in constructors").
+     */
+    @Workaround(library="JDK", version="1.7")
+    private Mercator(final OperationMethod method, final Parameters parameters, final byte type) {
+        super(method, parameters,
+                (type == SPHERICAL) ? Mercator2SP     .STANDARD_PARALLEL        : null,     // See note below.
+                (type == REGIONAL ) ? RegionalMercator.EASTING_AT_FALSE_ORIGIN  : AbstractMercator.FALSE_EASTING,
+                (type == REGIONAL ) ? RegionalMercator.NORTHING_AT_FALSE_ORIGIN : AbstractMercator.FALSE_NORTHING);
         /*
-         * The "Latitude of origin" is not formally a parameter of Mercator projection, except in variant A (1SP)
-         * where the parameter is included in the EPSG dataset for completeness in CRS labelling but is not allowed
-         * to be assigned any value other than zero.
-         */
-        if (!(abs(φ0) <= Formulas.ANGULAR_TOLERANCE)) {   // Use '!' for catching NaN.
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.IllegalParameterValue_2,
-                    Mercator2SP.LATITUDE_OF_ORIGIN.getName(), φ0));
-        }
+         * Note on above Mercator2SP.STANDARD_PARALLEL argument (used for computing radius of conformal sphere):
+         * according the EPSG guide we should rather use Mercator2SP.LATITUDE_OF_ORIGIN. But the later is fixed
+         * to 0° by EPSG guide, which makes radius calculation ineffective when using the official parameters.
+         * Given that we already allow usage of Mercator2SP.STANDARD_PARALLEL (which is not an EPSG parameter)
+         * for compatibility reasons, user who set the standard parallel may expect this latitude to be used for
+         * radius calculation. Using the standard parallel instead than the latitude of origin is also consistent
+         * with what EPSG does for the Equirectangular projection. Anyway, this choice matters only when the user
+         * request explicitely spherical formulas applied on an ellipsoidal figure of the Earth, which should be
+         * very rare.
+         */
+        this.type = type;
+        /*
+         * The "Longitude of natural origin" parameter is found in all Mercator projections and is mandatory.
+         * Since this is usually the Greenwich meridian, the default value is 0°. We keep the value in degrees
+         * for now; it will be converted to radians later.
+         */
+        final double λ0 = getAndStore(parameters, Mercator1SP.CENTRAL_MERIDIAN);
         /*
-         * A correction that allows us to employ a standard parallel that is not correspondent to the equator,
-         * as described in Snyder and al. at page 47. This is the same correction factor than the one applied
-         * for the Mercator (2SP) case, constant "ko" in EPSG:9805.
+         * The "Latitude of natural origin" is not formally a parameter of Mercator projection. But the parameter
+         * is included for completeness in CRS labelling, with the restriction (specified in EPSG documentation)
+         * that the value must be zero. The EPSG dataset provides this parameter for "Mercator variant A" (1SP),
+         * but Apache SIS accepts it also for other projections because we found some Well Known Text (WKT) strings
+         * containing it.
          *
-         * The scale correction is multiplied with the global scale, which allows the Apache SIS referencing
-         * module to merge this correction with the scale factor in a single multiplication. In principle we
-         * should never have both the scale factor and a standard parallel. Nevertheless we sometime see such
-         * CRS definitions.
-         */
-        k0 *= cos(φ1);
-        if (!isSpherical()) {
-            k0 /= rν(sin(φ1));
-        }
+         * According EPSG documentation, the only exception to the above paragraph is "Mercator variant C", where
+         * the parameter is named "Latitude of false origin" and can have any value. While strictly speaking the
+         * "Latitude of origin" can not have a non-zero value, if it still have non-zero value we will process as
+         * for "Latitude of false origin".
+         */
+        final double φ0 = toRadians(getAndStore(parameters, (type == REGIONAL)
+                ? RegionalMercator.LATITUDE_OF_FALSE_ORIGIN : Mercator1SP.LATITUDE_OF_ORIGIN));
+        /*
+         * In theory, the "Latitude of 1st standard parallel" and the "Scale factor at natural origin" parameters
+         * are mutually exclusive. The former is for projections of category "2SP" (namely variant B and C) while
+         * the later is for projections "1SP" (namely variant A and spherical). However we let users specify both
+         * if they really want, since we sometime see such CRS definitions.
+         */
+        final double φ1 = toRadians(getAndStore(parameters, Mercator2SP.STANDARD_PARALLEL));
+        double k0 = getAndStore(parameters, Mercator1SP.SCALE_FACTOR);
+        k0 *= cos(φ1) / rν(sin(φ1));
         /*
          * In principle we should rotate the central meridian (λ0) in the normalization transform, as below:
          *
@@ -158,15 +196,12 @@ public class Mercator extends Normalized
             offset.multiply(-λ0);
             denormalize.concatenate(0, null, offset);
         }
-        final ParameterDescriptorGroup descriptor = parameters.getDescriptor();
-        if (IdentifiedObjects.isHeuristicMatchForName(descriptor, MillerCylindrical.NAME)) {
+        if (φ0 != 0) {
+            denormalize.concatenate(1, null, new DoubleDouble(-log(expOfNorthing(φ0, excentricity * sin(φ0)))));
+        }
+        if (type == MILLER) {
             normalize  .concatenate(1, new DoubleDouble(0.8),  null);
             denormalize.concatenate(1, new DoubleDouble(1.25), null);
-            type = MILLER;
-        } else if (IdentifiedObjects.isHeuristicMatchForName(descriptor, PseudoMercator.NAME)) {
-            type = PSEUDO;
-        } else {
-            type = 0;
         }
     }
 
@@ -179,13 +214,23 @@ public class Mercator extends Normalized
     }
 
     /**
+     * Returns the type of the projection based on the name and identifier of the given parameter group.
+     */
+    private static byte getType(final ParameterDescriptorGroup parameters) {
+        if (identMatch(parameters, RegionalMercator .NAME, RegionalMercator .IDENTIFIER)) return REGIONAL;
+        if (identMatch(parameters, MercatorSpherical.NAME, MercatorSpherical.IDENTIFIER)) return SPHERICAL;
+        if (identMatch(parameters, PseudoMercator   .NAME, PseudoMercator   .IDENTIFIER)) return PSEUDO;
+        if (identMatch(parameters, MillerCylindrical.NAME, null))                         return MILLER;
+        return 0;
+    }
+
+    /**
      * Returns the sequence of <cite>normalization</cite> → {@code this} → <cite>denormalization</cite> transforms
      * as a whole. The transform returned by this method except (<var>longitude</var>, <var>latitude</var>)
      * coordinates in <em>degrees</em> and returns (<var>x</var>,<var>y</var>) coordinates in <em>metres</em>.
      *
      * <p>The non-linear part of the returned transform will be {@code this} transform, except if the ellipsoid
-     * {@linkplain #isSpherical() is spherical}. In the later case, {@code this} transform will be replaced by
-     * a simplified implementation.</p>
+     * is spherical. In the later case, {@code this} transform will be replaced by a simplified implementation.</p>
      *
      * @param  factory The factory to use for creating the transform.
      * @return The map projection from (λ,φ) to (<var>x</var>,<var>y</var>) coordinates.
@@ -194,7 +239,7 @@ public class Mercator extends Normalized
     @Override
     public MathTransform createMapProjection(final MathTransformFactory factory) throws FactoryException {
         Mercator kernel = this;
-        if (isSpherical() || type == PSEUDO) {
+        if ((type & SPHERICAL) != 0 || excentricity == 0) {
             kernel = new Spherical(this);
         }
         return context.completeTransform(factory, kernel);
@@ -335,9 +380,6 @@ public class Mercator extends Normalized
          */
         Spherical(final Mercator other) {
             super(other);
-            if (type != PSEUDO) {
-                ensureSpherical();
-            }
         }
 
         /**
@@ -374,8 +416,9 @@ public class Mercator extends Normalized
             /*
              * Following part is common to all spherical projections: verify, store and return.
              */
-            assert (type == PSEUDO) || (Assertions.checkDerivative(derivative, super.transform(srcPts, srcOff, dstPts, dstOff, derivate))
-                    && Assertions.checkTransform(dstPts, dstOff, λ, y)); // dstPts = result from ellipsoidal formulas.
+            assert (excentricity != 0)  // Can not perform the following assertions if excentricity is not zero.
+                   || (Assertions.checkDerivative(derivative, super.transform(srcPts, srcOff, dstPts, dstOff, derivate))
+                   && Assertions.checkTransform(dstPts, dstOff, λ, y)); // dstPts = result from ellipsoidal formulas.
             if (dstPts != null) {
                 dstPts[dstOff  ] = λ;
                 dstPts[dstOff+1] = y;
@@ -427,7 +470,8 @@ public class Mercator extends Normalized
             double x = srcPts[srcOff  ];
             double y = srcPts[srcOff+1];
             y = PI/2 - 2 * atan(exp(-y));     // Part of Snyder (7-4)
-            assert (type == PSEUDO) || checkInverseTransform(srcPts, srcOff, dstPts, dstOff, x, y);
+            assert (excentricity != 0)  // Can not perform the following assertion if excentricity is not zero.
+                   || checkInverseTransform(srcPts, srcOff, dstPts, dstOff, x, y);
             dstPts[dstOff  ] = x;
             dstPts[dstOff+1] = y;
         }

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/projection/NormalizedProjection.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -34,7 +34,6 @@ import org.apache.sis.util.Debug;
 import org.apache.sis.util.ComparisonMode;
 import org.apache.sis.util.resources.Errors;
 import org.apache.sis.parameter.Parameters;
-import org.apache.sis.parameter.DefaultParameterDescriptor;
 import org.apache.sis.parameter.DefaultParameterDescriptorGroup;
 import org.apache.sis.referencing.IdentifiedObjects;
 import org.apache.sis.referencing.operation.matrix.Matrices;
@@ -51,6 +50,7 @@ import static org.apache.sis.util.Argume
 
 // Branch-dependent imports
 import org.apache.sis.internal.jdk7.Objects;
+import org.opengis.referencing.ReferenceIdentifier;
 
 
 /**
@@ -99,7 +99,7 @@ import org.apache.sis.internal.jdk7.Obje
  * org.opengis.referencing.cs.CoordinateSystem) higher level}.</div>
  *
  * {@code NormalizedProjection} does not store the above cited parameters (central meridian, scale factor, <i>etc.</i>)
- * on intend, in order to make clear that those parameters are not used by subclasses.
+ * on intend (except indirectly), in order to make clear that those parameters are not used by subclasses.
  * The ability to recognize two {@code NormalizedProjection}s as {@linkplain #equals(Object, ComparisonMode) equivalent}
  * without consideration for the scale factor (among other) allow more efficient concatenation in some cases
  * (typically some combinations of inverse projection followed by a direct projection).
@@ -189,42 +189,130 @@ public abstract class NormalizedProjecti
      * <ul>
      *   <li>On the <b>normalization</b> matrix (to be applied before {@code this} transform):
      *     <ul>
-     *       <li>Nothing. Callers shall invoke {@link ContextualParameters#normalizeGeographicInputs(double)} themselves.</li>
+     *       <li>{@linkplain ContextualParameters#normalizeGeographicInputs(double) Subtract}
+     *           the <cite>central meridian</cite> value.</li>
+     *       <li>Convert from degrees to radians.</li>
      *     </ul>
      *   </li>
      *   <li>On the <b>denormalization</b> matrix (to be applied after {@code this} transform):
      *     <ul>
      *       <li>{@linkplain ContextualParameters#scaleAndTranslate2D(boolean, double, double, double) Scale}
      *           by the <cite>semi-major</cite> axis length.</li>
-     *       <li>Translate by the false easting and false northing (after the scale).</li>
+     *       <li>Translate by the <cite>false easting</cite> and <cite>false northing</cite> (after the scale).</li>
      *     </ul>
      *   </li>
      *   <li>On the <b>contextual parameters</b> (not the parameters of {@code this} transform):
      *     <ul>
      *       <li>Store the values for <cite>semi-major</cite> axis length, <cite>semi-minor</cite> axis length,
-     *           <cite>false easting</cite> and <cite>false northing</cite>.</li>
+     *           <cite>central meridian</cite>, <cite>false easting</cite> and <cite>false northing</cite> values.</li>
      *     </ul>
      *   </li>
      * </ul>
      *
-     * @param method        Description of the map projection parameters.
-     * @param parameters    The parameters of the projection to be created.
-     * @param falseEasting  The descriptor for fetching the <cite>false easting</cite> parameter.
-     * @param falseNorthing The descriptor for fetching the <cite>false northing</cite> parameter.
+     * <div class="section">Pre-requite</div>
+     * The parameters of the given {@code method} argument shall contains descriptor for the given parameters
+     * (using OGC names):
+     * <ul>
+     *   <li>{@code "semi_major"}       (mandatory)</li>
+     *   <li>{@code "semi_minor"}       (mandatory)</li>
+     *   <li>{@code "central_meridian"} (optional, default to 0°)</li>
+     *   <li>{@code "false_easting"}    (optional, default to 0 metre)</li>
+     *   <li>{@code "false_northing"}   (optional, default to 0 metre)</li>
+     * </ul>
+     *
+     * <div class="note"><b>Note:</b>
+     * Apache SIS uses EPSG names as much as possible, but this constructor is an exception to this rule.
+     * In this particular case we use OGC names because they are identical for a wide range of projections.
+     * For example there is at least two different EPSG names for the <cite>false northing</cite> parameter,
+     * depending on the projection:
+     *
+     * <ul>
+     *   <li><cite>Northing at false origin</cite></li>
+     *   <li><cite>Northing at projection centre</cite></li>
+     * </ul>
+     *
+     * OGC defines only {@code "false_northing"} for all, which makes a convenient name to look for in this
+     * constructor.</div>
+     *
+     * @param method     Description of the map projection parameters.
+     * @param parameters The parameters of the projection to be created.
+     */
+    protected NormalizedProjection(final OperationMethod method, final Parameters parameters) {
+        this(method, parameters, null,
+                descriptor(method, Constants.FALSE_EASTING),
+                descriptor(method, Constants.FALSE_NORTHING));
+        context.normalizeGeographicInputs(getAndStore(parameters, descriptor(method, Constants.CENTRAL_MERIDIAN)));
+    }
+
+    /**
+     * Returns the parameter descriptor for the given name.
+     * This is a helper method for above constructor only.
+     */
+    private static ParameterDescriptor<Double> descriptor(final OperationMethod method, final String name) {
+        ensureNonNull("method", method);
+        return Parameters.cast((ParameterDescriptor<?>) method.getParameters().descriptor(name), Double.class);
+    }
+
+    /**
+     * Constructs a new map projection by fetching the values using the given parameter descriptors.
+     * At the difference of the {@link #NormalizedProjection(OperationMethod, Parameters)} constructor,
+     * this constructor does <strong>not</strong> apply the following operations:
+     *
+     * <ul>
+     *   <li>Normalization: no operation done. Callers shall invoke
+     *     {@link ContextualParameters#normalizeGeographicInputs(double)} themselves.</li>
+     * </ul>
+     *
+     *
+     * <div class="section">Radius of conformal sphere (Rc)</div>
+     * If the {@code conformalSphereAtφ} argument is non-null, then the radius of the conformal sphere
+     * at latitude φ will be used instead than the semi-major axis length <var>a</var> (<b>Source:</b>
+     * <cite>Geomatics Guidance Note Number 7, part 2, version 49</cite> from EPSG: table 3 in section
+     * 1.2 and explanation in section 1.3.3.1).
+     *
+     * <p><b>Important usage notes:</b><p>
+     * <ul>
+     *   <li>The {@code conformalSphereAtφ} argument shall be non-null <strong>only</strong> when the user
+     *       requested explicitely spherical formulas, for example the <cite>"Mercator (Spherical)"</cite>
+     *       projection (EPSG:1026), but the figure of the Earth is an ellipsoid rather than a sphere.</li>
+     *   <li>This parameter value is <strong>not</strong> stored since we presume that the caller will fetch
+     *       the value for its own processing.</li>
+     * </ul>
+     *
+     * @param conformalSphere_φ If non-null, the the latitude where to compute the radius of conformal sphere.
+     * @param falseEasting      The descriptor for fetching the <cite>"False easting"</cite> parameter.
+     * @param falseNorthing     The descriptor for fetching the <cite>"False northing"</cite> parameter.
      */
-    protected NormalizedProjection(final OperationMethod method, final Parameters parameters,
+    NormalizedProjection(final OperationMethod method, final Parameters parameters,
+            final ParameterDescriptor<Double> conformalSphere_φ,
             final ParameterDescriptor<Double> falseEasting,
             final ParameterDescriptor<Double> falseNorthing)
     {
         ensureNonNull("parameters", parameters);
         context = new ContextualParameters(method);
-        final double a  = getAndStore(parameters, MapProjection.SEMI_MAJOR);
+              double a  = getAndStore(parameters, MapProjection.SEMI_MAJOR);
         final double b  = getAndStore(parameters, MapProjection.SEMI_MINOR);
         final double fe = getAndStore(parameters, falseEasting);
         final double fn = getAndStore(parameters, falseNorthing);
-        context.scaleAndTranslate2D(false, a, fe, fn);
-        excentricitySquared = 1.0 - (b*b) / (a*a);
+        final double rs = b / a;
+        excentricitySquared = 1 - (rs * rs);
         excentricity = sqrt(excentricitySquared);
+        if (conformalSphere_φ != null && excentricitySquared != 0) {
+            /*
+             * EPSG said: R is the radius of the sphere and will normally be one of the CRS parameters.
+             * If the figure of the earth used is an ellipsoid rather than a sphere then R should be calculated
+             * as the radius of the conformal sphere at the projection origin at latitude φ₀ using the formula
+             * for Rc given in section 1.2, table 3.
+             *
+             * Table 3 gives:
+             * Radius of conformal sphere Rc = a √(1 – ℯ²) / (1 – ℯ²⋅sin²φ)
+             *
+             * Using √(1 – ℯ²) = b/a we rewrite as: Rc = b / (1 – ℯ²⋅sin²φ)
+             */
+            final double sinφ = sin(toRadians(parameters.doubleValue(conformalSphere_φ)));
+            a = b / (1 - excentricitySquared * (sinφ*sinφ));
+        }
+        context.scaleAndTranslate2D(false, a, fe, fn);
         inverse = new Inverse();
     }
 
@@ -242,20 +330,23 @@ public abstract class NormalizedProjecti
     }
 
     /**
-     * Returns a parameter descriptor with the same properties than the given one, except that the parameter is
-     * optional. This is sometime needed when invoking {@link #getAndStore(Parameters, ParameterDescriptor)} for
-     * a parameter value which is mandatory in principle, but may be absent because the parameters for the same
-     * projection may be specified in different ways (for example <cite>"Mercator (variant A)"</cite> versus
-     * <cite>"Mercator (variant B)"</cite>).
-     *
-     * @param  <T> The type of parameter value.
-     * @param  descriptor The mandatory descriptor to make optional.
-     * @return A parameter descriptor with the same properties than the given one, but optional.
-     */
-    static <T> ParameterDescriptor<T> makeOptional(final ParameterDescriptor<T> descriptor) {
-        assert descriptor.getMinimumOccurs() == 1; // This method is useless if minOccurs == 0.
-        return new DefaultParameterDescriptor<T>(IdentifiedObjects.getProperties(descriptor), 0, 1,
-                descriptor.getValueClass(), Parameters.getValueDomain(descriptor), null, descriptor.getDefaultValue());
+     * Returns {@code true} if the projection specified by the given parameters has the given name or identifier.
+     * If non-null, the given identifier is presumed in the EPSG namespace and has precedence over the name.
+     *
+     * @param  parameters The user-specified parameters.
+     * @param  name       The name to compare against the parameter group name.
+     * @param  identifier The identifier to compare against the parameter group name.
+     * @return {@code true} if the given parameter group has a name or EPSG identifier matching the given ones.
+     */
+    static boolean identMatch(final ParameterDescriptorGroup parameters, final String name, final String identifier) {
+        if (identifier != null) {
+            for (final ReferenceIdentifier id : parameters.getIdentifiers()) {
+                if (identifier.equals(id.getCode()) && Constants.EPSG.equals(id.getCodeSpace())) {
+                    return true;
+                }
+            }
+        }
+        return IdentifiedObjects.isHeuristicMatchForName(parameters, name);
     }
 
     /**
@@ -266,27 +357,7 @@ public abstract class NormalizedProjecti
      * <p>This method shall be invoked at construction time only.</p>
      */
     final double getAndStore(final Parameters parameters, final ParameterDescriptor<Double> descriptor) {
-        final double value = parameters.doubleValue(descriptor);    // Apply a unit conversion if needed.
-        Comparable<Double> check = descriptor.getMinimumValue();
-        if (check instanceof Number && !(value >= ((Number) check).doubleValue())) {
-            throw outOfBounds(descriptor, value);
-        }
-        check = descriptor.getMaximumValue();
-        if (check instanceof Number && !(value <= ((Number) check).doubleValue())) {
-            throw outOfBounds(descriptor, value);
-        }
-        check = descriptor.getDefaultValue();
-        if (check == null || !check.equals(value)) {
-            context.parameter(descriptor.getName().getCode()).setValue(value);
-        }
-        return value;
-    }
-
-    /**
-     * Creates the exception for a parameter value out of bounds.
-     */
-    private static IllegalArgumentException outOfBounds(final ParameterDescriptor<Double> descriptor, double value) {
-        return new IllegalArgumentException(Errors.format(Errors.Keys.IllegalParameterValue_2, descriptor.getName(), value));
+        return MapProjection.getAndStore(parameters, context, descriptor);
     }
 
     /**
@@ -303,7 +374,7 @@ public abstract class NormalizedProjecti
      *
      * Subclasses can override this method if they wish to use alternative implementations under some circumstances.
      * For example many subclasses will replace {@code this} by a specialized implementation if they detect that the
-     * ellipsoid is actually {@linkplain #isSpherical() spherical}.
+     * ellipsoid is actually spherical.
      *
      * @param  factory The factory to use for creating the transform.
      * @return The map projection from (λ,φ) to (<var>x</var>,<var>y</var>) coordinates.
@@ -383,28 +454,6 @@ public abstract class NormalizedProjecti
     }
 
     /**
-     * Returns {@code true} if this projection is done on a sphere rather than an ellipsoid.
-     * Projections on spheres have an {@linkplain #excentricity} equals to zero.
-     *
-     * @return {@code true} if this projection is on a sphere.
-     */
-    public final boolean isSpherical() {
-        return excentricity == 0;
-    }
-
-    /**
-     * Ensures that this projection is done on a sphere rather than an ellipsoid.
-     * This method is invoked by constructors of classes implementing only spherical formulas.
-     *
-     * @throws IllegalArgumentException If the projection is not done on a sphere.
-     */
-    final void ensureSpherical() throws IllegalArgumentException {
-        if (!isSpherical()) {
-            throw new IllegalArgumentException(Errors.format(Errors.Keys.EllipticalNotSupported));
-        }
-    }
-
-    /**
      * Converts a single coordinate in {@code srcPts} at the given offset and stores the result
      * in {@code dstPts} at the given offset. In addition, opportunistically computes the
      * transform derivative if requested.

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/AbstractMathTransform.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -947,11 +947,7 @@ public abstract class AbstractMathTransf
      */
     @Override
     protected String formatTo(final Formatter formatter) {
-        final ParameterValueGroup parameters = getParameterValues();
-        if (parameters != null) {
-            WKTUtilities.appendName(parameters.getDescriptor(), formatter, null);
-            WKTUtilities.append(parameters, formatter);
-        }
+        WKTUtilities.appendParamMT(getParameterValues(), formatter);
         return "Param_MT";
     }
 
@@ -1112,8 +1108,7 @@ public abstract class AbstractMathTransf
         protected String formatTo(final Formatter formatter) {
             final ParameterValueGroup parameters = getParameterValues();
             if (parameters != null) {
-                WKTUtilities.appendName(parameters.getDescriptor(), formatter, null);
-                WKTUtilities.append(parameters, formatter);
+                WKTUtilities.appendParamMT(parameters, formatter);
                 return "Param_MT";
             } else {
                 formatter.append((FormattableObject) AbstractMathTransform.this);

Modified: sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/java/org/apache/sis/referencing/operation/transform/ContextualParameters.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -580,8 +580,7 @@ public class ContextualParameters extend
      */
     @Override
     protected String formatTo(final Formatter formatter) {
-        WKTUtilities.appendName(descriptor, formatter, null);
-        WKTUtilities.append(this, formatter);
+        WKTUtilities.appendParamMT(this, formatter);
         return "Param_MT";
     }
 

Modified: sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/main/resources/META-INF/services/org.opengis.referencing.operation.OperationMethod [UTF-8] Thu Apr  9 10:52:53 2015
@@ -2,7 +2,10 @@
 # Heavier classes (e.g. having more dependencies) or classes less likely to be used, should be last.
 org.apache.sis.internal.referencing.provider.Affine
 org.apache.sis.internal.referencing.provider.LongitudeRotation
+org.apache.sis.internal.referencing.provider.Equirectangular
 org.apache.sis.internal.referencing.provider.Mercator1SP
 org.apache.sis.internal.referencing.provider.Mercator2SP
+org.apache.sis.internal.referencing.provider.MercatorSpherical
 org.apache.sis.internal.referencing.provider.PseudoMercator
+org.apache.sis.internal.referencing.provider.RegionalMercator
 org.apache.sis.internal.referencing.provider.MillerCylindrical

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/jaxb/referencing/CodeTest.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -19,6 +19,7 @@ package org.apache.sis.internal.jaxb.ref
 import java.util.Collections;
 import org.opengis.referencing.crs.GeographicCRS;
 import org.opengis.referencing.ReferenceIdentifier;
+import org.apache.sis.internal.util.Constants;
 import org.apache.sis.metadata.iso.ImmutableIdentifier;
 import org.apache.sis.metadata.iso.citation.Citations;
 import org.apache.sis.metadata.iso.citation.HardCodedCitations;
@@ -43,7 +44,7 @@ public final strictfp class CodeTest ext
      */
     @Test
     public void testSimple() {
-        final ReferenceIdentifier id = new ImmutableIdentifier(HardCodedCitations.OGP, "EPSG", "4326");
+        final ReferenceIdentifier id = new ImmutableIdentifier(HardCodedCitations.IOGP, "EPSG", "4326");
         final Code value = new Code(id);
         assertEquals("codeSpace", "EPSG", value.codeSpace);
         assertEquals("code",      "4326", value.code);
@@ -64,7 +65,7 @@ public final strictfp class CodeTest ext
     @Test
     @DependsOnMethod("testSimple")
     public void testWithVersion() {
-        final ReferenceIdentifier id = new ImmutableIdentifier(HardCodedCitations.OGP, "EPSG", "4326", "8.2", null);
+        final ReferenceIdentifier id = new ImmutableIdentifier(HardCodedCitations.IOGP, "EPSG", "4326", "8.2", null);
         final Code value = new Code(id);
         assertEquals("codeSpace", "EPSG:8.2", value.codeSpace);
         assertEquals("code",      "4326",     value.code);
@@ -85,10 +86,10 @@ public final strictfp class CodeTest ext
     @Test
     @DependsOnMethod("testWithVersion")
     public void testForIdentifiedObject() {
-        final ReferenceIdentifier id = new ImmutableIdentifier(HardCodedCitations.OGP, "EPSG", "4326", "8.2", null);
+        final ReferenceIdentifier id = new ImmutableIdentifier(HardCodedCitations.IOGP, "EPSG", "4326", "8.2", null);
         final Code value = Code.forIdentifiedObject(GeographicCRS.class, Collections.singleton(id));
         assertNotNull(value);
-        assertEquals("codeSpace", "OGP", value.codeSpace);
+        assertEquals("codeSpace", Constants.IOGP, value.codeSpace);
         assertEquals("code", "urn:ogc:def:crs:EPSG:8.2:4326", value.code);
     }
 

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AffineTest.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -83,7 +83,7 @@ public final strictfp class AffineTest e
         final Matrix matrix = Matrices.createDiagonal(3, 3);
         assertWktEquals(
                 "ParameterGroup[“Affine parametric transformation”," +
-                " Id[“EPSG”, 9624, Citation[“OGP”]]]", Affine.parameters(matrix));
+                " Id[“EPSG”, 9624, Citation[“IOGP”]]]", Affine.parameters(matrix));
         /*
          * Try arbitrary values.
          */
@@ -95,7 +95,7 @@ public final strictfp class AffineTest e
                 "  Parameter[“A1”, 2.0, Id[“EPSG”, 8624]],\n"  +
                 "  Parameter[“B1”, 0.0, Id[“EPSG”, 8640]],\n" +
                 "  Parameter[“B2”, -1.0, Id[“EPSG”, 8641]],\n" +
-                "  Id[“EPSG”, 9624, Citation[“OGP”]]]", Affine.parameters(matrix));
+                "  Id[“EPSG”, 9624, Citation[“IOGP”]]]", Affine.parameters(matrix));
         /*
          * Setting a value on the last row make the matrix non-affine.
          * So it should not be anymore EPSG:9624.

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AllProvidersTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AllProvidersTest.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AllProvidersTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/AllProvidersTest.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -19,7 +19,8 @@ package org.apache.sis.internal.referenc
 import java.util.Map;
 import java.util.HashMap;
 import java.util.IdentityHashMap;
-import java.util.ServiceLoader;
+import org.opengis.util.GenericName;
+import org.opengis.metadata.Identifier;
 import org.opengis.parameter.GeneralParameterDescriptor;
 import org.opengis.parameter.ParameterDescriptorGroup;
 import org.opengis.referencing.operation.OperationMethod;
@@ -41,37 +42,79 @@ import static org.junit.Assert.*;
 @DependsOn({
     org.apache.sis.referencing.operation.DefaultOperationMethodTest.class,
     AffineTest.class,
+    LongitudeRotationTest.class,
     MapProjectionTest.class
 })
 public final strictfp class AllProvidersTest extends TestCase {
     /**
-     * Returns all registered operation methods.
+     * Returns all providers to test.
      */
-    private static Iterable<OperationMethod> methods() {
-        return ServiceLoader.load(OperationMethod.class, AbstractProvider.class.getClassLoader());
+    private static Class<?>[] methods() {
+        return new Class<?>[] {
+            Affine.class,
+            LongitudeRotation.class,
+            Equirectangular.class,
+            Mercator1SP.class,
+            Mercator2SP.class,
+            MercatorSpherical.class,
+            PseudoMercator.class,
+            RegionalMercator.class,
+            MillerCylindrical.class
+        };
     }
 
     /**
      * Ensures that every parameter instance is unique. Actually this test is not strong requirement.
      * This is only for sharing existing resources by avoiding unnecessary objects duplication.
+     *
+     * @throws Exception if the instantiation of a service provider failed.
      */
     @Test
-    public void ensureParameterUniqueness() {
+    public void ensureParameterUniqueness() throws Exception {   // ReflectiveOperationException on JDK7 branch.
         final Map<GeneralParameterDescriptor, String> groupNames =
                 new IdentityHashMap<GeneralParameterDescriptor, String>();
-        final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> existings =
+        final Map<GeneralParameterDescriptor, GeneralParameterDescriptor> parameters =
                 new HashMap<GeneralParameterDescriptor, GeneralParameterDescriptor>();
-        for (final OperationMethod method : methods()) {
+        final Map<Object, Object> namesAndIdentifiers = new HashMap<Object, Object>();
+        for (final Class<?> c : methods()) {
+            final OperationMethod method = (OperationMethod) c.newInstance();
             final ParameterDescriptorGroup group = method.getParameters();
-            final String name = group.getName().getCode();
+            final String operationName = group.getName().getCode();
             for (final GeneralParameterDescriptor param : group.descriptors()) {
-                assertFalse("Parameter declared twice in the same group.", name.equals(groupNames.put(param, name)));
-                final GeneralParameterDescriptor existing = existings.put(param, param);
+                assertFalse("Parameter declared twice in the same group.",
+                        operationName.equals(groupNames.put(param, operationName)));
+                /*
+                 * Ensure uniqueness of the parameter descriptor as a whole.
+                 */
+                final Identifier name = param.getName();
+                Object existing = parameters.put(param, param);
                 if (existing != null && existing != param) {
-                    fail("Parameter “" + param.getName().getCode() + "” defined in “" + name + '”'
+                    fail("Parameter “" + name.getCode() + "” defined in “" + operationName + '”'
                             + " was already defined in “" + groupNames.get(existing) + "”."
                             + " The same instance could be shared.");
                 }
+                /*
+                 * Ensure uniqueness of each name and identifier.
+                 */
+                existing = namesAndIdentifiers.put(name, name);
+                if (existing != null && existing != name) {
+                    fail("The name of parameter “" + name.getCode() + "” defined in “" + operationName + '”'
+                            + " was already defined elsewhere. The same instance could be shared.");
+                }
+                for (final GenericName alias : param.getAlias()) {
+                    existing = namesAndIdentifiers.put(alias, alias);
+                    if (existing != null && existing != alias) {
+                        fail("Alias “" + alias + "” of parameter “" + name.getCode() + "” defined in “" + operationName + '”'
+                                + " was already defined elsewhere. The same instance could be shared.");
+                    }
+                }
+                for (final Identifier id : param.getIdentifiers()) {
+                    existing = namesAndIdentifiers.put(id, id);
+                    if (existing != null && existing != id) {
+                        fail("Identifier “" + id + "” of parameter “" + name.getCode() + "” defined in “" + operationName + '”'
+                                + " was already defined elsewhere. The same instance could be shared.");
+                    }
+                }
             }
         }
     }

Modified: sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/LongitudeRotationTest.java
URL: http://svn.apache.org/viewvc/sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/LongitudeRotationTest.java?rev=1672288&r1=1672287&r2=1672288&view=diff
==============================================================================
--- sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/LongitudeRotationTest.java [UTF-8] (original)
+++ sis/trunk/core/sis-referencing/src/test/java/org/apache/sis/internal/referencing/provider/LongitudeRotationTest.java [UTF-8] Thu Apr  9 10:52:53 2015
@@ -71,9 +71,7 @@ public final strictfp class LongitudeRot
         final ParameterValueGroup p = provider.getParameters().createValue();
         p.parameter(LongitudeRotation.NAME).setValue(2.5969213, NonSI.GRADE);
         assertWktEquals(
-                "Param_MT[“Affine”,\n" +
-                "  Parameter[“num_row”, 3],\n" +
-                "  Parameter[“num_col”, 3],\n" +
-                "  Parameter[“elt_0_2”, 2.33722917]]", provider.createMathTransform(null, p));
+                "Param_MT[“Affine parametric transformation”,\n" +
+                "  Parameter[“A2”, 2.33722917, Id[“EPSG”, 8625]]]", provider.createMathTransform(null, p));
     }
 }



Mime
View raw message